php怎麼實現n的階乘
php實現n的階乘的方法:1、透過普通遞歸實現,程式碼如「function fact(int $n): int{...}」;2、透過普通循環實現,程式碼如「 while ($num
本文操作環境: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 = '1'; $num = '1'; while ($num <= $n) { $result = bcmul($result, $num); $num = bcadd($num, '1'); } 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。
总结
虽然本文将实现方法分为三大类,但其实也可以分为循环和递归两大类,在这两类中分别使用相应的算法优化计算效率。But,总体而言,循环的效率要优于递归。
讲道理,本文中使用的优化算法并不是最优解,只是用 PHP 相对好实现,代码易读性也比较高。有兴趣的读者可以谷歌了解更多的骚操作。
以上是php怎麼實現n的階乘的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

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

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

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

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

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

PHP 8.4 帶來了多項新功能、安全性改進和效能改進,同時棄用和刪除了大量功能。 本指南介紹如何在 Ubuntu、Debian 或其衍生版本上安裝 PHP 8.4 或升級到 PHP 8.4

Visual Studio Code,也稱為 VS Code,是一個免費的原始碼編輯器 - 或整合開發環境 (IDE) - 可用於所有主要作業系統。 VS Code 擁有大量針對多種程式語言的擴展,可以輕鬆編寫

JWT是一種基於JSON的開放標準,用於在各方之間安全地傳輸信息,主要用於身份驗證和信息交換。 1.JWT由Header、Payload和Signature三部分組成。 2.JWT的工作原理包括生成JWT、驗證JWT和解析Payload三個步驟。 3.在PHP中使用JWT進行身份驗證時,可以生成和驗證JWT,並在高級用法中包含用戶角色和權限信息。 4.常見錯誤包括簽名驗證失敗、令牌過期和Payload過大,調試技巧包括使用調試工具和日誌記錄。 5.性能優化和最佳實踐包括使用合適的簽名算法、合理設置有效期、

字符串是由字符組成的序列,包括字母、數字和符號。本教程將學習如何使用不同的方法在PHP中計算給定字符串中元音的數量。英語中的元音是a、e、i、o、u,它們可以是大寫或小寫。 什麼是元音? 元音是代表特定語音的字母字符。英語中共有五個元音,包括大寫和小寫: a, e, i, o, u 示例 1 輸入:字符串 = "Tutorialspoint" 輸出:6 解釋 字符串 "Tutorialspoint" 中的元音是 u、o、i、a、o、i。總共有 6 個元

本教程演示瞭如何使用PHP有效地處理XML文檔。 XML(可擴展的標記語言)是一種用於人類可讀性和機器解析的多功能文本標記語言。它通常用於數據存儲

靜態綁定(static::)在PHP中實現晚期靜態綁定(LSB),允許在靜態上下文中引用調用類而非定義類。 1)解析過程在運行時進行,2)在繼承關係中向上查找調用類,3)可能帶來性能開銷。

PHP的魔法方法有哪些? PHP的魔法方法包括:1.\_\_construct,用於初始化對象;2.\_\_destruct,用於清理資源;3.\_\_call,處理不存在的方法調用;4.\_\_get,實現動態屬性訪問;5.\_\_set,實現動態屬性設置。這些方法在特定情況下自動調用,提升代碼的靈活性和效率。
