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.3is 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.3has typedouble. If you wrote@(0.3f)then it would use-numberWithFloat:.Neither
floatnordoublecan 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 thefloatclosest to 0.3 and thedoubleclosest to 0.3. These two numbers are not equal to each other, so-containsObject:can't find a match.Both
floatanddoublecan store 0.0 and 1.0 exactly, so both conversions give you the same result and-containsObject:succeeds.