0

I have a string representing a rational number.

I want to convert the string to a float with strtof(nptr, &endptr)

The problem is that e.g. a string "1.0000000000000000000001" will be converted to 1. without raising any flags (iirc).

Therefore my question: How does one catch this precision loss?

stht55
  • 390
  • 1
  • 8
  • 2
    "a string `"0.00000000000000000000001"` will be converted to `0`" [Couldn't reproduce](https://ideone.com/izDbyG). – MikeCAT Jul 17 '22 at 17:29
  • @MikeCAT I edited my question. This string I gave as an example is converted to 1. in my example. – stht55 Jul 17 '22 at 17:31
  • 1
    It is almost always the case that a value cannot be exactly converted. It's not unusual but expected. – Weather Vane Jul 17 '22 at 17:34
  • @WeatherVane my question is how does one spot this. I know that it is expected. – stht55 Jul 17 '22 at 17:35
  • 2
    Is this an [XY Problem](http://xyproblem.info/)? Floating point work is usually inherently inaccurate, by its nature. – Weather Vane Jul 17 '22 at 17:36
  • Floats have 23-bit accuracy, so your precision is 1 part in 8.3 million. – stark Jul 17 '22 at 17:37
  • 1
    Worth reading: [Is floating point math broken?](http://stackoverflow.com/questions/588004/is-floating-point-math-broken) and [Why Are Floating Point Numbers Inaccurate?](https://stackoverflow.com/questions/21895756/why-are-floating-point-numbers-inaccurate) and [Floating point comparison `a != 0.7`](https://stackoverflow.com/questions/6883306/floating-point-comparison-a-0-7) – David C. Rankin Jul 17 '22 at 17:38
  • I have to use single precision. rounding errors will be extremely amplified (procedure is not stable but cant be optimized) -> must catch rounding error and throw exception – stht55 Jul 17 '22 at 17:39
  • 1
    At best you will get 6 or 7 significant digits of accuracy from a `float` -- and there are some numbers within that range that cannot be represented exactly to begin with. Those problems with floating-point numbers are explained in the links above. So in your example, you have the problems inherent in floating-point numbers, and `"0000000000000001"` too many digits that will never be represented. – David C. Rankin Jul 17 '22 at 17:42
  • 2
    If you are going to catch every inaccurate value, it's going to be most of them. Of the infinite range of values, fewer than 2³² of them can be exactly represented. – Weather Vane Jul 17 '22 at 17:47
  • If you are really concerned with inaccuracy, you should first decide on a numerical limit (greater than zero) for how much inaccuracy is OK (under the limit) how much is not OK (over the limit). If instead you're really concerned about the string representation of your output, let us know. – Dan Getz Jul 17 '22 at 17:51
  • stht55, `FLT_MIN` is _exactly_ 0.000000000000000000000000000000000000011754943508222875079687365372222456778186655567720875215087517062784172594547271728515625. Would you want to throw an exception if the string was "0.000000000000000000000000000000000000011754943508222875079687365372222456778186655567720875215087517062784172594547271728515625001"`? – chux - Reinstate Monica Jul 17 '22 at 20:55

1 Answers1

2

How does one catch this precision loss?

One doesn't, at least not with anything in the standard library; none of the strto* conversion functions will tell you if the value cannot be represented exactly.

Edit

I know that's not terribly helpful, but it means you'll have to go outside anything in the standard library. You'll either have to write your own conversion routines that somehow keep track of precision loss (I have no idea how you would implement this), or you'll have to go with some arbitrary-precision library like GMP, or you'll have to implement your own version of binary-coded decimal and hand-hack your own API to assign, compare, and manipulate BCD values.

C just doesn't give you the tools needed to do that kind of analysis.

John Bode
  • 119,563
  • 19
  • 122
  • 198
  • Especially considering "1.1" would be one such value! – Dan Getz Jul 17 '22 at 18:13
  • interesting, thank you. Seems like the loss of precision when doing such operations is not a big enough problem. – stht55 Jul 17 '22 at 20:48
  • @stht55: That's the downside of single-precision binary floating point - it can only represent 2^32 distinct values (-ish; not all bit patterns are valid value representations), and you only get about 7 decimal digits of precision. Double precision gives you 2^64 values and 10 digits of precision. If you need more than that, you have to use something beyond native types and standard library routines. – John Bode Jul 17 '22 at 22:34