【问题标题】:Output is NaN , how?输出是 NaN ,怎么样?
【发布时间】:2020-06-04 05:00:31
【问题描述】:

我正在尝试编写泰勒级数,但如果 n(=100) 的值很大,我会得到“nan”作为输出。 我哪里做错了?

#include<iostream>
#include<cmath>
using namespace std;

 int main(){

    int n;
    double x;

    cin >> n;
    cin >> x;

    long double temp_val = 1;
    int sign = 1;
    int power = 1;
    long long int factorial = 1;


    for(int i = 1 ; i < n ; i++){

        sign = sign* -1 ;
        power =  2*i;
        factorial  = factorial*(2*i)*(2*i-1);

        temp_val += sign*pow(x,power)/factorial;
    }
    cout<<temp_val;

}

【问题讨论】:

  • power 看起来会很快溢出。
  • @FrançoisAndrieux 有什么想法,如何解决?
  • 查看进入给出 NaN 的函数调用的实际值。如果您将表达式拆分为多个单独的行,这样您就可以看到中间步骤,这会有所帮助。
  • 如果double 没有所需的范围,请查看boost.org/doc/libs/1_71_0/libs/multiprecision/doc/html/…
  • 请不要修复您在问题中询问的问题。对于未来的读者来说,它使问题和答案变得毫无意义。我已恢复您的编辑。

标签: c++ nan taylor-series


【解决方案1】:

对于大型n,您的程序具有未定义的行为。

您正在计算factorial2n 的阶乘(所以为200)。 200! 是,according to Wolfram Alpha

788657867364790503552363213932185062295135977687173263294742533244359449963403342920304284011984623904177212138919638830257642790242637105061926624952829931113462857270763317237396988943922445621451664240254033291864131227428294853277524242407573903240321257405579568660226031904170324062351700858796178922222789623703897374720000000000000000000000000000000000000000000000000 P>

为了比较,long long int 可以容纳的典型最大值是

9223372036854775807

(假设它是 64 位)

显然,您无法将200! 放入其中。当您溢出有符号整数变量时,您的程序将具有undefined behavior。这意味着无法保证它的行为方式。

但是即使将变量类型更改为无符号,也不会有太大变化。该程序将不再有未定义的行为,但factorial 实际上不会保存正确的值。相反,它会不断回绕到零。

即使您将factorial 更改为double 类型,这对于典型的double 实现来说可能还不足以保持该值。您的平台可能有一个大于doublelong double 类型,并且能够保存此值。

如果x1 不接近,您将遇到与pow(x, power) 类似的问题。

正如@idclev463035818 的回答中提到的那样,泰勒级数,如果直接评估,在数值上表现得很糟糕,实际上不能以这种形式实际用于大型n

【讨论】:

  • 很好,我的回答中缺少对 OPs 代码中的问题的解释,现在他们都得到了
  • 谢谢,它确实有效。在这种情况下,powerfactorial 都溢出了。
【解决方案2】:

计算泰勒级数有一个陷阱,在其他情况下也会出现:要加项的分子和分母都增长得相当快并且容易溢出,但它们的商收敛到零(否则将它们相加直到无穷大不会收敛为有限数)。

您需要更新结果和总增量,而不是单独跟踪这两个术语。我不会为您提供完整的解决方案。在伪代码中

double res = 0;
double delta = x;
int n = 1;
double sign = -1;
while ( ! stop_condition ) {
    delta *= (x / n);
    res += sign*delta;
    ++n;
    sign *= -1;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-11-03
    • 2018-11-06
    • 1970-01-01
    • 1970-01-01
    • 2013-11-30
    • 1970-01-01
    • 2021-02-26
    • 2022-08-11
    相关资源
    最近更新 更多