Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ exp(-x)和exp(+;x)之间的泰勒级数差_C++_Iteration_Rounding_Series_Function Approximation - Fatal编程技术网

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

C++ exp(-x)和exp(+;x)之间的泰勒级数差,c++,iteration,rounding,series,function-approximation,C++,Iteration,Rounding,Series,Function Approximation,我正试图编写一个程序来计算exp(-x)和exp(x)的泰勒级数,对于大x,最多迭代200次。(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; //mul

我正试图编写一个程序来计算exp(-x)和exp(x)的泰勒级数,对于大x,最多迭代200次。(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.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时,泰勒定理只给出了一个非常糟糕的界

从概念上讲,当
x
变为负无穷大时,
e^{-x}
趋于零。但你的近似函数是一个固定次数的多项式,任何非常数多项式都趋向于渐近正无穷大或负无穷大。因此,如果考虑“代码> x的全部可能值范围,则相对误差必须是无限的。


总之,我认为你应该重新考虑你的方法。你可以考虑的是,只使用泰勒级数法来求< <代码> x >代码>满足<代码> -0.fp的泰勒多项式可能不是一个好主意。有关使用切比雪夫多项式进行函数逼近的文章,请参阅

rickandross指出了这种情况下的错误来源,即exp(-100)的泰勒展开式包含了大值的差异

对Taylor尝试进行了一个简单的修改,可以为我尝试的几个测试用例获得合理的答案,即使用exp(-x)=1/exp(x)这一事实。本方案:

#include <iostream>
#include <cmath>

double texp(double x)
{
  double last=1.0;
  double sum=1.0;
  if(x<0)
    return 1/texp(-x);

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

  return sum;
}

void test_texp(double x)
{
  double te=texp(x);
  double e=std::exp(x);
  double err=te-e;
  double rerr=(te-e)/e;
  std::cout << "x=" << x 
            << "\ttexp(x)=" << te 
            << "\texp(x)=" << e 
            << "\terr=" << err
            << "\trerr=" << rerr
            << "\n";
}

int main()
{
  test_texp(0);
  test_texp(1);
  test_texp(-1);
  test_texp(100);
  test_texp(-100);
}

这取决于你在“它对正计算很有效”中所说的“好”是什么意思。就绝对值而言,正指数的结果实际上比负指数的结果离真实答案更远|2.68811691354e+43-2.68811714182e+43 |=2.2828e+36表示e^100与|-8.42078025179e+24-3.72007597602e-44 |=8.42078e+24表示e^-100Ah是的,对不起,我指的是罚款,相对误差为正指数~0.00000001,负指数~10^68:(这是为了兴趣吗?或者你有一个应用程序,你可以使用双精度数字,但是不能使用标准库ExpEd)?@ RryYyKek这仅仅是为了兴趣,我对C++是相当新的,我正在尝试获得精确和舍入错误的处理。哇,非常感谢!这非常有帮助,我非常感谢这个非常周到/有洞察力的答案。我非常喜欢这种混合方法。这是一个很好的答案,除了第一段。一些求和的绝对值(远!)大于1,误差是由舍入误差造成的(如rickandross所述)@RoryWorker:谢谢你的评论,我已经编辑了我的答案。我对这里的浮点错误的严重程度做了一些调查,现在附在答案上。有一些严重的浮点错误正在发生,但我认为公平地说,它不是这里的主要错误源。
#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
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);
}
#include <iostream>
#include <cmath>

double texp(double x)
{
  double last=1.0;
  double sum=1.0;
  if(x<0)
    return 1/texp(-x);

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

  return sum;
}

void test_texp(double x)
{
  double te=texp(x);
  double e=std::exp(x);
  double err=te-e;
  double rerr=(te-e)/e;
  std::cout << "x=" << x 
            << "\ttexp(x)=" << te 
            << "\texp(x)=" << e 
            << "\terr=" << err
            << "\trerr=" << rerr
            << "\n";
}

int main()
{
  test_texp(0);
  test_texp(1);
  test_texp(-1);
  test_texp(100);
  test_texp(-100);
}
x=0 texp(x)=1   exp(x)=1    err=0   rerr=0
x=1 texp(x)=2.71828 exp(x)=2.71828  err=4.44089e-16 rerr=1.63371e-16
x=-1    texp(x)=0.367879    exp(x)=0.367879 err=-5.55112e-17    rerr=-1.50895e-16
x=100   texp(x)=2.68812e+43 exp(x)=2.68812e+43  err=1.48553e+28 rerr=5.52628e-16
x=-100  texp(x)=3.72008e-44 exp(x)=3.72008e-44  err=-2.48921e-59    rerr=-6.69128e-16