简体   繁体   中英

Why does it show nan?

Ok so i am doing an a program where I am trying to get the result of the right side to be equivalent to the left side with 0.0001% accuracy
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;
}


and lets say i enter 45 for x I get the result
The value for sin 45 in nan.


can anyone help me out on where I did wrong ?

First your while condition should be while((fabs(next - value))> accuracy) and fact should return long double . When you change that it still won't work for value of 45 . The reason is that this Taylor series converge too slowly for large values. Here is the error term in the formula

在此输入图像描述

Here k is the number of iterations a=0 and the function is sin .In order for the condition to become false 45^(k+1)/(k+1)! times some absolute value of sin or cos (depending what the k-th derivative is) (it's between 0 and 1) should be less than 0.0001 . Well in this formula for value of 50 the number is still very large (we should expect error of around 1.3*10^18 which means we will do more than 50 iterations for sure). 45^50 and 50! will overflow and then dividing them will give you infinity/infinity=NAN . In your original version fact value doesn't fit in the integer (your value overflows to 0 ) and then the division over 0 gives you infinity which after subtract of another infinity gives you NAN .

If the choice of 45 implies you think the input is in degrees, you should rethink that and likely should reduce mod 2 Pi.

First fix two bugs:

    long double fact(long int n)
...
      }while((fabs(next - value))> accuracy);

the return value of fact will overflow quickly if it is long int . The return value of fact will overflow eventually even for long double . When you compare to 0 instead of accuracy the answer is never correct enough, so only nan can stop the while

Because of rounding error, you still never converge (while pow is giving values bigger than fact you are computing differences between big numbers, which accumulates significant rounding error, which is then never removed). So you might instead stop by computing long double m=pow(x,n)/fact(n); before increasing n in each step of the loop and use:

}while(m > accuracy*.5);

At that point, either the answer has the specified accuracy or the remaining error is dominated by rounding error and iterating further won't help.

I quote from here in regard to pow :

Return value

If no errors occur, base raised to the power of exp (or iexp) (baseexp), is returned.

If a domain error occurs , an implementation-defined value is returned ( NaN where supported )

If a pole error or a range error due to overflow occurs, ±HUGE_VAL, ±HUGE_VALF, or ±HUGE_VALL is returned.

If a range error occurs due to underflow, the correct result (after rounding) is returned.

Reading further:

Error handling

...

except where specified above, if any argument is NaN, NaN is returned

So basically, since n is increasing and and you have many loops pow returns NaN (the compiler you use obviously supports that). The rest is arithmetic. You calculate with overflowing values.

I believe you are trying to approximate sin(x) by using its Taylor series. I am not sure if that is the way to go.

Maybe you can try to stop the loop as soon as you hit NaN and not update the variable next and simply output that. That's the closest you can get I believe with your algorithm.

If you had compiled your system with any reasonable level of warnings enabled you would have immediately seen that you are not using the variable accuracy . This and the fact that your fact function returns a long int are but a small part of your problem. You will never get a good result for sin(45) using your algorithm even if you correct those issues.

The problem is that with x=45 , the terms in the Taylor expansion of sin(x) won't start decreasing until n=45 . This is a big problem because 45 45 /45! is a very large number, 2428380447472097974305091567498407675884664058685302734375 / 1171023117375434566685446533210657783808, or roughly 2*10 18 . Your algorithm initially adds and subtracts huge numbers that only start decreasing after 20+ additions/subtractions, with the eventual hope that the result will be somewhere between -1 and +1. That is an unrealizable hope given an input value of 45 and using a native floating point type.

You could use some BigNum type (the internet is chock-full of them) with your algorithm, but that's extreme overkill when you only want four place accuracy. Alternatively, you could take advantage of the cyclical nature of sin(x) , sin(x+2*pi)=sin(x) . An input value of 45 is equivalent to 1.017702849742894661522992634... (modulo 2*pi). Your algorithm works quite nicely for an input of 1.017702849742894661522992634.

You can do much better than that, but taking the input value modulo 2*pi is the first step toward a reasonable algorithm for computing sine and cosine. Even better, you can use the facts that sin(x+pi)=-sin(x) . This lets you reduce the range from -infinity to +infinity to 0 to pi. Even better, you can use the fact that between 0 and pi, sin(x) is symmetric about pi/2. You can do even better than that. The implementations of the trigonometric functions take extreme advantage of these behaviors, but they typically do not use Taylor approximations.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM