0

I am very hesitant to put this because I know that 99.9% of the time the user is to blame for an error but I am seriously confused about this one.

I have a float named rotation defined in my header as such:

@property(nonatomic)float rotation;

After the rotation has been given a value I check it using this if statement

if (fabsf(rotation) == M_PI_2)
{
    NSLog(@"Execute more code now");
}

Now I have checked the definition of M_PI_2 and came up with 1.57079632679489661923132169163975144

I noticed that it wasn't working so I put another NSLog before the if statement as such:

    NSLog(@"%f == %f", fabs(rotation), M_PI_2);

These were the results I got:

2014-06-26 16:29:40.831 76J284E[82085:60b] 0.000000 == 1.570796
2014-06-26 16:29:40.834 76J284E[82085:60b] 3.141593 == 1.570796
2014-06-26 16:29:44.653 76J284E[82085:60b] 0.000000 == 1.570796
2014-06-26 16:29:44.658 76J284E[82085:60b] 3.141593 == 1.570796
2014-06-26 16:29:47.951 76J284E[82085:60b] 0.000000 == 1.570796
2014-06-26 16:29:47.953 76J284E[82085:60b] 3.141593 == 1.570796
2014-06-26 16:29:54.305 76J284E[82085:60b] 0.000000 == 1.570796
2014-06-26 16:29:54.310 76J284E[82085:60b] 1.570796 == 1.570796
2014-06-26 16:29:54.313 76J284E[82085:60b] 4.712389 == 1.570796
2014-06-26 16:29:54.318 76J284E[82085:60b] 3.141593 == 1.570796

Shouldn't a few of those trigger the if statement? What am I doing wrong here, thanks.

Edit

I should add that I am defining rotation with M_PI_2 (At certain times)

TrevorPeyton
  • 629
  • 3
  • 10
  • 22
  • try defining M_PI_2 `1.570796` not `1.57079632679489661923132169163975144` – sertsedat Jun 26 '14 at 20:41
  • How exact a match do you expect? your nslog is only showing 6 decimal places of precision. You'll have to do some rounding or implement substring to allow for less precise matches. – Scott Solmer Jun 26 '14 at 20:43
  • @jackjop I had thought that and just tested that no luck. Could it be that I just have to find the correct number of places? I've had to do this with ints before. – TrevorPeyton Jun 26 '14 at 20:43
  • @jackjop Doesn't help because fabsf is just a different version of abs but for floats so it would most certainly return a float (but I still did try it and it didn't work). – TrevorPeyton Jun 26 '14 at 20:49
  • no no this `if (fabsf(rotation) == M_PI_2.f) ` --- my bad sorry – sertsedat Jun 26 '14 at 20:49
  • which had been explained [here](http://stackoverflow.com/questions/24439793/objective-c-if-statement-possibly-not-working-correctly) – sertsedat Jun 26 '14 at 20:51
  • just try it, I'm curious – sertsedat Jun 26 '14 at 20:55
  • M_PI_2.f doesn't exist because it was a double (which was the underlying problem). – TrevorPeyton Jun 26 '14 at 21:05

3 Answers3

2

The numbers are not equal, you just aren't printing the complete value of the floating point number. This article talks about C++, but the same principles apply.

onit
  • 6,306
  • 3
  • 24
  • 31
  • The only problem of why I have trouble believing this is because I define rotation with M_PI_2. – TrevorPeyton Jun 26 '14 at 20:45
  • Floating point is not guaranteed to be associative or distributive. – onit Jun 26 '14 at 20:54
  • 1
    If `rotation` is a `float` but `M_PI_2` is a `double`, then `rotation = M_PI_2` converts the `double` to a `float`, losing precision. When you then compare `rotation == M_PI_2`, the float is **promoted** to a double, but it doesn't get back the lost information. In other words, `rotation` really doesn't equal `M_PI_2` because it can't hold all of the information in the latter. – Ken Thomases Jun 26 '14 at 20:55
  • @KenThomases Thank you, I had assumed M_PI_2 was a float. – TrevorPeyton Jun 26 '14 at 21:04
2

Your problem is that M_PI_2 is a double and rotation is a float. This statement:

float rotation = M_PI_2;

takes the double-precision constant M_PI_2, rounds it to float precision (throwing away 29 bits of mantissa) and then assigns it to rotation.

Later on you check to see if the rounded value matches the unrounded value. It doesn't. 'cause it's been rounded.

try defining M_PI_2 1.570796

Nope. 1.570796 is still a double, and cannot be exactly represented by a float or a double, so the rounding issue still occurs. Try this:

const float M_PI_2 = 1.57079632679489661923132169163975144f;

float rotation = M_PI_2;

if (rotation == M_PI_2) ...

Assigning the constant to a float and/or appending 'f' to the constant will do the trick.

For more details:

http://randomascii.wordpress.com/2012/06/26/doubles-are-not-floats-so-dont-compare-them/

Also, when printing floats you need to print nine digits of mantissa, otherwise you don't know what float you have. For doubles you need 17 digits of mantissa. For more information:

http://randomascii.wordpress.com/2012/03/08/float-precisionfrom-zero-to-100-digits-2/

Bruce Dawson
  • 3,284
  • 29
  • 38
1

There are two problems. You defined M_PI_2 to be 1.57079632679489661923132169163975144 and your trying to see if it's equal to 1.570796. It's almost equal but not quite. If those numbers were how many trillions of dollars I have in my account, I'd prefer them to not be equal and to take the M_PI_2 one.

Second you can't directly compare floating point numbers due to floating point calculation errors. Heres a good discussion on the problem How dangerous is it to compare floating point values?

Community
  • 1
  • 1
Brandon
  • 2,387
  • 13
  • 25
  • So even if i'm correct even if I do `float numberOne = .1234; float numberTwo = numberOne;` it's incorrect? – TrevorPeyton Jun 26 '14 at 20:49
  • I realized I used the word can't. I really meant you shouldn't. Most of the time comparing a float to a float will work, but you will run into cases where 1.5 != 1.5. The same reasoning applies to calculations like division. 100/10.0 might really be 9.999999999 or 10.00000000000001 – Brandon Jun 26 '14 at 20:51
  • Ya, I understand that now (and from now on I won't be comparing them) but my edit states that I define rotation using M_PI_2. – TrevorPeyton Jun 26 '14 at 20:52
  • Even if you use a #define for a floating point number, the computer still needs to represent that floating point number somewhere in memory, which means it's going to be susceptible to the floating point rounding problem. In general this really isn't a big deal except in places like financial applications or when you expect your condition to pass but it fails because of it. – Brandon Jun 26 '14 at 20:57
  • See the third answer. The number of digits is not the problem. Float versus double is the problem -- different amounts of rounding. – Bruce Dawson Jun 26 '14 at 23:28