搜尋
首頁後端開發PHP問題php怎麼實現n的階乘

php怎麼實現n的階乘

Jun 03, 2021 am 09:16 AM
php

php實現n的階乘的方法:1、透過普通遞歸實現,程式碼如「function fact(int $n): int{...}」;2、透過普通循環實現,程式碼如「 while ($num

php怎麼實現n的階乘

本文操作環境:Windows10系統、PHP 7.2.15版,DELL G3電腦

php怎麼實現n的階乘?

據本人了解,階乘的實現方法一般可以分為三種,通常意義下的遞歸和循環各算一種,還有一大類透過一些巧妙的數學方法減少運算次數(尤其是乘法運算次數),進而優化計算效率。

如果要考慮到高精度、大整數的階乘,對於PHP 語言而言,情況會更複雜一些,例如使用BCMath 擴展提供的一些方法時,顯式的數字與字串轉換操作比較頻繁。

本文在只考慮 n 為整數的情況下,分別嘗試實現上述的幾種情況,每種情況給出可用的程式碼範例,並在文末附上幾種方法的綜合對比情況。

普通遞歸實現

首先是普通遞歸實現,根據遞歸的通用公式fact(n) = n * fact(n-1) 很容易寫出階乘的計算代碼。普通遞歸實現的優點在於程式碼比較簡潔,和通用公式一樣的過程使得程式碼容易理解。缺點則在於由於需要頻繁地呼叫自身,需要大量的入棧出棧操作,整體的計算效率不高(見文末表格)。

function fact(int $n): int
{
    if ($n == 0) {
        return 1;
    }
    return $n * fact($n - 1);
}

普通循環實作

普通迴圈實作有些「動態規劃」的味道,但由於中間態變數使用頻率低,不需要額外儲存空間,所以要比一般的動態規劃演算法簡單。普通遞歸法是自頂向下(由 n 到 1)的計算過程,而普通循環則是自底向上進行計算。

因此相對而言,程式碼沒有上述方法直觀,但由於少了頻繁的入棧出棧過程,計算效率會高一些(請參閱文末表格)。

function fact(int $n): int
{
    $result = 1;
    $num = 1;
    while ($num <= $n) {
        $result = $result * $num;
        $num = $num + 1;
    }
    return $result;
}

自行實現的大整數階乘

由於 PHP 中 int 型別的範圍限制,上述兩種方法最多只能精確計算到 20 的階乘。如果只是考慮到 20 的階乘的情況,那麼用查表法實現會更快:事先計算好 0-20 的階乘並存儲到一個數組中,需要用時查詢一次便可。

為了能夠適應大數的階乘,得到精確的計算結果,本文基於「普通循環方法」進行改進,使用數組儲存計算結果中的每一位(由低到高位),透過相乘進位的方式依序計算每一位的結果。

不言而喻,本方法的優點在於可以適用於高精度的大數階乘場合,缺點就是對於小數階乘而言,計算過程複雜且速度慢。

function fact(int $n): array
{
    $result = [1];
    $num = 1;
    while ($num <= $n) {
        $carry = 0;
        for ($index = 0; $index < count($result); $index++) {
            $tmp = $result[$index] * $num + $carry;
            $result[$index] = $tmp % 10;
            $carry = floor($tmp / 10);
        }
        while ($carry > 0) {
            $result[] = $carry % 10;
            $carry = floor($carry / 10);
        }
        $num = $num + 1;
    }
    return $result;
}

BCMath 擴展方法

BCMath 是 PHP 的一個數學擴展,用於處理字串表示的數字(任意大小和精度)的數值計算。由於是使用 C 語言實現的擴展,計算速度會比上述自行實現的快。

推薦學習:《PHP影片教學

在本人的筆記本上,同樣是計算2000 的階乘,自行實現的需要平均0.5-0.6 秒,使用BCMath 耗時0.18-0.19 秒。此方法的缺點主要在於需要安裝相應的擴展,屬於非程式碼層面的改動,對於環境管理升級不便的應用而言,可實踐性有待商榷。

function fact(int $n): string
{
    $result = &#39;1&#39;;
    $num = &#39;1&#39;;
    while ($num <= $n) {
        $result = bcmul($result, $num);
        $num = bcadd($num, &#39;1&#39;);
    }
    return $result;
}

最佳化演算法

在本文開頭有提到,最佳化演算法盡量減少運算次數(尤其是乘法的運算次數)來實現快速階乘。考慮到對於小整數階乘而言,最快的演算法應該是查表法,時間複雜度為 O(1),所以本小節主要針對大整數的精確階乘進行討論和測試。

據了解,目前階乘最佳化比較常見的是透過n! = C(n, n/2) * (n/2)! * (n/2)! 式子進行複雜度最佳化,而此式子中的亮點主要在於C(n, n/2) 的最佳化。考慮到大整數情況下,PHP 語言實現C(n, n/2) 的效率不高,而且實現的程式碼可讀性比較差(頻繁的數字與字串的明確轉換),所以本文用的是另外一種比較巧妙的方法。

乘法的計算速度通常要低於加減法運算,透過減少乘法的運算次數可以提高整體運算速度。透過數學歸納可以發現,對於 n 的階乘,可以依序求出比 (n/2)^2 小 1、1 3、1 3 5... 的數值,再依序相乘得到目標值。

此演算法的優點在於計算速度較快,而缺點就是實作過程不直觀、不易理解。經測試,以下程式碼計算 2000 的階乘平均時間為 0.11 秒,大約是普通循環方法的一半耗時。

除了這種方法優化,也有看到其它的類似的思路,比如對1...n 中的數反複檢驗是否被2 整除,記錄下被2 整除的次數x,並嘗試歸納出共同的奇數相乘式,最後乘以2^x 得到結果。

function fact(int $n): string
{
    $middleSquare = pow(floor($n / 2), 2);
    $result = $n & 1 == 1 ? 2 * $middleSquare * $n : 2 * $middleSquare;
    $result = (string)$result;
    for ($num = 1; $num < $n - 2; $num = $num + 2) {
        $middleSquare = $middleSquare - $num;
        $result = bcmul($result, (string)$middleSquare);
    }
    return $result;
}

综合对比

本文中提到的方法是按照由劣到优的顺序,因此,下列表格中每一行中提到优劣势,主要是和其上一两种方法对比。

表格中「测试耗时」一列的测试环境为个人笔记本,硬件配置为 Dell/i5-8250U/16GB RAM/256GB SSD Disk,软件配置为 Win 10/PHP 7.2.15。

php怎麼實現n的階乘

总结

虽然本文将实现方法分为三大类,但其实也可以分为循环和递归两大类,在这两类中分别使用相应的算法优化计算效率。But,总体而言,循环的效率要优于递归。

讲道理,本文中使用的优化算法并不是最优解,只是用 PHP 相对好实现,代码易读性也比较高。有兴趣的读者可以谷歌了解更多的骚操作。

以上是php怎麼實現n的階乘的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
酸與基本數據庫:差異和何時使用。酸與基本數據庫:差異和何時使用。Mar 26, 2025 pm 04:19 PM

本文比較了酸和基本數據庫模型,詳細介紹了它們的特徵和適當的用例。酸優先確定數據完整性和一致性,適合財務和電子商務應用程序,而基礎則側重於可用性和

PHP安全文件上傳:防止與文件相關的漏洞。PHP安全文件上傳:防止與文件相關的漏洞。Mar 26, 2025 pm 04:18 PM

本文討論了確保PHP文件上傳的確保,以防止諸如代碼注入之類的漏洞。它專注於文件類型驗證,安全存儲和錯誤處理以增強應用程序安全性。

PHP輸入驗證:最佳實踐。PHP輸入驗證:最佳實踐。Mar 26, 2025 pm 04:17 PM

文章討論了PHP輸入驗證以增強安全性的最佳實踐,重點是使用內置功能,白名單方法和服務器端驗證等技術。

PHP API率限制:實施策略。PHP API率限制:實施策略。Mar 26, 2025 pm 04:16 PM

本文討論了在PHP中實施API速率限制的策略,包括諸如令牌桶和漏水桶等算法,以及使用Symfony/Rate-limimiter之類的庫。它還涵蓋監視,動態調整速率限制和手

php密碼哈希:password_hash和password_verify。php密碼哈希:password_hash和password_verify。Mar 26, 2025 pm 04:15 PM

本文討論了使用password_hash和pyspasswify在PHP中使用密碼的好處。主要論點是,這些功能通過自動鹽,強大的哈希算法和SECH來增強密碼保護

OWASP前10 php:描述並減輕常見漏洞。OWASP前10 php:描述並減輕常見漏洞。Mar 26, 2025 pm 04:13 PM

本文討論了OWASP在PHP和緩解策略中的十大漏洞。關鍵問題包括注射,驗證損壞和XSS,並提供用於監視和保護PHP應用程序的推薦工具。

PHP XSS預防:如何預防XSS。PHP XSS預防:如何預防XSS。Mar 26, 2025 pm 04:12 PM

本文討論了防止PHP中XSS攻擊的策略,專注於輸入消毒,輸出編碼以及使用安全增強的庫和框架。

PHP接口與抽像類:何時使用。PHP接口與抽像類:何時使用。Mar 26, 2025 pm 04:11 PM

本文討論了PHP中接口和抽像類的使用,重點是何時使用。界面定義了無實施的合同,適用於無關類和多重繼承。摘要類提供常見功能

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

EditPlus 中文破解版

EditPlus 中文破解版

體積小,語法高亮,不支援程式碼提示功能

MantisBT

MantisBT

Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

將Eclipse與SAP NetWeaver應用伺服器整合。

mPDF

mPDF

mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。