【问题标题】:Different answers when calculating factorial using iteration and recursion使用迭代和递归计算阶乘时的不同答案
【发布时间】:2013-03-30 04:29:44
【问题描述】:

第一次发帖,希望这个问题可以接受。

作为一个小测试,我编写了一个应用程序,它使用迭代和递归来计算一个数字的阶乘。这似乎工作正常,除非尝试计算大于 24 的数字的阶乘。

例如,在计算 24 的阶乘时,两种方法都给出正确答案 62044840173323941。

但是,在计算 25 的阶乘时,答案会有所不同。递归方法给出的答案是 1.5511210043330986e+025,而迭代方法给出的答案是 1.5511210043330984e+025。

根据 Wolfram Alpha 的说法,正确答案应该与迭代方法相同,那么为什么函数之间会出现差异?我问了我的同事,他们也无法解释这种行为。

#define TEST_CASE 25

double GetFactorialRecursive(double i)
{   
    if (i == 1)
    return i;
    else
    return i * GetFactorialRecursive(i - 1);
}

double GetFactorialIterative(double i)
{
    double result = 1.0;
    for (; i > 0; --i)
        result *= i;
    return result;
}

int main ()
{
    double recres = 0, itrres = 0; 
    recres = GetFactorialRecursive(TEST_CASE);
    itrres = GetFactorialIterative(TEST_CASE);

    if (recres != itrres)
        std::cout << "Error" << "\n";
    std::cout << std::setprecision(25) << "Recursion: " << recres << ", Iteration: " << itrres << "\n";
    return 0;
}

感谢您的考虑。

【问题讨论】:

  • 我自己试过了。同样的结果,还值得注意的是这两个数字仅相差一位:Recursion: 15511210043330986055303168 [4529a940c33f6121]Iteration: 15511210043330983907819520 [4529a940c33f6120]

标签: c++ recursion iteration factorial


【解决方案1】:

递归版本计算 5 * (4 * (3 * (2 * 1)))

迭代版本计算1 * (2 * (3 * (4 * 5)))

运算顺序的不同会改变浮点算术四舍五入的方式,从而产生不同的结果。

【讨论】:

  • 在这种情况下浮点数舍入的原因是因为double类型最多只能容纳大约15-17个有效数字,而n!往往多于15-17即使是相对较小的 n 值,它们中的数字也是如此。另一方面,Wolfram|Alpha 在处理这些数量时使用了与 double 完全不同的方法。
【解决方案2】:

double 的类型是 not an exact type。它有望成为正确值的近似值。

所以不能保证这两种实现都是准确的。

就您的实施而言,有两个因素可能导致不同的答案。

  1. 您对乘法的排序不同。
  2. 您的迭代版本在同一个变量中执行所有数学运算。与 Intel 兼容的架构(x86 和 x86-64)在其浮点寄存器中使用 80 位精度,并且该精度一直保持到寄存器存储在内存中。

【讨论】:

  • +1 用于指出寄存器问题,这是一个 PITA,优化(将变量保留在寄存器中而不是将其放回内存中)实际上可以改变程序的可观察行为:(跨度>
【解决方案3】:

乘法的顺序不同,由于浮点舍入而给出不同的结果。

如果您将for 循环从1 更改为i(而不是从i 更改为1),您应该得到与递归版本相同的结果。

【讨论】:

  • 正如 Drew Dormann 指出的那样,实际上你可能不会,除非寄存器 内存转换在代码生成后也完全相同,因为寄存器往往(在 x86 架构上)具有更好的精度......
猜你喜欢
  • 2015-04-19
  • 2020-07-05
  • 1970-01-01
  • 2017-04-19
  • 2020-08-17
  • 1970-01-01
  • 1970-01-01
  • 2015-01-08
  • 2012-06-25
相关资源
最近更新 更多