PHP中未签名的右移/Zerofill Right Shift/>(Java/JavaScript等效)
在将此标记为副本之前,请阅读下面的内容,并检查my code*my updated code
所以我的问题是,我必须实现Java/JavaScript'>>>;'(无符号右移/零填充右移),但我不能让它以完全相同的方式工作
我选择了在SO和web上发现的11个最有前途的实现(链接作为注释添加到代码中),并添加了一些测试用例。不幸的是,没有一个函数对所有测试返回与Java/JS相同的响应(可能其中一些只在32位系统上工作)
Live Code+JS+PHP结果演示(点击运行):
http://phpfiddle.org/main/code/bcv7-bs2q*
http://phpfiddle.org/main/code/dpkw-rxfe
最接近的功能是:
// http://stackoverflow.com/a/27263298
function shr9($a,$b) {
if($a>=0) return $a>>$b;
if($b==0) return (($a>>1)&0x7fffffff)*2+(($a>>$b)&1);
return ((~$a)>>$b)^(0x7fffffff>>($b-1));
}
及
// http://stackoverflow.com/a/25467712
function shr11($a, $b) {
if ($b > 32 || $b < -32) {
$m = (int)($b/32);
$b = $b-($m*32);
}
if ($b < 0)
$b = 32 + $b;
if ($a < 0)
{
$a = ($a >> 1);
$a &= 2147483647;
$a |= 0x40000000;
$a = ($a >> ($b - 1));
} else {
$a = ($a >> $b);
}
return $a;
}
不幸的是,shr9在(-10>;>;>;-3)和*(32>;>;32)上失败,但它是唯一要通过的(-3>;>;>;0);shr11在(-3>;>;0)和(32>;>;32)上失败
测试用例:
0 >>> 3 == 0
3 >>> 0 == 3
0 >>> -3 == 0
-3 >>> 0 == 4294967293 (in JS); -3 (in Java)
10 >>> 3 == 1
10 >>> -3 == 0
-10 >>> 3 == 536870910
-10 >>> -3 == 7
-672461345 >>> 25 == 107
32 >>> 32 == 32
128 >>> 128 == 128
编辑:我发现只有在JavaScript中-3 >>> 0
才等于4294967293
(为什么?),但在Java中,它等于^{
*大更新:
从PHP 7开始,按负数移位被认为是无效的,并导致:“致命错误:未捕获算术错误:按负数移位位”。根据这一点,我认为我们不必通过这些测试,所以我更新了问题和代码
# 1 楼答案
因为我真的没有主意了,我克隆了Chromium V8引擎和Mozilla Central repo来获取SpiderMonkey。我开始搜索JS>>>;运算符,最后在Mozilla的代码中,我发现了一个有将近20年历史的文件(从1997年开始),其中包含用于测试“按位零填充右移操作”的无运算符代码。在用PHP重写后,这段代码通过了所有测试
[LiveDemo]
用法示例:
UnsignedRightShift(10, 3);
(=10>;>;3)免责声明:我知道这甚至不是一个“专业”的解决方案,性能很差(4.33s,110000个循环;有问题的函数完成~0.04s,110000个循环),也许这段代码中甚至有不必要的函数,但目前我只有时间逐行实现它。如果有人有更好的解决方案、更好的性能或更干净的代码,我非常乐意看到
# 2 楼答案
在研究了问题中的两个函数(“shr9”和“shr11”)并合并/调整了好的部分后,我终于找到了解决方案。所有测试都通过了(我甚至在演示中添加了更多测试),而且它也适用于负数的移位
[Live Demo]
这段代码不仅准确,而且速度也很快
基准测试结果:100000次循环:0.25秒
基准测试:http://phpfiddle.org/main/code/mj68-1s7e