用PHP實現n的階乘--高精度演算法
今天在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秒!!!!