php如何实现无符号右移
@幕后导演,我最初给的那个右移函数(网上找的)在32位里应该也是对的。然后我的sint32
操作在32位里应该也没有副作用(32位php中的所有整数都是32位有符号整数,所以该函数相当于空操作)。所以用这两个函数应该可以写出32位64位结果一致的代码。
// 32位无符号右移
function shr32($x, $bits) {
$c = 0x7fffffff >> ($bits - 1);
return $c & ($x >> $bits);
}
// 转为32位有符号整数
function sint32($int) {
return unpack('l', pack("L", $int))[1];
}
这样之所以可以,是因为负数右移时不是在前面补0,而是在前面补1,所以只要把多余的1去掉,结果就是正确的了。
// 32位无符号右移
function shr32($x, $bits) {
$c = 0x7fffffff >> ($bits - 1);
return $c & ($x >> $bits);
}
以下是64位结果,32位也一样,只是前面少了32个1。
php > var_dump(decbin(-2147483647));
string(64) "1111111111111111111111111111111110000000000000000000000000000001"
php > var_dump(decbin(-2147483647 >> 3));
string(64) "1111111111111111111111111111111111110000000000000000000000000000"
// 无符号右移>>>
function uright($a, $n) {
// console.log($a);
if ($n != 0) {
$c = 2147483647 >> ($n - 1);
return $c &($a >> $n);
} else {
if (is_string($a)) {
if (PHP_INT_MAX > 2147483647) {
$a = intval($a);
} else {
$a = floatval($a);
}
}
if (!is_int($a)) {
$a = intval($a);
}
if ((0 > $a) || ($a > 4294967295)) {
$a &= 4294967295;
if (0 > $a) {
$a = sprintf('%u', $a);
}
}
return $a;
}
}
@幕后导演,嗯,上述代码仅限64位php使用,所以我的sint32原本是这样的:
不过后来我发现它在32位里没有副作用,只是个空操作,所以把抛出异常删了。
但是这个无符号右移函数在32位里确实不能达到预期目的,因为负数在32位里
& 0xffffffff
后依然是负数,并不会消除它的符号位。