在用 PHP 翻譯別人用 Java 寫的以下一段代碼時,碰到了一些關於 PHP 整數操做的問題。php
Java 代碼:java
public static long hash(String string) { long h = 1125899906842597L; int len = string.length(); for (int i = 0; i < len; i++) { h = 31*h + string.charAt(i); } return h; }
因爲 Long 類型的 h 的初始值就比較大,通過屢次乘以 31 以後會溢出。可是移除後 h 的值也不會爲 0,運算能夠正常繼續。可是在 PHP(5.3.27_1) 中,當整數溢出後,用 intval 取值會獲得 0。而 PHP 中用來作大數運算的 BC_MATH 中的函數雖然能夠進行大數運算,可是沒法在溢出後截斷溢出。這讓人很鬱悶。又不想光爲這個簡單的功能去用 C 寫一個擴展。最後又複習了一邊《深刻理解計算機系統》中第二章關於整數運算的描述,寫了一個整數溢出的函數。函數
function overflow_long($value) { $max_int = bcsub(bcpow(2, 63), 1); $int_span = bcpow(2, 64); $min_int = bcsub(bcadd($max_int, 1), $int_span); $mod_value = bcmod($value, $int_span); if (bccomp($mod_value, $max_int) > 0) { return bcsub($mod_value, $int_span); } elseif (bccomp($mod_value, $min_int) < 0) { return bcadd($mod_value, $int_span); } else { return $mod_value; } }
而後實現上述 Java 代碼的功能。this
private function hash($str) { $char_arr = str_split($str); $len = strlen($str); $h = 1125899906842597; for($i=0; $i<$len; $i++) { echo $h, "<br />"; $h = $this->overflow_long(bcmul(31, $h)) + ord($char_arr[$i]); } return $h; }