1. 程式人生 > >用PHP實現n的階乘--高精度演算法

用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秒!!!!