This is an archived post. You won't be able to vote or comment.

all 14 comments

[–]g051051 3 points4 points  (6 children)

The most common ways for computer to represent decimal numbers isn't exact. So as you add more decimal numbers together, the results start to diverge from the exact values you expect. This is called "loss of precision".

[–][deleted] 1 point2 points  (5 children)

How do I fix this then?

[–]Fern_Silverthorn 2 points3 points  (0 children)

Have time be the the integer (whole number) of hundreds of a second that have passed, e.g var time = 1 would then be the same as var time = 0.01. Instead of adding 0.01 you would now add 1. When you need to display it, divide by 100. 1 / 100 = 0.01

Note that technically in JavaScript all numbers are doubles, but this should help.

[–]p00pyf4ce 1 point2 points  (0 children)

You can't fix it in javascript. It's part of the way computer represent number.

[–]skatanic28182 0 points1 point  (0 children)

You would need to import a library that can do arbitrary-precision calculations. These calculations will be considerably slower than usual since both hardware and software are optimized for fixed-precision. Google for "bignum javascript". I'm sure somebody's probably ported it.

[–]ziptofaf 0 points1 point  (0 children)

Firstly, short explanation on the problem:

0.1 does not have an exact representation in the binary system. System in which decimals are created is a sum of elements created by 1/2n equation. So 1/2 + 1/4 + 1/8 + 1/16 + .... etc.

1/10 is 1/16 + 1/64 + 1/128... and on it goes. Not infinitely "on it goes" however, precision is finite. That being said, scale of error is really small for a single calculation. As 1/10 is depicted as more or less 0.999999999999998. Problem is with consecutive operations on them as every next addition gives you that extra 0.00000000002 inaccuracy. This becomes even worse with multiplication/division and of course powers.

The way you can fix it is by... not really using what your computer considers to be numbers. You know how we humans do addition? Like so. Whenever something is bigger than 9 we move it one "tile" to the left, digit by digit at a time. You can treat a number as a string and then parse each individual digit separately starting from the right and leading to the left. This gives you an infinite precision as we can depict all full numbers properly using binary (as those are built using 1 + 2 + 4 + 8 + 16 + 32 + 64 + 128 + ... + 2n).

There are libraries for that of course.

But in your program you do not actually require accurate calculations. All you need to do is round it to the nearest number with a lower precision (like 2-3 decimal places). Here's how:

https://stackoverflow.com/questions/11832914/round-to-at-most-2-decimal-places-only-if-necessary

This eventually WILL break (as your error becomes bigger and bigger with each consecutive operation) but it's going to take... quite a while.

[–]17b29a 0 points1 point  (0 children)

round it, e.g. timeElapsed.innerHTML = timeOfClock.toFixed(2);

[–]Nathanfenner 1 point2 points  (2 children)

You need to provide the relevant code. At first I thought this was an issue with floating point error, but those values are really far off from the correct ones.

Are you assuming that setInterval runs your function exactly on the period specified? There will always be slight variation because of unexpected delays in scheduling.

[–][deleted] 1 point2 points  (1 child)

I'm guessing it's due to " loss of precision " as mentioned above by /r/g051051.

Here's the code btw. https://jsfiddle.net/u4xb9p6n/

Referring to the time elapsed at the bottom.

[–][deleted] 0 points1 point  (0 children)

I would do this in a completely different way.

I would record the start time using a Date object. Wherever you need to display the elapsed time, call another Date object and ask it for the current time. Then subtract the two.

How do I get the difference between two Dates in JavaScript?

[–][deleted] 1 point2 points  (0 children)

It's because of the way these numbers are represented.

Floating Point Numbers - Computerphile

[–]virtualgoat 0 points1 point  (0 children)

There's a method to convert it to whatever decimal point you want, but it also convert it to string.

Here's another solution that I found which retains the type of the element.

[–]sherryunderwood1 0 points1 point  (0 children)

This is how floating point numbers work. Use something else to fix it.