Multi line math results different than single line

Viewed 398

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

3 Answers

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 ; ).

Related