Has anyone seen this weird value while handling sin / cos/ tan / acos.. math stuff?
===THE WEIRD VALUE===
-1.#IND00
=====================
void inverse_pos(double x, double y, double& theta_one, double& theta_two)
{
// Assume that L1 = 350 and L2 = 250
double B = sqrt(x*x + y*y);
double angle_beta = atan2(y, x);
double angle_alpha = acos((L2*L2 - B*B - L1*L1) / (-2*B*L1));
theta_one = angle_beta + angle_alpha;
theta_two = atan2((y-L1*sin(theta_one)), (x-L1*cos(theta_one)));
}
This is the code I was working on.
In a particular condition - like when x & y are 10 & 10,
this code stores -1.#IND00 into theta_one & theta_two.
It doesn't look like either characters or numbers :(
Without a doubt, atan2 / acos / stuff are the problems.
But the problem is, try and catch doesn't work either
cuz those double variables have successfully stored
some values in them.
Moreover, the following calculations never complain about it
and never break the program!
I'm thinking of forcing to use this value somehow and make the entire program crash...
So that I can catch this error..
Except for that idea, I have no idea how I should check whether these
theta_one and theta_two variables have stored this crazy values.
Any good ideas?
Thank you in advance..
The "weird value" is NaN (not a number).
The problem is because (L2*L2 - B*B - L1*L1) / (-2*B*L1) = 6.08112… is outside of the range [-1, 1] where acos is well-defined for real numbers. So NaN is returned.
Are you sure the formula is correct?
If you want to catch an NaN, the NaN needs to be a signaling NaN. For gcc, compile with the -fsignaling-nans option.
Related
I have a calculation using double and run into problems due to catastrophic cancellation (nearly equal values are subtracted). I am looking for a rearrangement to keep the loss of significance at a minimum.
My equation is that of a plane from which I compute z = z(x, y) (with a set of constants z0, x21, ...):
// (z-z0)*(x21*y31 - y21*x31) = (x-x0)*(y21*z31 - z21*y31) + (y-y0)*(z21*x31-x21*z31)
double z = z0 + (x-x0)*(y21*z31 - z21*y31)/(x21*y31 - y21*x31)
+ (y-y0)*(z21*x31-x21*z31)/(x21*y31 - y21*x31);
One set of values for which I run into problems is given below. In this case it is due to y-terms all being close to zero (y21 ~= -0.0032, y31 ~= -0.0097, y-y0 ~= -0.0032):
(z-z0) * 9.3241e-18 ~= 0.1112*0.0830 + (-0.0032)*2.8428
~= 0.009234 - 0.009234
~= 5.2042e-18
The result is barely usable since I suspect both 9.3241e-18 and 5.2042e-18 to be affected by calculation errors.
I am looking for a way to deal with calculation errors due to subtraction in general and a smart rearrangement for the special case of y21, y31, y-y0 being close to zero in particular. The rearrangement I tried have not had success so far. How can I deal with those calculation problems (in C++).
I was having an issue with some floating point math and I've found that if I do my math on one line, I get -0 passed to tan(), and if I do it across two lines, I get 0 passed to tan(). Have a look:
float theta = PI / 2.f;
float p = (PI / 2.f) - theta;
float result = tan(p);
The above, p = -0, result = -4.37...
float theta = PI / 2.f;
float p = PI / 2.f;
p -= theta;
float result = tan(p);
The above, p = 0, result = 0.
Can anyone explain the difference? I assume the -0 is causing that result from tan(), although I can't find anything on google that explains why. Why does the exact same calculation spread across different lines result in a different answer?
Thanks
It is probably because of the type of PI.
If you use double it will change to float and then the outcome
will be as you just represent.
But if PI is float both of this test scenarios are equal.
What #Naor says is probably correct. but I'd like to add something.
You probably not getting -4.37xx but -4.37xxxe-xx which is a pretty small negative number.
Since you can always get errors in floating point math. I'd say there is no need to change your code. Both snips are correct.
So this is what, in my opinion, is happening:
In both examples PI is a define, probably defined like this:
#define 3.14 //and some more digits
In C++, number like this is treated as double.
After preprocessing, this expression:
PI / 2.0f
will be treated as double-typed prvalue. This means that this line hides one more operation:
float theta = PI / 2.f;
which is a double-to-float conversion, which definitely looses some precision in this case.
In first example this also happens here:
float p = (PI / 2.f) - theta;
but only after evaluating whole expression. Note that during this evaluation (PI / 2.f) will be still double, but theta will be a float-to-double converted value, which explains the slight difference in result from 0.0.
In your last example you first convert (PI / 2.f) to float:
float p = PI / 2.f;
to subtract float-typed theta from it in next line. Which must result to 0.0, which probably compiler optimized out anyway ; ).
I am writing a program for class that simply calculates distance between two coordinate points (x,y).
differenceofx1 = x1 - x2;
differenceofy1 = y1 - y2;
squareofx1 = differenceofx1 * differenceofx1;
squareofy1 = differenceofy1 * differenceofy1;
distance1 = sqrt(squareofx1 - squareofy1);
When I calculate the distance, it works. However there are some situations such as the result being a square root of a non-square number, or the difference of x1 and x2 / y1 and y2 being negative due to the input order, that it just gives a distance of 0.00000 when the distance is clearly more than 0. I am using double for all the variables, should I use float instead for the negative possibility or does double do the same job? I set the precision to 8 as well but I don't understand why it wouldn't calculate properly?
I am sorry for the simplicity of the question, I am a bit more than a beginner.
You are using the distance formula wrong
it should be
distance1 = sqrt(squareofx1 + squareofy1);
instead of
distance1 = sqrt(squareofx1 - squareofy1);
due to the wrong formula if squareofx1 is less than squareofy1 you get an error as sqrt of a negative number is not possible in case of real coordinates.
Firstly, your formula is incorrect change it to distance1 = sqrt(squareofx1 + squareofy1) as #fefe mentioned. Btw All your calculation can be represented in one line of code:
distance1 = sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2));
No need for variables like differenceofx1, differenceofy1, squareofx1, squareofy1 unless you are using the results stored in these variables again in your program.
Secondly, Double give you more precision than float. If you need precision more than 6-7 places after decimal use Double else float works too. Read more about Float vs Double
I stumbled across code like
double x,y = ...;
double n = sqrt(x*x+y*y);
if (n > 0)
{
double d1 = (x*x)/n;
double d2 = (x*y)/n;
}
and I am wondering about the numerical stability of such an expression for small values of x and y.
For both expressions, lim (x->0, y->0) (...) = 0, so from a mathematical point of view, it looks safe (the nominator O(x²) whereas the denominator is O(x)).
Nevertheless my question is: Are there any possible numerical problems with this code?
EDIT: If possible I'd like to avoid re-writing the expressions because n is actually used more than twice and to keep readability (it's relatively clear in the context what happens).
If x and y are very close to DBL_MIN, the calculations are
succeptible to underflow or extreme loss of precision: if x is
very close to DBL_MIN, for example x * x may be 0.0, or
(for somewhat larger values) it may result in what is called
gradual underflow, with extreme loss of precision: e.g. with
IEEE double (most, if not all desktop and laptop PCs), 1E-300
* 1E-300 will be 0.0. Obviously, if this happens for both
* x and y, you'll end up with n == 0.0, even if x and
y are both positive.
In C++11, there is a function hypot, which will solve the
problem for n; if x * x is 0.0, however, d1 will still
be 0.0; you'll probably get better results with (x / n) * x
(but I think that there still may be limit cases where you'll
end up with 0.0 or gradual underflow—I've not analyzed it sufficiently to be sure). A better solution
would be to scale the data differently, to avoid such limit
cases.
double MyClass::dx = ?????;
double MyClass::f(double x)
{
return 3.0*x*x*x - 2.0*x*x + x - 5.0;
}
double MyClass::fp(double x) // derivative of f(x), that is f'(x)
{
return (f(x + dx) - f(x)) / dx;
}
When using finite difference method for derivation, it is critical to choose an optimum dx value. Mathematically, dx must be as small as possible. However, I'm not sure if it is a correct choice to choose it the smallest positive double precision number (i.e.; 2.2250738585072014 x 10−308).
Is there an optimal numeric interval or exact value to choose a dx in to make the calculation error as small as possible?
(I'm using 64-bit compiler. I will run my program on a Intel i5 processor.)
Choosing the smallest possible value is almost certainly wrong: if dx were that smallest number, then f(x + dx) would be exactly equal to f(x) due to rounding.
So you have a tradeoff: Choose dx too small, and you lose precision to rounding errors. Choose it too large, and your result will be imprecise due to changes in the derivative as x changes.
To judge the numeric errors, consider (f(x + dx) - f(x))/f(x)1 mathematically. The numerator denotes the difference you want to compute, but the denominator denotes the magnitude of numbers you're dealing with. If that fraction is about 2‒k, then you can expect approximately k bits of precision in your result.
If you know your function, you can compute what error you'd get from choosing dx too large. You can then balence things, so that the error incurred from this is about the same as the error incurred from rounding. But if you know the function, you might be better off by providing a function that directly computes the derivative, like in your example with the polygonal f.
The Wikipedia section that pogorskiy pointed out suggests a value of sqrt(ε)x, or approximately 1.5e-8 * x. Without any more detailed knowledge about the function, such a rule of thumb will provide a reasonable default. Also note that that same section suggests not dividing by dx, but instead by (x + dx) - x, as this takes rounding errors incurred by computing x + dx into account. But I guess that whole article is full of suggestions you might use.
1 This formula really should divide by f(x), not by dx, even though a past editor thought differently. I'm attempting to compare the amount of significant bits remaining after the division, not the slope of the tangent.
Why not just use the Power Rule to derive the derivative, you'll get an exact answer:
f(x) = 3x^3 - 2x^2 + x - 5
f'(x) = 9x^2 - 4x + 1
Therefore:
f(x) = 3.0 * x * x * x - 2.0 * x * x + x - 5.0
fp(x) = 9.0 * x * x - 4.0 * x + 1.0