Unsigned right shift function not working for negative input

白昼怎懂夜的黑 提交于 2019-12-20 04:20:49

问题


I'm looking for a way to use the >>> function from JavaScript in the 64-bit version of PHP 5.5.14. I found this function in my googling:

function uRShift($a, $b) 
{ 
    $z = hexdec(80000000); 
    if ($z & $a) 
    { 
        $a = ($a >> 1); 
        $a &= (~$z); 
        $a |= 0x40000000; 
        $a = ($a >> ($b - 1)); 
    } else { 
        $a = ($a >> $b); 
    } 
    return $a; 
}

This function seems to work fine for positive numbers, but I get differing results when passing in negative numbers.

For example:

PHP:

In: echo uRShift(-672461345, 25);
Out: -149

JavaScript (Chrome 35):

In: -672461345 >>> 25
Out: 107

EDIT:

I also tried the other function mentioned in the answer linked above.

function uRShift($a, $b)
{
    if($b == 0) return $a;
    return ($a >> $b) & ~(1<<(8*PHP_INT_SIZE-1)>>($b-1));
}

PHP:

In: echo uRShift(-672461345, 25);
Out: 549755813867

Runnable


回答1:


The constant 0x80000000 (it's written as a call to hexdec and stored in the $z variable in this example) represents the lowest signed two's complement negative integer (100000.... in binary). The expression ~$z should give the bitwise NOT of this, namely, the highest signed positive integer (which ends up being 2147483647).

The original number (positive 0x80000000, that is, 2147483648) cannot be stored as a signed 32-bit integer, so normally it would be stored as a float of some kind. Unfortunately, PHP 5.5 thinks that ~(2147483648) is equal to -2147483649, which would be correct if we were dealing with e.g. 64-bit integers.

And indeed, echoing out PHP_INT_SIZE in runnable indicates that integers are 8 bytes, which is 64 bits. Thus, the arithmetic isn't working out right in PHP 5.5.

To remedy this, just replace the ~$z with a static constant, as follows:

function uRShift($a, $b) 
{ 
    if ($a < 0) 
    { 
        $a = ($a >> 1); 
        $a &= 2147483647; 
        $a |= 0x40000000; 
        $a = ($a >> ($b - 1)); 
    } else { 
        $a = ($a >> $b); 
    } 
    return $a; 
}

This function still has some weaknesses; for example, shifting by 0 doesn't work properly.



来源:https://stackoverflow.com/questions/24659911/unsigned-right-shift-function-not-working-for-negative-input

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!