atof() precision

Pages: 12
you have to handle it, somehow, yourself or if you can find a library (does boost have a scientific double manager section?).

there really are only 3 choices.
1) use integers, and float the point yourself.
2) use the biggest double your system supports, and wrap everything in cleanup/rounding/error correction post processing.
3) use a high precision double (or integer) N bit class that is slow but can do big precision work. A mix of 3 and 1 ... using a big-integer class... seems solid to me.

3 'kicks the can down the road'. It fixes nothing, you just get more sig digits to play with. You may still need to apply #2 to #3 solutions.
2 fixes the problem, but it costs you -- every double operation that was 1-2 clock cycles is going to become 10+ clocks. If the simulation is big, it will suffer some speed. 1) fixes the problem via integer truncation BUT YOU MAY also have to use 2 to round it if you want that instead.
Last edited on
@jlb

Those "garbage digits" are always significant.

But not in the mathematical sense? Because I was just explained that double precision has only 15 to 16 significant digits?



Yes, you calculated a value of 4499.10000000000036 which is different than 4499 so if you do your subtraction you will be left with the fractional part, .10000000000036

The set_precision() function doesn't affect the actual number stored in memory, it just alters the display of that number. The value held in memory is not "magically" altered by set_precision(), the value in memory is really 4499.1000 0000 0000 36 or thereabouts. Floating point math is inherently imprecise having much more than just "round off" problems.


Ok, let me recapitulate:
When using double precision numbers, you can only trust 15-16 digits.
If I see a number like 4499.10000000000036, I know that the number I should take is actually 4499.1000... (I round away the insignificant 36). However, the computer internally still represents the number with the 36 and this has nothing to do with set_precision(). I only make it show me more digits that are being stored.
Since the computer internally works with these mathematically insignificant digits, they can become significant digits after 'unlucky' calculations and I will be left with a mathematically wrong result.


@jonnin
Thanks for the 3 ways. I will think about it.
Last edited on
But not in the mathematical sense?

Who is talking about mathematical sense? You have to deal with the limitations of the computer in this case, if you want the computer to compute your value.

I know that the number I should take is actually 4499.1000... (I round away the insignificant 36).

How do you "know" that the value should be 4499.1...?

Have you manually calculated the value?

How are you trying to round away those "insignificant" values?

Jim
Why do values on the order of 10^-12 or smaller have any substantial effects on the result of your algorithm? Do you really need your quantities to span fifteen orders of magnitude?

Probably not. The issue is most likely that you're accumulating error over time.

Any electronics hobbyist can tell you that the solution to these problems is not (usually) to choose super high-precision components. Rather, it's best to build your circuits to give a reasonable result in the presence of bad components with wide tolerances.

In software-speak, you should choose an algorithm that is more tolerant of those errors (i.e., not just rounding error, but of measurement error). If this is possible (and I suspect it is) that would be the preferred solution, before looking for more precise math.

For example, sums can be made more accurate with William Kahan's algorithm:
https://en.wikipedia.org/wiki/Kahan_summation_algorithm
Last edited on

jlb wrote:

How do you "know" that the value should be 4499.1...?

Because I was told double precision has 15-16 significant digits. Or is that wrong now?
Have you manually calculated the value?

I gave the exact result in my earlier post.

How are you trying to round away those "insignificant" values?

Round down from digits <5, round up from digits >=5.


@mbozzi
I need to understand exactly how this floating point arithmetic works.
My program deals with particles and 'hard walls'. These walls have a beginning and an end coordinate. My particles have known positions and velocities, so I can calculate the intersection of their trajectories with said walls. If I have a point of intersection, I move my particle there. The particle, however, must never move beyond a wall. Due to the numerical inaccuracies of double precision arithmetic, it happens that the particle gets moved a little bit too far. If I have to deal with stuff like this, I need to know exactly what the computer does with its floating point numbers.

Anyway, it's also about understanding. I want to understand what's going on. I am not satisfied with merely accepting and trying to run away from the problem.
What is happening on the inside with the double precision numbers?
What is the significance of these final digits that are outside of the 15-16 digits space?

Sometimes, if I have two doubles that onle differ at the 17th digit, the computer thinks they are the same if I test with "if(a==b)" or "cout<<a-b;" (gives either 0 or not).
Other times, it still sees a difference. Yet I cannot find a rule to that, it looks completely random to me.
What is happening on the inside with the double precision numbers?

If that paper doesn't help, see also
https://floating-point-gui.de/
and Wikipedia:
https://en.wikipedia.org/wiki/Floating-point_arithmetic

If you want an exercise, consider implementing a C++ class that implements a mini-float: an 8-bit floating point number.

What is the significance of these final digits that are outside of the 15-16 digits space?

The "garbage" at the end is not garbage, but the actual decimal representation of the floating point value, as is required by at least three of the relevant standards, save that the last digit is rounded in an implementation-defined manner (probably the IEEE754 default half-to-even).

Recall that as a binary format the exact value of a floating point number is expressed as a sum of powers of two, hence why the end looks like trash in decimal.
The double that is nearest to 4399.1 has the exact value 4399.10000000000036379788070917129516601562500...00...00...
It's a disservice to talk about "exact values" and then examine an incomplete decimal representation. Start thinking in hexadecimal:
4399.10000000000036379788070917129516601562500...00...00... == 0x1.12f199999999ap+12

Sometimes, if I have two doubles that only differ at the 17th digit, the computer thinks they are the same if I test with "if(a==b)" or "cout<<a-b;" (gives either 0 or not).


When you specify a double, you get one of the closest two representable values (often the nearest). This is why modifying a 17th digit may or may or may not result in a different value: the chosen representation may or may not differ.
Last edited on
Thank you mbozzi!
I have also found this source and started to work through it:
https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
You think it's good?
There, I was just introduced to the concept of "guard digits". I assume they are still being used to protect against rounding errors?
edit: I just saw that this article was also supported by one of your links.

Recall that as a binary format the exact value of a floating point number is expressed as a sum of powers of two, hence why the end looks like trash in decimal.
The double that is nearest to 4399.1 has the exact value 4399.10000000000036379788070917129516601562500...00...00...

Ahh! So these 'strange digits' in the end are because my entered double cannot be represented accurately in a binary system (within the given precision)? And when I print it out with too many digits, I see the result of the back conversion from that inaccurate binary representation to my decimal system?
Last edited on
I have also found this source and started to work through it:
https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
You think it's good?

It seems just fine to me.

Ahh! So these 'strange digits' in the end are because my entered double cannot be represented accurately in a binary system (within the given precision)? And when I print it out with too many digits, I see the result of the back conversion from that inaccurate binary representation to my decimal system?

Yes!
Last edited on
Thank you, it helped a lot.

Meanwhile, I have figured out that my system is indeed a "deterministic chaotic system", meaning that small deviations in starting conditions can grow exponentially over the course of the simulation.
In other words, rounding errors can grow exponentially over the course of my simulation...

I am just reading material on this.
Topic archived. No new replies allowed.
Pages: 12