1

On iOS, I attempt to store a number 1448924191 as an NSNumber and then retrieve it as a float with floatValue:

 double max_float = MAXFLOAT; // really big num (3.4028234663852886E+38) double someEpoch = 1448924191; NSNumber *epochNum = [NSNumber numberWithDouble:someEpoch]; // 

But when I ask for the float back, the return is off - rounded to the nearest 60-unit interval it seems:

 float asFloat = [epochNum floatValue]; // 1448924160 - rounded to 60??? double asDouble = [epochNum doubleValue]; // 1448924191 - correct 

Using doubleValue solves the issue, but why? Shouldn't float be able to handle this number since it is far less than FLOAT_MAX?

5
  • 2
    Do you know how floating point numbers work? Commented Nov 30, 2015 at 23:25
  • 1
    That number has too many significant digits to be stored as a float. Use double. Commented Nov 30, 2015 at 23:27
  • See stackoverflow.com/questions/16108431/… for details. Commented Nov 30, 2015 at 23:28
  • 1
    BTW - your question has nothing to do with MAX_FLOAT. Commented Nov 30, 2015 at 23:30
  • 1
    An analogy: "3.1 is less than INT_MAX, so why does int x = (int)3.1; store 3 in x?" Commented Nov 30, 2015 at 23:31

1 Answer 1

1

As has been mentioned in the comments on your question, this is a fundamental limitation of floating-point numbers. A float on iOS is a 32-bit floating-point number. Some of those bits are used to store an exponent, so the number of significant digits that can be stored is substantially less than the number of digits in an int, for example.

If you #import <float.h>, you'll get access to a number of macros that will tell you the details of the floating-point format, including:

FLT_DIG

This is the number of decimal digits of precision for the float data type. Technically, if p and b are the precision and base (respectively) for the representation, then the decimal precision q is the maximum number of decimal digits such that any floating point number with q base 10 digits can be rounded to a floating point number with p base b digits and back again, without change to the q decimal digits.

Which is more-or-less the number of digits in the largest number that you can convert from int to float without losing any precision. It's actually a conservative estimate - you can calculate the absolute largest integer you can store in a float by doing some calculations with the other macros in that header, though I doubt that'll ever be something you'll want to do.

Speaking of converting from int to float, you should also be aware that in this line of code from your example:

double someEpoch = 1448924191; 

You're implicitly converting from the integer 1448924191 to a double representation. This works fine, because 1448924191 is exactly-representable as both a double and an int. If you make that value larger than what will fit into a long int, you can get strange behavior, since the constant will get stored as an unsigned long, then converted to double. The compiler will at least warn you about this error when it occurs.

If you want a double constant, you should make sure to include a decimal point in the value:

double someEpoch = 1448924191.0; 

This is less-critical if you're just going to assign it to a double variable immediately, but if you ever #define a float constant, it's useful to add the decimal point to ensure it gets treated as a floating-point value everywhere that it's used.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.