8
NSString *str = @"37.3336";
float f = [str floatValue];

f is 37.3335991.

Aside from rounding this myself, is there a way to get the exact float value from a NSString?

CodaFi
  • 43,043
  • 8
  • 107
  • 153
Morrowless
  • 6,856
  • 11
  • 51
  • 81

2 Answers2

4

Use [NSDecimalNumber decimalNumberWithString:locale:]. This will maintain the number in a decimal format rather than a binary format.

Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • that works but still a question how can I convert string to float making it 37.33360000? NSNUmber.floatValue still gives 37.3335991 – Yaro Sep 03 '20 at 07:43
  • @Yaro https://stackoverflow.com/questions/588004/is-floating-point-math-broken The point of this answer is that if you need to work with a decimal representation (i.e. you want specific digits in base 10), then you need to work with NSDecimalNumber. You cannot convert it to a floats. Floats are not stored in base 10. – Rob Napier Sep 03 '20 at 12:55
  • So the best approach is to write a function that converts base 10 NSNumber 37.3336 to float 37.333600? There is got to be a better way. – Yaro Sep 04 '20 at 15:00
  • @Yaro There is no such thing as "float 37.333600". It's the same as "1/3 in decimal." Decimal digits cannot express some fractions precisely. In exactly the same way, a binary float cannot express 37.3336 precisely. If you need the actual digits 37.3336, you cannot use float directly. You can use DecimalNumber, or you can scale scale everything and use Int, or you can apply rounding during display. But you cannot convert this directly to a float; please see the linked answer for more, as well as the most famous https://floating-point-gui.de. – Rob Napier Sep 04 '20 at 15:56
4

Not easily. It's entirely possible that the number represented in the NSString has no exact representation as a primitive floating-point type.

If you know your input will never exceed a certain length, and don't need to be able to parse to a primitive floating-point type then you could use something like NSDecimalNumber (good for up to 38 digits) or implement a comparable utility yourself where you note the position of the decimal point, parse the number as an integer, and reinsert the decimal point at the correct location whenever you need to print it out.

Or if your input length is meant to be unconstrained then the only thing you can really try is using an arbitrary-precision arithmetic library.

Note that with any of these approaches, you still will not be able to construct a primitive floating-point value that is guaranteed to exactly match your input. If you need exact precision then you simply cannot rely upon float and double.

aroth
  • 54,026
  • 20
  • 135
  • 176