为什么会显示nan?

时间:2015-12-26 11:56:50

标签: c++ factorial

好的所以我正在做一个程序,我试图让右侧的结果相当于左侧,精度为0.0001%
sin x = x - (x ^ 3)/ 3! +(x ^ 5)/ 5! +(x ^ 7)/ 7! + ...

#include<iostream>
#include<iomanip>
#include<math.h>

using namespace std;

long int fact(long int n)
{
    if(n == 1 || n == 0)
        return 1;
    else
        return n*fact(n-1);
}

int main()
{
    int n = 1, counts=0; //for sin
    cout << "Enter value for sin" << endl;
    long double x,value,next = 0,accuracy = 0.0001;
    cin >> x;
    value = sin(x);
    do
    {
        if(counts%2 == 0)
            next = next + (pow(x,n)/fact(n));
        else
            next = next - (pow(x,n)/fact(n));
        counts++;
        n = n+2;
    } while((fabs(next - value))> 0);
    cout << "The value of sin " << x << " is " << next << endl;
}


让我说我为x输入45 我得到了结果
sin 45的值为nan。

任何人都可以帮我解决我做错的事吗?

3 个答案:

答案 0 :(得分:2)

首先你的状况应该是 while((fabs(next - value))> accuracy)fact应该返回long double。 当你改变它仍然不会为45的价值工作。原因是这个泰勒级数对于大值收敛得太慢。 这是公式中的错误术语

enter image description here

这里k是迭代次数a=0,函数是sin。为了使条件变为假45^(k+1)/(k+1)!次,绝对值为sin或{ {1}}(取决于第k个导数)(它在0和1之间)应小于cos。 在这个值为50的公式中,数字仍然非常大(我们应该预期误差大约为1.3 * 10 ^ 18,这意味着我们肯定会做超过50次迭代)。 0.000145^50会溢出,然后将它们分开会给你50!。 在您的原始版本infinity/infinity=NAN中,值不适合整数(您的值溢出到fact),然后0上的除法会给出无穷大,在减去另一个无穷大之后你0

答案 1 :(得分:0)

我引用here关于pow

  

返回值

     

如果没有发生错误,则将基数提升到exp的幂(或   iexp)(baseexp),返回。

     

如果发生域错误,请执行   返回实现定义的值(支持的NaN

     

如果由于溢出而发生极点错误或范围错误,则为±HUGE_VAL,         

如果由于发生范围错误   下溢,返回正确的结果(舍入后)。

进一步阅读:

  

错误处理

     

...

     

除了上面指定的地方,如果任何参数是NaN,则返回NaN

所以基本上,因为n正在增加并且你有很多循环pow返回NaN(你使用的编译器显然支持它)。其余的是算术。你用溢出值来计算。

我相信你试图通过使用泰勒系列来近似sin(x)。我不确定这是否可行。

也许你可以在点击NaN后立即尝试停止循环,而不是更新变量next并输出。这是你可以得到的最接近你的算法。

答案 2 :(得分:0)

如果您使用任何合理级别的警告编译了系统,您会立即看到您没有使用变量accuracy。这个以及fact函数返回long int的事实只是问题的一小部分。即使你纠正了这些问题,使用你的算法也不会得到sin(45)的好结果。

问题在于x=45sin(x)的泰勒扩展中的术语开始逐渐减少,直到n=45。这是一个很大的问题,因为45 45 / 45!是一个非常大的数字,2428380447472097974305091567498407675884664058685302734375/1171023117375434566685446533210657783808,或大约2 * 10 18 。你的算法最初会添加和减去只有在20多次加法/减法后开始减少的大数字,最终希望结果介于-1和+1之间。考虑到输入值为45并使用本机浮点类型,这是一个不可实现的希望。

你可以使用一些BigNum类型(互联网充满了它们)和你的算法,但是当你只需要四个位置的准确性时,那就太极端了。或者,您可以利用sin(x)sin(x+2*pi)=sin(x)的周期性。输入值45等于1.017702849742894661522992634 ...(模2 * pi)。您的算法非常适合输入1.017702849742894661522992634。

你可以做得更好,但是以2 * pi为模的输入值是计算正弦和余弦的合理算法的第一步。更好的是,您可以使用sin(x+pi)=-sin(x)的事实。这使您可以将-infinity到+ infinity的范围缩小到0到pi。更好的是,你可以使用0和pi之间的事实,sin(x)关于pi / 2是对称的。你可以做得更好。三角函数的实现极大地利用了这些行为,但它们通常不使用泰勒近似。