I have some method that receives a float
as an argument, and checks to see if this float is in an array. To do this, I first convert the float to a NSNumber
. This is a testable simplification of my code:
float aFloat = 0.3;
NSNumber *aNSNumber = @(aFloat);
NSArray *anArray = @[@(0.0), @(0.3), @(1.0)];
NSLog(@"%d", [anArray containsObject:aNSNumber]);
This code will log 0
(i.e. NO
), so it's saying that 0.3
is not in anArray
. If aFloat
is a "round" number such as 0.0
, 0.5
, or 1.0
, the test works and logs 1
(i.e. YES
). Any number other than that, like the 0.3
above, fails.
In the other hand, if we change aFloat
to be a double
, it works. Or, if we change anArray
to this:
NSArray *array = @[[NSNumber numberWithFloat:0.0], [NSNumber numberWithFloat:0.3], [NSNumber numberWithFloat:1.0]];
It also works. What I presumed is that the NSNumber @()
notation creates a numberWithDouble:
.
But, my question is, shouldn't it work even when aFloat
is a float
? Since I'm "converting" it anyways by saving it in aNSNumber
... And shouldn't it automatically recognize that the float
0.3
and the double
0.3
are actually the same numbers? Also, why the "round" numbers works anyway?
@(0.3)
uses-numberWithDouble:
because0.3
has typedouble
. If you wrote@(0.3f)
then it would use-numberWithFloat:
.Neither
float
nordouble
can store 0.3 exactly. (It's similar to the problem of writing 1/3 in decimal form - you can't do it exactly using a finite number of digits.) Instead, you get thefloat
closest to 0.3 and thedouble
closest to 0.3. These two numbers are not equal to each other, so-containsObject:
can't find a match.Both
float
anddouble
can store 0.0 and 1.0 exactly, so both conversions give you the same result and-containsObject:
succeeds.