exp(-x)和exp(+ x)之间的泰勒级数差

khfrekek

我正在尝试编写一个程序,对于大x,它最多可以计算200次迭代的exp(-x)和exp(x)泰勒级数。(exp(x)= 1 + x + x ^ 2/2 + ...)。

我的程序非常简单,似乎可以正常运行。但是对于exp(-x),它发散了,但是对于exp(+ x)​​,它收敛得很好。到目前为止,这是我的代码:

long double x = 100.0, sum = 1.0, last = 1.0;

for(int i = 1; i < 200; i++) {
        last *= x / i;    //multiply the last term in the series from the previous term by x/n
        sum += last; //add this new last term to the sum
    }
cout << "exp(+x) = " << sum << endl;

x = -100.0; //redo but now letting x<0
sum = 1.0;
last = 1.0;

for(int i = 1; i < 200; i++) {
            last *= x / i;
            sum += last;
        }
    cout << "exp(-x) = " << sum << endl;

当我运行它时,得到以下输出:

exp(+x) = 2.68811691354e+43 
exp(-x) = -8.42078025179e+24

当实际值是:

exp(+x) = 2.68811714182e+43 
exp(-x) = 3.72007597602e-44

如您所见,它对于正向计算有效,但对负向无效。有没有人知道为什么仅在每两个词上加一个负数就可以使舍入误差这么大?另外,有什么我可以实施的解决此问题的方法吗?

提前致谢!!

克里斯·贝克

我认为这实际上与浮点近似误差无关,我认为还有另一个更重要的误差源。

就像您自己说的那样,您的方法非常简单。您正在x=0对该函数进行泰勒级数逼近,然后在处对其进行求值x=-100

您实际上期望这种方法的准确性如何?为什么?

在较高的水平上,您应该只希望您的方法在附近的狭窄区域内是准确的x=0泰勒的逼近定理告诉您,例如,如果您N围绕进行级数运算x=0,则您的逼近度O(|x|)^(N+1)至少将是准确的因此,如果您使用200个字词,则您应该准确到例如10^(-60)范围内的[-0.5, 0.5]但是在x=100泰勒定理中,这仅给您一个非常可怕的界限。

从概念上讲,您知道e^{-x}随着x负无穷大趋向于零但是您的逼近函数是一个固定次数的多项式,任何非常数多项式都趋于渐近于无穷大或负无穷大。因此,如果考虑的可能值的整个范围,则相对误差必须不受限制x

简而言之,我认为您应该重新考虑您的方法。您可能会考虑的一件事是,仅对x满足使用泰勒级数方法-0.5f <= x <= 0.5f对于x大于0.5f,请尝试除以x2并递归调用该函数,然后对结果求平方。或类似的东西。

为了获得最佳结果,您可能应该使用既定方法。

编辑:

我决定编写一些代码来查看我的想法实际如何运作。这似乎与整个范围的C库实现完美匹配x = -10000,以x = 10000至少为精度位数为我展示。:)

还要注意,即使对于x大于100的值,我的方法也是准确的,泰勒级数方法实际上在正端也会失去精度。

#include <cmath>
#include <iostream>

long double taylor_series(long double x)
{
    long double sum = 1.0, last = 1.0;

    for(int i = 1; i < 200; i++) {
            last *= x / i;    //multiply the last term in the series from the previous term by x/n
            sum += last; //add this new last term to the sum
    }

    return sum;
}

long double hybrid(long double x)
{
    long double temp;
    if (-0.5 <= x && x <= 0.5) {
        return taylor_series(x);
    } else {
        temp = hybrid(x / 2);
        return (temp * temp);
    }
}

long double true_value(long double x) {
    return expl(x);
}

void output_samples(long double x) {
    std::cout << "x = " << x << std::endl;
    std::cout << "\ttaylor series = " << taylor_series(x) << std::endl;
    std::cout << "\thybrid method = " << hybrid(x) << std::endl;
    std::cout << "\tlibrary = " << true_value(x) << std::endl;
}

int main() {
    output_samples(-10000);
    output_samples(-1000);
    output_samples(-100);
    output_samples(-10);
    output_samples(-1);
    output_samples(-0.1);
    output_samples(0);
    output_samples(0.1);
    output_samples(1);
    output_samples(10);
    output_samples(100);
    output_samples(1000);
    output_samples(10000);
}

输出:

$ ./main 
x = -10000
    taylor series = -2.48647e+423
    hybrid method = 1.13548e-4343
    library = 1.13548e-4343
x = -1000
    taylor series = -2.11476e+224
    hybrid method = 5.07596e-435
    library = 5.07596e-435
x = -100
    taylor series = -8.49406e+24
    hybrid method = 3.72008e-44
    library = 3.72008e-44
x = -10
    taylor series = 4.53999e-05
    hybrid method = 4.53999e-05
    library = 4.53999e-05
x = -1
    taylor series = 0.367879
    hybrid method = 0.367879
    library = 0.367879
x = -0.1
    taylor series = 0.904837
    hybrid method = 0.904837
    library = 0.904837
x = 0
    taylor series = 1
    hybrid method = 1
    library = 1
x = 0.1
    taylor series = 1.10517
    hybrid method = 1.10517
    library = 1.10517
x = 1
    taylor series = 2.71828
    hybrid method = 2.71828
    library = 2.71828
x = 10
    taylor series = 22026.5
    hybrid method = 22026.5
    library = 22026.5
x = 100
    taylor series = 2.68812e+43
    hybrid method = 2.68812e+43
    library = 2.68812e+43
x = 1000
    taylor series = 3.16501e+224
    hybrid method = 1.97007e+434
    library = 1.97007e+434
x = 10000
    taylor series = 2.58744e+423
    hybrid method = 8.80682e+4342
    library = 8.80682e+4342

编辑:

对于谁感兴趣:

注释中提出了一些有关原始程序中浮点错误有多重要的问题。我最初的假设是它们可以忽略不计-我进行了测试以查看是否正确。事实证明这是不正确的,并且存在很大的浮点错误,但是即使没有浮点错误,仅taylor系列也会引入很大的错误。泰勒级数在200项时的真实价值x=-100似乎接近-10^{24},而不是10^{-44}我使用进行了检查boost::multiprecision::cpp_rational,这是建立在其任意精度整数类型上的任意精度有理类型。

输出:

x = -100
    taylor series (double) = -8.49406e+24
                (rational) = -18893676108550916857809762858135399218622904499152741157985438973568808515840901824148153378967545615159911801257288730703818783811465589393308637433853828075746484162303774416145637877964256819225743503057927703756503421797985867950089388433370741907279634245166982027749118060939789786116368342096247737/2232616279628214542925453719111453368125414939204152540389632950466163724817295723266374721466940218188641069650613086131881282494641669993119717482562506576264729344137595063634080983904636687834775755173984034571100264999493261311453647876869630211032375288916556801211263293563
                           = -8.46257e+24
    library                = 3.72008e-44
x = 100
    taylor series (double) = 2.68812e+43
                (rational) = 36451035284924577938246208798747009164319474757880246359883694555113407009453436064573518999387789077985197279221655719227002367495061633272603038249747260895707250896595889294145309676586627989388740458641362406969609459453916777341749316070359589697827702813520519796940239276744754778199440304584107317957027129587503199/1356006206645357299077422810994072904566969809700681604285727988319939931024001696953196916719184549697395496290863162742676361760549235149195411231740418104602504325580502523311497039304043141691060121240640609954226541318710631103275528465092597490136227936213123455950399178299
                           = 2.68812e+43
    library                = 2.68812e+43

代码:

#include <cmath>
#include <iostream>
#include <boost/multiprecision/cpp_int.hpp>

typedef unsigned int uint;
typedef boost::multiprecision::cpp_rational rational;

// Taylor series of exp

template <typename T>
T taylor_series(const T x) {
    T sum = 1, last = 1;

    for (uint i = 1; i < 200; i++) {
        last = last * (x / i);
        sum = sum + last;
    }
    return sum;
}

void sample(const int x) {
    std::cout << "x = " << x << std::endl;
    long double e1 = taylor_series(static_cast<long double>(x));
    std::cout << "\ttaylor series (double) = " << e1 << std::endl;
    rational e2 = taylor_series(static_cast<rational>(x));
    std::cout << "\t            (rational) = " << e2 << std::endl;
    std::cout << "\t                       = " << static_cast<long double>(e2) << std::endl;
    std::cout << "\tlibrary                = " << expl(static_cast<long double>(x)) << std::endl;
}

int main() {
    sample(-100);
    sample(100);
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

ldexp(1,x)和exp2(x)之间的差异

来自分类Dev

sympy如何将ln((exp(x)+1)/ exp(x))简化为log(1 + exp(-x))?

来自分类Dev

Haskell中的exp x并键入签名

来自分类常见问题

如何计算exp(a * x ** 2 + b * x + c)的积分?

来自分类Dev

如何计算exp(a * x ** 2 + b * x + c)的积分?

来自分类Dev

SED和Reg Exp

来自分类Dev

reg exp: "if" 和单个 "="

来自分类Dev

RuntimeWarning:在np.exp(x ** 2)中遇到溢出

来自分类Dev

MATLAB中cos(x)的泰勒级数

来自分类Dev

该语句以八度为单位做什么?X = [ones(20,1)(exp(1)+ exp(2)*(0.1:0.1:2))'];

来自分类Dev

计算1 /(1 + exp(x))python时避免数值不稳定性

来自分类Dev

泰勒级数-计算sin(x)直到6位精度

来自分类Dev

带有Tensorflow的cos(x)+1的泰勒级数

来自分类Dev

C ++-使用泰勒级数逼近估算cos(x)

来自分类Dev

使用泰勒级数在C中找到sin(x)

来自分类Dev

如何使用sympy为x的正弦生成泰勒级数

来自分类Dev

exp(-x ^ 2/2)从x =-无穷大到x = +无穷大的蒙特卡洛积分

来自分类Dev

exp2应该比exp快吗?

来自分类Dev

LOG和EXP函数中的舍入问题

来自分类Dev

无法正确设置JWT的Exp和Iat

来自分类Dev

正确显示exp栏

来自分类Dev

找不到.exp

来自分类Dev

NF_NETLINK_CONNTRACK_EXP_DESTROY和NF_NETLINK_CONNTRACK_DESTROY之间的区别是什么?

来自分类Dev

我的泰勒级数图的代码在Matlab中用cos(2x)代替cos(x)

来自分类Dev

bigInt的Math.exp()吗?

来自分类Dev

在Go中安装exp / html

来自分类Dev

使用reg exp查找单词

来自分类Dev

(caadr exp)在赋值变量中

来自分类Dev

Pow()vs.exp()性能