用PHP实现n的阶乘--高精度算法

时间:2022-10-26 03:36:38

今天在IT届,最火的新闻莫过于李世石输给了alphago。看到新闻说,“围棋有361个落子点,所以下棋有10^171种可能。”然后我就突然想361的阶乘是多少呢?即

361*360*359*358*......*5*4*3*2*1 = ?

于是自己用php实现了一下算法。代码如下:

<?php $result = "1"; for($i = 1; $i <= 361; $i++){ $val = strval($i); $result = bigNumMulty($result, $val); } echo $result."\n"; //两个大数相乘,$num1和$num2都是string型的 function bigNumMulty($num1, $num2){ $len1 = strlen($num1); $len2 = strlen($num2); $zeroNum1 = 0; $result = '0'; for($i = $len1 - 1; $i >= 0; $i--){ $zeroNum2 = 0; for($j = $len2 - 1; $j >= 0; $j--){ $data = stringMulty($num1[$i], $num2[$j]); $data .= addZero($zeroNum1 + $zeroNum2); $result = bigNumAdd($result, $data); $zeroNum2++; } $zeroNum1++; } return $result; } //两个大数相加,$num1和$num2都是string型的 function bigNumAdd($num1, $num2){ $len1 = strlen($num1); $len2 = strlen($num2); $result = ''; if($len1 > $len2){ $big = $num1; $small = $num2; $blen = $len1; $slen = $len2; }else{ $blen = $len2; $slen = $len1; $big = $num2; $small = $num1; } $ten = 0; for($i = 0; $i < $slen; $i++){ $data = stringAdd($big[$blen - $i - 1], $small[$slen - $i - 1], $ten); $ten = intval($data / 10); $single = intval($data % 10); $result = strval($single) . $result; } for(; $i < $blen; $i++){ $data = stringAdd($big[$blen - $i - 1], '0', $ten); $ten = intval($data / 10); $single = intval($data % 10); $result = strval($single) . $result; } if($ten) $result = '1'.$result; return $result; } //string型数据相加 function stringAdd($num1, $num2, $ten){ $int1 = intval($num1); $int2 = intval($num2); $int3 = intval($ten); $result = $int1 + $int2 + $int3; return $result; } //string型数据相乘 function stringMulty($num1, $num2){ $int1 = intval($num1); $int2 = intval($num2); $result = $int1 * $int2; return strval($result); } //为string型数据后面加0 function addZero($num){ $result = ''; while($num){ $result .= '0'; $num--; } return $result; }

不过这个算法计算的时间相当久。。。35分钟。。。
最终结果如下:
1437923258884890654832362511499863354754907538644755876127282765299227795534389618856841908003141196071413794434890585968383968233304321607713808837056557879669192486182709780035899021100579450107333050792627771722750412268086775281368850575265418120435021506234663026434426736326270927646433025577722695595343233942204301825548143785112222186834487969871267194205609533306413935710635197200721473378733826980308535104317420365367377988721756551345004129106165050615449626558110282424142840662705458556231015637528928999248573883166476871652120015362189137337137682618614562954409007743375894907714439917299937133680728459000034496420337066440853337001284286412654394495050773954560000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

哈哈,35分钟,不是一个程序可以接受的。然后优化了一下:

<?php $result = array(1); for($i = 1; $i <= 361; $i++){ $result = bigNumMulty($result, $i); } echoArr($result); //两个大数相乘,$num1和$num2都是string型的 function bigNumMulty($arr, $num){ $result = array(0); foreach($arr as $key=>$val){ $data = $val * $num; addData($result, $data, $key); } return $result; } function addData(&$arr, $num, $index){ while($num){ $single = $num % 10; $data = $arr[$index] + $single; $arr[$index] = $data % 10; $arr[$index + 1] += intval($data / 10); $num = intval($num / 10); $index++; } } function echoArr($arr){ $index = 0; foreach($arr as $key=>$val){ if($val > 0){ $index = $key; } } for(; $index > -1; $index--){ if(empty($arr[$index])){ echo 0; }else{ echo $arr[$index]; } } }

运行一下,3秒!!!!