PHP的二进制位移操作

PHP主要是设计于文本操作的,其实PHP不适合做数学运算,效率也不高,不过因为这次的项目中有个东西必须使用到二进制位移操作,在PHP上面遇到了一些麻烦。

因为PHP只有32位有符号整数,没有64位长整型,也没有无符号整数。其整型的范围是-231-1~231,超出这个范围的,将被解释为浮点数。因此,0xFFFFFFFF,直接打印,显示的是4294967295,及232

>> 0xFFFFFFFFF
4294967295
>>  gettype(0xFFFFFFFF)
'double'

而在32位有符号整型中,0xFFFFFFFF应表示-1:

 >> (int)0xFFFFFFFFF
-1

而PHP不支持浮点数的二进制位移操作,如果要进行,会先转换为整型,最后的结果,也将按照整型来返回:

>> 1 << 31
-2147483648
>> 1 << 30
1073741824
>> 1 << 32
1
>> 0xFFFFFFFF >> 1
-1

同时PHP的向右位移操作,高位会填充符号位,而且PHP没有提供类似Java的>>>来强制填充0:

>> 1 << 32
1
>> 0xFFFFFFFF >> 1
-1
>> 0xFFFFFFFF >> 2
-1
>> 0xFFFFFFFF >> 3
-1
>> 0xFFFFFFFF >> 31
-1

如何解决这个问题呢,我考虑过使用BCMath数学函数库,直接处理字符串表示的整数,或者是GMP/BigInt扩展等。不过我想既然使用字符串,那么我可以字符串地彻底一些,把数字转换成32个二进制的字符串,再手工填充0,最后转换回来。

不知道哪位有更好的方法,请告诉我。

代码如下:
(另外,其实代码可以扩展为任意位2进制的位移操作,这里我没有做)

 
  1. <?php   
  2. /**  
  3.  * 无符号32位右移  
  4.  * @param mixed $x 要进行操作的数字,如果是字符串,必须是十进制形式  
  5.  * @param string $bits 右移位数  
  6.  * @return mixed 结果,如果超出整型范围将返回浮点数  
  7.  */  
  8. function shr32($x$bits){   
  9.     // 位移量超出范围的两种情况   
  10.     if($bits <= 0){   
  11.         return $x;   
  12.     }   
  13.     if($bits >= 32){   
  14.         return 0;   
  15.     }   
  16.     //转换成代表二进制数字的字符串   
  17.     $bin = decbin($x);   
  18.     $l = strlen($bin);   
  19.     //字符串长度超出则截取底32位,长度不够,则填充高位为0到32位   
  20.     if($l > 32){   
  21.         $bin = substr($bin$l - 32, 32);   
  22.     }elseif($l < 32){   
  23.         $bin = str_pad($bin, 32, '0', STR_PAD_LEFT);   
  24.     }   
  25.     //取出要移动的位数,并在左边填充0   
  26.     return bindec(str_pad(substr($bin, 0, 32 - $bits), 32, '0', STR_PAD_LEFT));   
  27. }   
  28. /**  
  29.  * 无符号32位左移  
  30.  * @param mixed $x 要进行操作的数字,如果是字符串,必须是十进制形式  
  31.  * @param string $bits 左移位数  
  32.  * @return mixed 结果,如果超出整型范围将返回浮点数  
  33.  */  
  34. function shl32 ($x$bits){   
  35.     // 位移量超出范围的两种情况   
  36.     if($bits <= 0){   
  37.         return $x;   
  38.     }   
  39.     if($bits >= 32){   
  40.         return 0;   
  41.     }   
  42.     //转换成代表二进制数字的字符串   
  43.     $bin = decbin($x);   
  44.     $l = strlen($bin);   
  45.     //字符串长度超出则截取底32位,长度不够,则填充高位为0到32位   
  46.     if($l > 32){   
  47.         $bin = substr($bin$l - 32, 32);   
  48.     }elseif($l < 32){   
  49.         $bin = str_pad($bin, 32, '0', STR_PAD_LEFT);   
  50.     }   
  51.     //取出要移动的位数,并在右边填充0   
  52.     return bindec(str_pad(substr($bin$bits), 32, '0', STR_PAD_RIGHT));   
  53. }   
  54. ?>   

你可能感兴趣的:(PHP的二进制位移操作)