无符号右移/零填充右移/>>>在PHP(Java / JavaScript等价物) [英] Unsigned Right Shift / Zero-fill Right Shift / >>> in PHP (Java/JavaScript equivalent)
问题描述
在将此标记为重复之前,请阅读以下内容,并检查 我的代码 * 我的更新代码!
Before flagging this as a duplicate, please read below, and check my code * my updated code!
所以我的问题是,我必须实现Java / JavaScript'>>>'(无符号右移/零填充右移),但我不能让它完全相同方式。
So my problem is that, I have to implement Java/JavaScript '>>>' (Unsigned Right Shift / Zero-fill Right Shift), but I can't get it work exactly the same way.
我选择了我在SO和网络上发现的11个最有希望的实现(链接在代码中添加为注释)并添加了一些测试用例。不幸的是, NONE 函数返回了与所有测试相同的Java / JS响应。 (也许其中一些只在32位系统上工作)
I've selected the 11 most promising implementations I've found on SO and on the web (links are added as comments in the code) and added a few test cases. Unfortunately NONE of the functions returned the same response as Java/JS to ALL of the tests. (Maybe some of them are only working on 32bit systems)
实时代码+ JS + PHP结果演示(点击运行):
http://phpfiddle.org/main/code/bcv7-bs2q *
http:// phpfiddle。 org / main / code / dpkw-rxfe
Live Code + JS+PHP results demo (click Run):
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)。
Unfortunately shr9 fails on (-10 >>> -3) and * (32 >> 32), but is the only to pass (-3 >>> 0); and shr11 fails on (-3 >>> 0) and also (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
等于 4294967293
仅在JavaScript (为什么?),但在Java中,它等于 -3
。不幸的是,这并没有改变我仍然无法通过所有测试的任何功能的事实。
I found that -3 >>> 0
is equals 4294967293
only in JavaScript (why?), but in Java, it equals -3
. Unfortunately, this doesn't change the fact that I still can't get any function to pass all tests.
* BIG UPDATE:
从PHP 7开始,按负数位移位被视为无效并导致:致命错误:未捕获的算术错误:按负数移位。根据这一点,我认为我们不必通过这些测试,所以我已经更新了问题和代码。
Since PHP 7, bit shift by a negative number is considered to be invalid and causes: "Fatal error: Uncaught ArithmeticError: Bit shift by negative number". According to this, I think we don't have to pass those tests, so I've updated the question and the codes.
推荐答案
在查看问题(shr9和shr11)中的两个函数并合并/调整好的部分之后,我终于找到了解决方案。所有测试都通过了(我甚至在演示中添加了更多),它也适用于负数的移位。
After looking into the two functions from the question ("shr9" and "shr11") and merging/tweaking the good parts, I finally found the solution. All tests passed (I even added more in the demo), and it also works for shifts by a negative number.
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
这篇关于无符号右移/零填充右移/>>>在PHP(Java / JavaScript等价物)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!