编写一个算法来计算欧拉数,直到

问题描述

我的算法课程教授给了我以下作业:

编写一个 C/C++ 程序,以 eps > 0 的给定精度计算欧拉数 (e) 的值。

提示:数字 e = 1 + 1/1! +1/2! + ... + 1 / n! + ... = 2.7172 ... 可以计算为 序列 x_0,x_1,x_2,... 的元素之和,其中 x_0 = 1,x_1 = 1+ 1/1 !,x_2 = 1 + 1/1! +1/2 !,...,只要条件|x_(i+1) - x_i|,求和就会继续>= eps 有效。

正如他进一步解释的那样,eps 是算法的精度。例如,精度可能是 1/100 |x_(i + 1) - x_i| = ( x_(i+1) - x_i ) 的绝对值

目前,我的程序如下所示:

#include<iostream>
#include<cstdlib>
#include<math.h>
#include<vector>

// Euler's number

using namespace std;

double factorial(double n)
{
    double result = 1;
    for(double i = 1; i <= n; i++)
    {
        result = result*i;

    }
    return result;
}

int main()
{
    long double euler = 2;
    long double counter = 2;
    float epsilon = 2;
    do
    {
        euler+= pow(factorial(counter),-1);
        counter++;
    }
    while( (euler+1) - euler >= epsilon);
    cout << euler << endl;
    return 0;
}

问题出现在我实现停止条件|x_(i+1) - x_i|时> = eps(while 所在的行((euler+1) - euler >= epsilon);) 输出是 2.5 而不是 2.71828

解决方法

|x_(i+1) - x_i| > = eps 表示“x (x_(i+1)) 的下一个值与{{的当前值之间的距离1}} (x) 大于或等于 epsilon"。

您的代码正在向 x_i 添加 one 并检查一个非常不同的条件:

x

这意味着:“迭代直到(euler+1) - euler >= epsilon 不是euler + 1的下一个值!)减去当前值是......”,这与原始状态。此外,euler,因此您正在检查 (euler+1) - euler == 1 是否小于常数 1。

,

OP 在他们尝试的两个实现中都遗漏了一些东西。

  • 只要条件 |xi+1 - xi| >= eps 有效。

    现在,如果我们考虑发布的系列,那区别是什么?

    x0 = 1,x1 = 1 + 1 / 1!,x2 = 1 + 1/1! +1/2!,...
    |x1 - x0| = 1 / 1!,|x2 - x1| = 1 / 2!,...,|xi - xi - 1| = 1 / i!

    使条件变为1/i! >= 每股收益

  • 函数 factorial 在每次迭代中多次调用,而我们可以通过几次操作轻松计算欧拉数的新近似值

    term /= ++i
    欧拉 += 项

当一个浮点数通过operator<<输出时,用默认的位数表示。要查看更多内容,我们可以使用输入/输出操纵器,如 std::setprecision。这不会影响该数字的内部表示,也不会影响涉及它的任何计算的实际精度,它只是一个格式说明符。

double 这样的浮点类型的精度(和范围)是有限的,而阶乘增长得非常快。在某些时候,1/i!将非常小以至于 euler += 1/i! 在数值上等于 euler 的先前值。见例如以下结果,使用 double 变量

获得
 1   2
 2   2.5
 3   2.666666666666666518636930049979127943515777587890625
 4   2.70833333333333303727386009995825588703155517578125
 5   2.716666666666666341001246109954081475734710693359375
 6   2.718055555555555447000415369984693825244903564453125
 7   2.71825396825396836675281520001590251922607421875
 8   2.718278769841270037233016410027630627155303955078125
 9   2.71828152557319224769116772222332656383514404296875
10   2.718281801146384513145903838449157774448394775390625
11   2.71828182619849290091451621265150606632232666015625
12   2.71828182828616871091753637301735579967498779296875
13   2.718281828446759362805096316151320934295654296875
14   2.71828182845823018709552343352697789669036865234375
15   2.718281828458994908714885241352021694183349609375
16   2.7182818284590428703495490481145679950714111328125
17   2.71828182845904553488480814849026501178741455078125
18   2.71828182845904553488480814849026501178741455078125
19   2.71828182845904553488480814849026501178741455078125
20   2.71828182845904553488480814849026501178741455078125

     2.718281828459045090795598298427648842334747314453125    <--- std::numbers::e

请注意,计算出的值与 std::numbers::e 之间的差值大约为 +4.4e-16(实际上是 next 可表示的 double 值)。

完整的代码(包括所有需要的初始化)留给读者去写。