C# 中的 For 循环与 Python 中的 For 循环

See*_*ker 14 c# python for-loop computation

我正在编写一个计算 e^x 值的方法。我在 python 中实现的方法如下。

import math

def exp(x):
    return sum([
        x**n/math.factorial(n)
        for n in range(0, 100)
    ])
Run Code Online (Sandbox Code Playgroud)

这将很好地返回 e^x 的值。但是当我尝试在 c# 中实现相同的方法时,它没有输出与 python 中相同的值。下面是c#中的实现。

static double exp(int x)
{
    double FinalAnswer = 0;
    for (int j = 0; j <= 100; j++)
    {
        FinalAnswer += (Math.Pow(x, j))/Factorial(j);
    }
    return FinalAnswer;
}
Run Code Online (Sandbox Code Playgroud)

该代码的输出最初是一个无穷大符号。为了解决这个问题,我只是减少了循环运行的次数。C# 中循环仅运行 10 次的代码的输出与 Python 中循环运行 100 次的输出非常接近。我的问题是不同编程语言的两个循环之间发生了什么。起初我认为我在计算 e^x 的方法中使用的表达式收敛得很快。但是运行 10 次的循环如何产生与运行 100 次循环的输出相匹配的输出。

另外,当我将 c# 中的 for 循环增加到 20 和 30 时,x > 3 的 e^x 值相差很大。有人可以解释一下这是怎么回事吗?

Moo*_*ist 20

您可能在这里遇到的是C# 版本的 Factorial 函数的整数溢出(至少是您的实现,或者无论它来自哪里)。

在 C# 中,anint是存储在 32 位内存中的数字类型,这意味着它的范围约为-2^31 <= n <= 2^31 - 1+/- 21 亿。您可以尝试使用long64 位数字类型,但是对于 for 循环中更大的上限(例如接近 100),您也会溢出long

当您在 C# 中运行阶乘函数时,它在开始时会正常启动,但是如果您继续下去,您会发现它突然跳到负数,如果您继续下去,它会变成 0 并且停止变化。您会看到由于除以 0 导致的无穷大输出,并且 C# 有一种用双精度数处理该问题的方法;那就是回来double.PositiveInfinity

在 python 中不会发生这种情况的原因是它使用可变数量的位数来存储其数值。

添加注释:您可能还想尝试使用与double类型一起使用的阶乘函数而不是intor long,但是通过这样做,您将失去确切值的精度,但您会获得更大的范围,因为您可以存储的数量更大

进一步注意:正如评论中提到的,C# 有一个名为 的类型BigInteger,旨在处理巨大的数字,例如您期望从阶乘函数的大量输入中获得的值。您可以在此处找到 BigInteger 文档的参考


您可以做的是使用您使用的幂分别计算阶乘函数的每个分量。这就是我的意思:

public decimal Exp(decimal power, int accuracy = 100)
{
    decimal runningTotal = 1;
    decimal finalValue = 1;
    for (int i = 1; i <= accuracy; i++)
    {
        runningTotal *= power/i;
        finalValue += runningTotal;
    }
    return finalValue;
}
Run Code Online (Sandbox Code Playgroud)

  • @YonatanNir 我对其中的复杂性不是很熟悉,但在较高的层面上,Python 存储数字的方式使用不固定的字节数。如果您尝试表示的数字需要的字节数大于变量当前包含的字节数,则它只会分配更多字节并使用它。您可以在这里找到更好的比较:https://www.pythontutorial.net/advanced-python/python-integers/ (2认同)
  • C# 还有一个“BigInteger”类(在“System.Numerics”中),它可用于存储任意大的数字,但代价是计算速度较慢且代码更加复杂。(您将无法使用“Math.Factorial()”或“Math.Pow()”,但您可以轻松地编写自己的 BigInteger 实现。)BigInteger 有自己的“Pow()”函数它的价值是什么。 (2认同)
  • 作为参考,最后一项 `math.factorial(n)` (`n=99`) 相当于 `942689044888324774562618574305724247380969376407895166349423877729470707002322379888297615920772 9119823605850588608460429412647567360000000000000000000000` - 作为一个无符号整数,这需要 519 位,甚至比 `long` 还要多。 (2认同)