Java 中大数的阶乘

2024 年 9 月 10 日 | 阅读 7 分钟

我们已经讨论过数字的阶乘。然而,我们仍然需要单独讨论大数的阶乘。这是因为一个人不能用计算小数阶乘的方法来计算大数的阶乘。因此,在本节中,我们将讨论如何在 Java 中查找大数的阶乘。让我们通过一个例子来理解。

示例

数字 10 的阶乘是

10! = 10 x 9 x 8 x 7 x 6 x 5 x 4 x 3 x 2 x 1 = 3628800

数字 3628800 可以轻松存储。但是,问题是,如果不是 10,而是要计算 110 的阶乘呢?110 的阶乘是

这里的问题是如何存储数字 110 的阶乘,它包含 179 位数字?

算法

步骤 1:创建一个大小为 maximum 的数组“result[]”,其中 maximum 是输出中存在的最大位数。

步骤 2:将数组“result[]”中存储的值初始化为 1,并将 result[] 数组的大小 resultSize 初始化为 1。

步骤 3:对从 y = 2 到 num 的所有数字执行以下操作。

……i) 将 y 与 result[] 相乘,并更新 result[] 和 resultSize 以保持乘法结果。

上述算法强调了基本学校数学的应用。其思想是通过分别选取两个数字的每一位来相乘,并将进位传递到下一个两位数的乘法中。让我们通过一个例子来理解。

假设我们必须将 9786 乘以 10。那么,我们将执行如下乘法。

将数字 9786 存储在数组中,如下所示

result[] = {6, 8, 7, 9}

y = 10

将进位初始化为 c = 0。

对 j = 0 到 resultSize - 1 执行以下操作

....a) 找到 result[j] * y + v 的值。设该值为 product。

....b) 通过将 product 的最后一位存储在其中来更新 result[j]。

....c) 通过将剩余的位数保留在进位中来更新进位。

j = 0, product = result[0] * y + c = 6 * 10 + 0 = 60。

result[0] = 0, c = 6

j = 1, product = result[1] * y + c = 8 * 10 + 6 = 86

result [1] = 6, c = 8

j = 2, product = result[2] * y + c = 7 * 10 + 8 = 78

result [2] = 8, c = 7

j = 3, product = result[3] * y + c = 9 * 10 + 7 = 97

result [3] = 7, c = 9

现在,将进位的所有位数放入 result[],并将 resultSize 增加进位中的位数。

因此,

result[4] = c = 9

因此,结果数组变为

result[] = {0, 6, 8, 7, 9}

现在,我们所要做的就是按相反的顺序打印结果数组。因此,当我们将 9786 乘以 10 时,得到 97860。

注意:对于数字 9786,我们以相反的顺序将其数字存储在结果数组中。这是因为如果我们以数字中出现的相同顺序存储数字,那么在不使用额外空间的情况下更新 result[] 将变得困难。

实施

让我们看看上述算法的实现。

使用数组

文件名:LargeNumFact.java

输出

The factorial of the number 110 is: 
15882455415227429404253703127090772871724410234473563207581748318444567162948183030959960131517678520479243672638179990208521148623422266876757623911219200000000000000000000000000

使用 LinkedList

除了数组之外,还可以使用链表来计算大数的阶乘。使用链表的优点是链表不会占用任何额外空间。这是因为与数组不同,我们可以根据需要分配和取消分配内存。

文件名:LargeNumFact1.java

输出

The factorial of the number 110 is:  
15882455415227429404253703127090772871724410234473563207581748318444567162948183030959960131517678520479243672638179990208521148623422266876757623911219200000000000000000000000000

注意:除了在 display() 方法中使用尾部递归外,还可以使用循环遍历链表的节点,然后显示其数据。但是,在此之前,必须将其节点存储在堆栈中。这是因为数字阶乘的位数是以相反的顺序存储在链表中的。更新 display() 方法的以下代码,并且将得到相同的输出。

使用 BigInteger

还可以使用 BigInteger 类来计算大数的阶乘。在此方法中,我们将使用 BigInteger 类提供的 multiply() 方法。观察以下代码。

文件名:LargeNumFact2.java

输出

The factorial of the number 110 is:  
15882455415227429404253703127090772871724410234473563207581748318444567162948183030959960131517678520479243672638179990208521148623422266876757623911219200000000000000000000000000