PHP中的无符号右移/零填充右移/ >>>(Java / JavaScript等效)

在将此标记为重复之前,请阅读以下内容,并检查我的代码 * 我的更新代码 !

所以我的问题是,我必须实现Java / JavaScript’>>>’(无符号右移/零填充右移),但我无法以完全相同的方式工作。

我已经选择了我在SO和Web上找到的11个最有前途的实现(链接在代码中添加为注释)并添加了一些测试用例。 不幸的是,没有任何函数返回与Java / JS相同的响应到所有测试。 (也许其中一些只在32位系统上工作)

实时代码+ JS + PHP结果演示(点击运行):
http://phpfiddle.org/main/code/bcv7-bs2q *
http://phpfiddle.org/main/code/dpkw-rxfe

最接近的function是:

// 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 > 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 

编辑:我发现-3 >>> 0仅在JavaScript中等于4294967293 (为什么?) ,但在Java中,它等于-3 。 不幸的是,这并没有改变我仍然无法通过所有测试的任何function的事实。


*大更新:

从PHP 7开始,位移负数被认为是无效的并且导致:“ 致命错误:未捕获的算术错误:按负数移位 ”。 据此,我认为我们不必通过这些测试,所以我已经更新了问题和代码。

在查看问题(“shr9”和“shr11”)中的两个函数并合并/调整好的部分之后,我终于找到了解决方案。 所有测试都通过了(我甚至在演示中添加了更多),它也适用于负数的移位。

[现场演示]

 function unsignedRightShift($a, $b) { if ($b >= 32 || $b < -32) { $m = (int)($b/32); $b = $b-($m*32); } if ($b < 0) { $b = 32 + $b; } if ($b == 0) { return (($a>>1)&0x7fffffff)*2+(($a>>$b)&1); } if ($a < 0) { $a = ($a >> 1); $a &= 0x7fffffff; $a |= 0x40000000; $a = ($a >> ($b - 1)); } else { $a = ($a >> $b); } return $a; } 

这段代码不仅准确,而且速度快。
基准测试结果:100000次循环:0.25秒
基准测试: http : //phpfiddle.org/main/code/mj68-1s7e

由于我真的没有想法,我克隆了Chromium V8引擎和Mozilla Central回购以获得SpiderMonkey。 我开始搜索JS >>>运算符,最后在Mozilla的代码中,我找到了一个近20年的文件(从1997年开始), js / src / tests / ecma / Expressions / 11.7.3.js ,其中包含运算符用于测试“零填充按位右移操作”的无代码。 在PHP中重写后,此代码通过了所有测试。

[LiveDemo]

 = pow(2,31) ) ? $n - pow(2,32) : $n; return ( $n ); } function ToUint32( $n ) { $sign = ( $n < 0 ) ? -1 : 1; if ( abs( $n ) == 0 || abs( $n ) == INF) { return 0; } $n = $sign * floor( abs($n) ); $n = $n % pow(2,32); if ( $n < 0 ){ $n += pow(2,32); } return ( $n ); } function ToUint16( $n ) { $sign = ( $n < 0 ) ? -1 : 1; if ( abs( $n ) == 0 || abs( $n ) == INF) { return 0; } $n = ( $sign * floor( abs($n) ) ) % pow(2,16); if ($n <0) { $n += pow(2,16); } return ( $n ); } function Mask( $b, $n ) { $b = ToUint32BitString( $b ); $b = substr( $b, strlen($b) - $n ); $b = ToUint32Decimal( $b ); return ( $b ); } function ToUint32BitString( $n ) { $b = ""; for ( $p = 31; $p >=0; $p-- ) { if ( $n >= pow(2,$p) ) { $b .= "1"; $n -= pow(2,$p); } else { $b .= "0"; } } return $b; } function ToInt32BitString( $n ) { $b = ""; $sign = ( $n < 0 ) ? -1 : 1; $b .= ( $sign == 1 ) ? "0" : "1"; for ( $p = 30; $p >=0; $p-- ) { if ( ($sign == 1 ) ? $sign * $n >= pow(2, $p) : $sign * $n > pow(2,$p) ) { $b .= ( $sign == 1 ) ? "1" : "0"; $n -= $sign * pow( 2, $p ); } else { $b .= ( $sign == 1 ) ? "0" : "1"; } } return $b; } function ToInt32Decimal( $bin ) { $r = 0; $sign; if ( intval($bin[0]) == 0 ) { $sign = 1; $r = 0; } else { $sign = -1; $r = -(pow(2,31)); } for ( $j = 0; $j < 31; $j++ ) { $r += pow( 2, $j ) * intval($bin[31-$j]); } return $r; } function ToUint32Decimal( $bin ) { $r = 0; for ( $l = strlen($bin); $l < 32; $l++ ) { $bin = "0" . $bin; } for ( $j = 0; $j < 32; $j++ ) { $r += pow( 2, $j ) * intval($bin[31-$j]); } return $r; } function RShift( $s, $a ) { $s = ToUint32BitString( $s ); for ( $z = 0; $z < $a; $z++ ) { $s = "0" . $s; } $s = substr( $s, 0, strlen($s) - $a ); return ToUint32Decimal($s); } function UnsignedRightShift( $s, $a ) { $s = ToUint32( $s ); $a = ToUint32( $a ); $a = Mask( $a, 5 ); return ( RShift( $s, $a ) ); } 

用法示例: UnsignedRightShift(10, 3); (= 10 >>> 3)

免责声明:我知道这甚至不接近“专业”解决方案,性能不好(4.33s,110,000循环;有问题的function完成~0.04s,110,000循环),也许这个片段甚至有不必要的function,但目前我只有时间逐行实施。 如果有人有更好的解决方案,更好的性能或更清晰的代码,我很高兴看到它。