首頁 後端開發 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

熱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

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

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

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

適用於 Ubuntu 和 Debian 的 PHP 8.4 安裝和升級指南 適用於 Ubuntu 和 Debian 的 PHP 8.4 安裝和升級指南 Dec 24, 2024 pm 04:42 PM

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

我後悔之前不知道的 7 個 PHP 函數 我後悔之前不知道的 7 個 PHP 函數 Nov 13, 2024 am 09:42 AM

如果您是經驗豐富的PHP 開發人員,您可能會感覺您已經在那裡並且已經完成了。操作

如何設定 Visual Studio Code (VS Code) 進行 PHP 開發 如何設定 Visual Studio Code (VS Code) 進行 PHP 開發 Dec 20, 2024 am 11:31 AM

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

在PHP API中說明JSON Web令牌(JWT)及其用例。 在PHP API中說明JSON Web令牌(JWT)及其用例。 Apr 05, 2025 am 12:04 AM

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

php程序在字符串中計數元音 php程序在字符串中計數元音 Feb 07, 2025 pm 12:12 PM

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

您如何在PHP中解析和處理HTML/XML? 您如何在PHP中解析和處理HTML/XML? Feb 07, 2025 am 11:57 AM

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

解釋PHP中的晚期靜態綁定(靜態::)。 解釋PHP中的晚期靜態綁定(靜態::)。 Apr 03, 2025 am 12:04 AM

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

什麼是PHP魔術方法(__ -construct,__destruct,__call,__get,__ set等)並提供用例? 什麼是PHP魔術方法(__ -construct,__destruct,__call,__get,__ set等)並提供用例? Apr 03, 2025 am 12:03 AM

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

See all articles