39
Problem
Test there in the consoles of your browsers:
1067.11-1000 = 67.1099999999999
The right thing would be 67.11
- Could someone explain this to me?
- And how do I fix it?
39
Test there in the consoles of your browsers:
1067.11-1000 = 67.1099999999999
The right thing would be 67.11
58
This occurs because of an inaccuracy in converting the value 1067.11 to the representation of the number in memory... this inaccuracy, which is revealed to the subtract the value 1000.
Numerical inaccuracies occur by a variety of factors, arising from the way in which such numbers are represented by the computer.
Numbers with floating point, in modern systems are usually
represented in accordance with the standard
IEEE 754 native way. Javascript specifically, uses the double
to represent all numbers.
In the case of double
of the standard IEEE 754, inaccuracies are caused by
two factors:
Amount of space to represent the number is finite. In the current case, this limitation is not what causes the imprecision.
Exponent numerical basis is 2, which cannot be aligned with the base of the
original number 1067.11
which is at base 10. This is the cause of
inaccuracy in the current case.
To better understand we have to see how exactly the type is represented double
.
double
The double
of the standard IEEE 754 is formed as follows:
signal: 1 bit for signal
exponent: 11 bit integer, to indicate the value of the displaced exponent 1023 units, or one of the two values with special meanings: 0x000 for subnormal and zero values; 0x7FF to represent infinity and Nan. (i.e. 2x - 1023, where x is the whole value of the field)
mantissa: 52 bits, for normal exponent values, represents a value
rational ranging from 1.0 inclusive to 2.0 exclusive, mathematically [1, 2[
.
For the exponent value 0x000, then represents subnormal values (i.e.
smaller than the smallest representative normal value) or zero; for the value of
exponent 0x7FF represents infinity if it is 0, or Nan if it is different from 0.
Although it doesn’t seem so, number 1067.11 cannot be represented exactly by javascript. So how can javascript convert that number back to string, just like "1067.11"?
alert(1067.11); // vai mostrar "1067.11", como é possível então?
This is because the javascript implementation is smart... at the time of
convert to string, shows the value shorter which would be representable by
this value of double
.
This happens because a single value of double
results from several conversions of
string for double:
1067.1100000000000000000001
1067.11000000000000001
1067.11000000000001
1067.11
1067.10999999999978626875
1067.1099999999997862687453
1067.10999999999978626874509
1067.1099999999998999553285190717
When writing any of the above numbers on Chrome console, the result is
1067.11
... because this is the shortest string.
But the truth is you’re being duped!
The exact value of the string "1067.11" converted to double
is 1067.1099999999998999553285190717
.
The exact value minus 1000 is 67.1099999999998999553285190717
.
The shortest value representable by the previous double is 67.1099999999999
.
Completion:
1067.11 - 1000 == 67.1099999999999
é **EXATAMENTE** o mesmo que
1067.1099999999998999553285190717 - 1000 == 67.1099999999998999553285190717
That is to say:
O que realmente acontece na memória => O que é mostrado para você
1067.1099999999998999553285190717 => 1067.11
- 1000 => - 1000
--------------------------------- ------------------
67.1099999999998999553285190717 => 67.1099999999999
References
My sources of information and learning:
27
Source: http://www.guj.com.br/8905-problemas-no-calculo-com-javascript
The reason for this is this:.
The computer does not work well with decimals. As you know, the data is represented internally in binary format.
The number 4, for example, is represented by the computer thus:
100 (onde 1x2^2 + 0x2^1 + 0x2^0 = 4)
How is a number with decimal places represented? The number becomes inaccurate because, after the comma, each connected bit represents 2 -n, where n is the number of the house counted from right to left, starting from 1. Thus, the number 2.5 would be represented in binary by:
2 = 10
0,5 = 0.1
2,5 = 10.1
Now, consider the effort to write a fraction that is not multiple of 2, like 0.3, using powers of 2:
The first power we would use could be 1/4, which is 0.25. To improve accuracy, we can add 1/32, which is 0.03125. We would then get, 0.28125. What if we wanted to increase the accuracy even more? You’d add up to 1/64, which is 0.015625, and you’d get 0.296875... Our number already looks like this: 0.3 = 0.010011
We could continue adding multiple divisors of 2 larger and larger, but we would hardly reach 0.3. This asymptotic behavior is extremely inconvenient and, for a base like 2, extremely frequent.
With this, we see that the base system 2 is very poor to represent numbers that cannot be obtained by fractions of 2. And from this comes all this imprecision. What the computer does is increase (a lot) the number of bits when accounts involving floats are done. This attenuates the problem, but does not solve it. Small programming tips (like multiplying before splitting, when possible) also help.
However, it is often not enough. Java (but not Javascript) provides classes (Bigdecimal and Biginteger) for you to manipulate arbitrary precision numbers. In this case, the calculations are done indirectly, and are much slower compared to the primitive way. But still, they break a gallon.
This explains their odd number. It’s not a Javascript bug, it’s the way computers work. The same problem will repeat itself in all programming languages.
Nesse caso, os cálculos são feitos por software(...)
That sounds so weird.
Good, this question and answer were missing from the site. I just think it would be worth mentioning some more "bureaucratic" issues, such as the use of the IEEE 754 standard in js.
One more thing: the answer would be more accurate if you indicated that in Javascript, there is a single numeric type (Number
). This type stores values as floating points. It stores not integer values, but power values. Therefore, any calculation is based on approximations. Bonus if you cite the functions that allow you to round up results like the one in the example to force the nearest integer to be used.
An excellent reference on the subject for those who read English: http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
"The same problem will repeat itself in all programming languages." I disagree with your position. This is a question of how each language treats numerical data and not a problem of how the computer stores numbers and stuff and stuff.
@Edgarmunizberlinck this is a problem of how the computer stores numbers, not the language. It is mathematically impossible to represent all real numbers with binary numbers.
@carloscinelli still does not justify the argument of "all languages". Java Bigdecimal for example has no loss of precision. Anyway, precision problems usually occur when we have numbers on different scales of accuracy, so it is not a computer problem but lack of modesty of the developer when performing its operations.
@Edgarmunizberlinck the need to create a library/packet of arbitrary precision stems from the fact that computers store information in binary form, it is not something of logic or syntax or the language itself. With these libraries you increase the accuracy of the real numbers on computers, but you can’t represent them exactly ever.
@Edgarmunizberlinck Actually, the Java Bigdecimal varies in behavior. If you use the constructor that receives a double it also operates internally in a "wrong" way, itself javadoc guides this. The same occurs in the method Bigdecimal#valueOf(double).
14
I think the first part of the question is already well answered.. :)
As for the second, in Javascript you can format your number in fixed-point using the method Number.prototype.toFixed()
The method receives a parameter indicating the number of digits:
(1067.11-1000).toFixed(2);
in this case, the result will be the string "67.11"
.
To explicitly work with it again as a number:
resultado = Number( (1067.11 - 1000).toFixed(2) );
Good, it worked out ;)
Everyone explained, but the only one who solved it was you, thanks
Browser other questions tagged javascript mathematics floating-point
You are not signed in. Login or sign up in order to post.
The added answers are already quite complete, so I won’t post one more. But if you want to read more about it and understand why comma operations can be "tricky" and should be used with care, I suggest this article: http://hal.archives-ouvertes.fr/docs/00/28/14/PDF/floating-point-article.pdf
– easuter
I made a reply showing exactly what is happening in the computer memory, to make it clear what is happening. I hope it helps!
– Miguel Angelo
If you want even more details, I could also show how the conversion is done between double/string... I think I just needed this to close the answer I gave.
– Miguel Angelo
@Miguelangelo This conversion could be shown here: https://answall.com/q/264529/3082
– Paulo Roberto Rosa