Calculations failed because of - nan - c++

My exercise is to write code which will print the value of this phrase
I have written a code which should work, but when I try to print a value I receive "the value is -nan".
//My Code
#include <iostream>
#include <stdio.h>
#include <cmath>
using namespace std;
int main()
{
double y;
double x = 21;
y = 30 * sqrt(x * (1/(tan(sqrt(3*x) - 2.1))));
printf ("The value is: \n=> %f", y );
}
My question is how can I print the proper value?

try this
printf( "sqrt(3*x) = %lf\n", sqrt(3*x));
printf( "sqrt(3*x) - 2.1 = %lf\n", sqrt(3*x) - 2.1);
printf( "tan(sqrt(3*x) - 2.1) = %lf\n", tan(sqrt(3*x) - 2.1));
then you will notice that the last one is negative which will result in a sqrt of a negative number, thus the NaN

The problem is that, depending on the unit (radians or degrees), you get different results with trigonometric functions. Keep in mind that the tan function expects its argument in radians.
sqrt(3*21)-2.1 = 5.837, and you have to calculate its tangent. It is indeed negative if we work with radians (it is around -0.478), leading to the square root of a negative number which is NaN (Not a Number), but if you use degrees then it is +0.102 and you can complete the calculation. If you want to have the result you would have with degrees, considering the function accepts radians, you must convert the number. The conversion is simple: multiply by Pi and divide by 180. Like this:
y = 30 * sqrt(x * (1/(tan((sqrt(3*x) - 2.1)*M_PI/180))));
In this case the result is 429.967.

If the problem is not related with conversion to radians, i.e. multiplication by M_PI / 180.
In general, operations that produce NaN (Not a Number)1 are:
In your case the result of tan() is negative which leads to negative input value for the outer sqrt(), which is the last example from the above table.
To resolve the problematic situation you could either use some mathematical trick2 and try to rewrite the expression such that it doesn't produce a NaN, or if the problem is in the negative square root, you can use the #include <complex> and:
std::complex<double> two_i = std::sqrt(std::complex<double>(-4));
The rest of the answers provide you with a strategy of how to identify the NaN source, by checking each computation involved
1. Bit patterns reserved for special quantities to handle exceptional situations like taking the square root of a negative number, other than aborting computation are called NaNs.
2. Use trigonometric relations.
where #define M_PI = 3.14159265358979323846;

Related

Im trying to calculate the formula of a sphere using cpp

Im making a calculator that can code the volume of a sphere, but i cant make the formula without getting the wrong answer. volume of sphere is 4/3 pi r cubed. And cant figure out how to make a fraction without making a complex function. Any idea on how to write out the formula correctly?
}else if (volumeChoice == "sphere"){
double sphereRadius { 0 };
const double pi { 3.14159265358979323846 };
cout << "Enter the radius\n";
cin >> sphereRadius;
double sphereFormula { (4/3) pi * pow(3.0, sphereRadius)};
cout << sphereFormula;
There are a couple main issues I noticed.
One: 4/3 uses integer division in C++, so the result returns 1, not 1.3333...
Change it to 4.0/3.0
Two: There is no multiplication sign between the 4/3 and pi, so it shouldn't compile.
Three: The pow function first parameter is the base, and the second is the exponent. The call should be pow(sphereRadius, 3.0) not pow(3.0, sphereRadius)
The line after changes should look like the following:
double sphereFormula { (4.0/3.0) * pi * pow(sphereRadius, 3.0)};
4 / 3 is integer division (result is 1), and your result will not be accurate because of that. Change it to 4.0 / 3.0 and you should see better results.
I'd be surprised if this code compiles because you're missing a multiplication sign between your four thirds and pi.
Finally, your arguments to pow() are switched. The first argument is the base, the second is the exponent. It never hurts to refer to the documentation.
double sphereFormula{(4.0 / 3.0) * pi * pow(sphereRadius, 3.0)};
A touch more explanation:
C++ reads natural number literals (4 and 3 in your case) as integers. Placing a .0 causes the compiler to read the literal as a double. C++ is not like python or other languages that will produce a decimal result from integer division.

How does Cpp work with large numbers in calculations?

I have a code that tries to solve an integral of a function in a given interval numerically, using the method of Trapezoidal Rule (see the formula in Trapezoid method ), now, for the function sin(x) in the interval [-pi/2.0,pi/2.0], the integral is waited to be zero.
In this case, I take the number of partitions 'n' equal to 4. The problem is that when I have pi with 20 decimal places it is zero, with 14 decimal places it is 8.72e^(-17), then with 11 decimal places, it is zero, with 8 decimal places it is 8.72e^(-17), with 3 decimal places it is zero. I mean, the integral is zero or a number near zero for different approximations of pi, but it doesn't have a clear trend.
I would appreciate your help in understanding why this happens. (I did run it in Dev-C++).
#include <iostream>
#include <math.h>
using namespace std;
#define pi 3.14159265358979323846
//Pi: 3.14159265358979323846
double func(double x){
return sin(x);
}
int main() {
double x0 = -pi/2.0, xf = pi/2.0;
int n = 4;
double delta_x = (xf-x0)/(n*1.0);
double sum = (func(x0)+func(xf))/2.0;
double integral;
for (int k = 1; k<n; k++){
// cout<<"func: "<<func(x0+(k*delta_x))<<" "<<"last sum: "<<sum<<endl;
sum = sum + func(x0+(k*delta_x));
// cout<<"func + last sum= "<<sum<<endl;
}
integral = delta_x*sum;
cout<<"The value for the integral is: "<<integral<<endl;
return 0;
}
OP is integrating y=sin(x) from -a to +a. The various tests use different values of a, all near pi/2.
The approach uses a linear summation of values near -1.0, down to 0 and then up to near 1.0.
This summation is sensitive to calculation error with the last terms as the final math sum is expected to be 0.0. Since the start/end a varies, the error varies.
A more stable result would be had adding the extreme f = sin(f(k)) values first. e.g. sum += sin(f(k=1)), then sum += sin(f(k=3)), then sum += sin(f(k=2)) rather than k=1,2,3. In particular the formation of term x=f(k=3) is likely a bit off from the negative of its x=f(k=1) earlier term, further compounding the issue.
Welcome to the world or numerical analysis.
Problem exists if code used all float or all long double, just different degrees.
Problem is not due to using an inexact value of pi (Exact value is impossible with FP as pi is irrational and all finite FP are rational).
Much is due to the formation of x. Could try the below to form the x symmetrically about 0.0. Compare exactly x generated this way to x the original way.
x = (x0-x1)/2 + ((k - n/2)*delta_x)
Print out the exact values computed for deeper understanding.
printf("x:%a y:%a\n", x0+(k*delta_x), func(x0+(k*delta_x)));

How to increase accuracy of floating point second derivative calculation?

I've written a simple program to calculate the first and second derivative of a function, using function pointers. My program computes the correct answers (more or less), but for some functions, the accuracy is less than I would like.
This is the function I am differentiating:
float f1(float x) {
return (x * x);
}
These are the derivative functions, using the central finite difference method:
// Function for calculating the first derivative.
float first_dx(float (*fx)(float), float x) {
float h = 0.001;
float dfdx;
dfdx = (fx(x + h) - fx(x - h)) / (2 * h);
return dfdx;
}
// Function for calculating the second derivative.
float second_dx(float (*fx)(float), float x) {
float h = 0.001;
float d2fdx2;
d2fdx2 = (fx(x - h) - 2 * fx(x) + fx(x + h)) / (h * h);
return d2fdx2;
}
Main function:
int main() {
pc.baud(9600);
float x = 2.0;
pc.printf("**** Function Pointers ****\r\n");
pc.printf("Value of f(%f): %f\r\n", x, f1(x));
pc.printf("First derivative: %f\r\n", first_dx(f1, x));
pc.printf("Second derivative: %f\r\n\r\n", second_dx(f1, x));
}
This is the output from the program:
**** Function Pointers ****
Value of f(2.000000): 4.000000
First derivative: 3.999948
Second derivative: 1.430511
I'm happy with the accuracy of the first derivative, but I believe the second derivative is too far off (it should be equal to ~2.0).
I have a basic understanding of how floating point numbers are represented and why they are sometimes inaccurate, but how can I make this second derivative result more accurate? Could I be using something better than the central finite difference method, or is there a way I can get better results with the current method?
The accuracy can be increased by choosing a type which has more precision. float is currently defined as an IEEE-754 32-bit number, giving you a precision of ~7.225 decimal places.
What you want is the 64-bit counterpart: double with ~15.955 decimal places accuracy.
That should be sufficient for your calculation, however worth mentioning is boosts implementation which offers a quadruple-precision floating point number (128-bit).
Finally The GNU Multiple Precision Arithmetic Library offers types with an arbitrary number of decimal places for precision.
Go analytical. ;-) probably not an option given "with the current
method".
Use double instead of float.
Vary the epsilon (h), and combine the results in some way. For example you could try 0.00001, 0.000001, 0.0000001 and average them. In fact, you'd want the result with the smallest h that doesn't overflow/underflow. But it's not clear how to detect overflow and underflow.

The result of own double precision cos() implemention in a shader is NaN, but works well on the CPU. What is going wrong?

as i said, i want implement my own double precision cos() function in a compute shader with GLSL, because there is just a built-in version for float.
This is my code:
double faculty[41];//values are calculated at the beginning of main()
double myCOS(double x)
{
double sum,tempExp,sign;
sum = 1.0;
tempExp = 1.0;
sign = -1.0;
for(int i = 1; i <= 30; i++)
{
tempExp *= x;
if(i % 2 == 0){
sum = sum + (sign * (tempExp / faculty[i]));
sign *= -1.0;
}
}
return sum;
}
The result of this code is, that the sum turns out to be NaN on the shader, but on the CPU the algorithm is working well.
I tried to debug this code too and I got the following information:
faculty[i] is positive and not zero for all entries
tempExp is positive in each step
none of the other variables are NaN during each step
the first time sum is NaN is at the step with i=4
and now my question: What exactly can go wrong if each variable is a number and nothing is divided by zero especially when the algorithm works on the CPU?
Let me guess:
First you determined the problem is in the loop, and you use only the following operations: +, *, /.
The rules for generating NaN from these operations are:
The divisions 0/0 and ±∞/±∞
The multiplications 0×±∞ and ±∞×0
The additions ∞ + (−∞), (−∞) + ∞ and equivalent subtractions
You ruled out the possibility for 0/0 and ±∞/±∞ by stating that faculty[] is correctly initialized.
The variable sign is always 1.0 or -1.0 so it cannot generate the NaN through the * operation.
What remains is the + operation if tempExp ever become ±∞.
So probably tempExp is too high on entry of your function and becomes ±∞, this will make sum to be ±∞ too. At the next iteration you will trigger the NaN generating operation through: ∞ + (−∞). This is because you multiply one side of the addition by sign and sign switches between positive and negative at each iteration.
You're trying to approximate cos(x) around 0.0. So you should use the properties of the cos() function to reduce your input value to a value near 0.0. Ideally in the range [0, pi/4]. For instance, remove multiples of 2*pi, and get the values of cos() in [pi/4, pi/2] by computing sin(x) around 0.0 and so on.
What can go dramatically wrong is a loss of precision. cos(x) usually is implemented by range reduction followed by a dedicated implementation for the range [0, pi/2]. Range reduction uses cos(x+2*pi) = cos(x). But this range reduction isn't perfect. For starters, pi cannot be exactly represented in finite math.
Now what happens if you try something as absurd as cos(1<<30) ? It's quite possible that the range reduction algorithm introduces an error in x that's larger than 2*pi, in which case the outcome is meaningless. Returning NaN in such cases is reasonable.

Solving equation for y

When testing out the equation I get a -1.#IND00 as an answer when it solves for y. I'm basically trying to create a program that solves for y give the equation below
y=y/(3/17)-z+x/(a%2)+PI
#include <stdio.h>
#include <math.h>
#define PI 3.14
int main (void)
{
int a=0;
double z=0,x=0,y=0;
printf("Values for x, z, and a:");
scanf("%lf%lf%d", &x,&z,&a);
y = (((y/(double)(3/17)))-z + (x/(a%2))+PI);
printf("y = %lf\n", y);
return 0;
}
Since there are no questionmarks, I assume the question is "How do you write a C++ program that solves this equation?"
C++ is a programming language and by itself is not able to solve your equation, i.e. C++ won't do any transformation to your equation to get it into a form where y occurs only on the lefthand side and all parameters on the righthand side. You have to transform it yourself, manually or by using a solver.
What happens in the posted code?
Lets start at the leftmost part of the equation y/(double)(3/17) from inside out according to the parentheses:
3/17 is interpreted as integer division, which results in 0;
(double)(0) casts the integer 0 into a double of 0.0;
y/0.0 is a division by 0 as explained in this post which results in your error.
You could fix this as pointed out in the comments by either casting the first integer like (double)3/17 or turning the integer 3 into a double 3.0 or using static_cast.
However, y is still initialized to 0, so y/(double)3/17 is 0 and the equation calculated is basically -z + x/(a%2) + PI.
So, unless you transform the equation and put the transformed equation into the code, you won't get the results you expect.