Closed Bug 5856 (js-ieee-double-hurts) Opened 25 years ago Closed 25 years ago

javascript rounding bug

Categories

(Core :: JavaScript Engine, defect, P3)

defect

Tracking

()

VERIFIED INVALID

People

(Reporter: AriB, Assigned: norrisboyd)

References

()

Details

Just to give one example
14.28 x 9 should be 128.52;
your browser's answer = 128.51999999999998

This bug is also from Netscape 4.5
Status: NEW → RESOLVED
Closed: 25 years ago
Resolution: --- → INVALID
ECMAScript requires the use of IEEE double precision for numbers.

14.28 correctly rounded as an IEEE double is represented as

1.1100100011110101110000101000111101011100001010001111e3 in base 2, which is

exactly equal to 14.2799999999999993605115378159098327159881591796875 decimal.

Multiplying this value by 9 yields exactly

128.5199999999999942446038403431884944438934326171875.

Per the ECMA spec, this is again rounded to the nearest IEEE double, which is

1.0000000100001010001111010111000010100011110101110000e7 base 2, or

128.51999999999998181010596454143524169921875 decimal.



Why does the result print as 128.51999999999998?  Well, the ECMA spec requires

numbers to be printed with sufficient precision (and no more than that precision)

so that if the printed string were read in again and converted back to a number,

it would round to exactly the same IEEE double that was printed.  Printing 128.52

would be incorrect because the rounding 128.52 to the closest IEEE double yields

128.520000000000010231815394945442676544189453125, which is closer than

128.51999999999998181010596454143524169921875.  Thus we must print

128.51999999999998.

Every other language that uses standard IEEE double-precision arithmetic will

also give this result.  This includes Java and most implementations of C and C++.
Changing component to "Javascript Engine".  "Javascript" component is being
retired.
Status: RESOLVED → VERIFIED
Verified Invalid
*** Bug 251585 has been marked as a duplicate of this bug. ***
Note that ECMA-262 Edition 3 added Number.prototype.toFixed, which takes a
precision argument telling how many digits after the decimal point to show.  Use
this method well and you won't mind the disparity between finite precision base
2 and the "arbitrary" or "appropriate" precision base 10 that we use every day.

/be
*** Bug 281659 has been marked as a duplicate of this bug. ***
*** Bug 20140 has been marked as a duplicate of this bug. ***
*** Bug 1813 has been marked as a duplicate of this bug. ***
*** Bug 283303 has been marked as a duplicate of this bug. ***
*** Bug 297361 has been marked as a duplicate of this bug. ***
*** Bug 320093 has been marked as a duplicate of this bug. ***
*** Bug 356566 has been marked as a duplicate of this bug. ***
Alias: js-ieee-double-hurts
OS: Windows 98 → All
Hardware: PC → All
Duplicate of the Bug: 15* 1.33 (instead of expected 19.95 it return 19.950000000000003)
(37 + Math.pow(2, -1) + Math.pow(2, -3) + Math.pow(2, -5)) * 1e-32
3.7656250000000003e-31
in my string to number converter, it comes out without the 0000000003 error amount.
at least into the console.
reopen this bug?
by the way, the representation of the mantissa is best represented in binary form (base 2). so that's what I have done. even successive adds above have not deterred my converter from coming out with the right result. does the debugger contain an old/defective IEEE in its JS engine? I don't know if it uses its own JS engine or whether it uses the browser's. to me it's only important to get right results. this should come out 
this should come out 
(37 + Math.pow(2, -1) + Math.pow(2, -3) + Math.pow(2, -5)) * 1e-32
3.765625e-31
but came out 
(37 + Math.pow(2, -1) + Math.pow(2, -3) + Math.pow(2, -5)) * 1e-32
3.7656250000000003e-31
in the 54.0.1 console.
same problem with:

$('.chnagenumber').val()--> "3" 
$('.chnagenumber').val()*0.0001 --->"0.00030000000000000003"


my dirty solution:

alert(((0.0001*3)*1000000000000)/1000000000000); it display 0.0003 correcty
https://en.wikipedia.org/wiki/IEEE_754

11 mar 2019 4:56 pm edt:
(1)to Waldemar Horwat's comment:
'Every other language that uses standard IEEE double-precision arithmetic will
also give this result. This includes Java and most implementations of C and C++.'

now c produce better result:
//math_test.c
//compile-command:gcc -o math_test math_test.c
#include <stdio.h>
int main ()
{
/* javascript-eval-result,javascript-standard-arithmetic-result:
(1)defect:2.9+2.8=5.699999999999999
(2)defect:2.9-2.8=0.10000000000000009
(3)defect:2.9-2=0.8999999999999999
(4)not defect:2.9X2=5.8
(5)defect:2.9X2.3=6.669999999999999
(6)not defect:2.8/1.4=2
(7)not defect:2.8/4=0.7
(7)not defect:2.8/3=0.9333333333333332
/
printf("2.9+2.8=%f",2.9+2.8); // 2.9+2.8=5.700000
printf("\n2.9-2.8=%f",2.9-2.8); // 2.9-2.8=0.100000
printf("\n2.9-2=%f",2.9-2); // 2.9-2=0.900000
printf("\n2.9x2=%f",2.9
2); // 2.9x2=5.800000
printf("\n2.9x2.3=%f",2.9*2.3); // 2.9x2.3=6.670000
printf("\n2.8/1.4=%f",2.8/1.4); // 2.8/1.4=2.000000
printf("\n2.8/4=%f",2.8/4); // 2.8/4=0.700000
printf("\n2.8/3=%f",2.8/3); // 2.8/3=0.933333
printf("\n");

return 1;
}

(2)to brendan eich's comment 'Note that ECMA-262 Edition 3 added Number.prototype.toFixed, which takes a
precision argument telling how many digits after the decimal point to show. Use
this method well':
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed
from google(Number.prototype.toFixed)result 1
will also round-up result for 2.8/3=0.9333333333333332=0.9.
if that result remain 0.9333333333333332 then that's better because:
linuxmint-18.2->gnu-calculator says:
0.9333333333333332 x 3 = 2.8
0.9 x 3 = 2.7
0.93 x 3 = 2.79.

a javascript-htm-test-file:
<!--- defect_eval.htm:
(1)https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval from google(javascript evalulate math)
should contain warning about this eval-defect:
(2)mozilla should write warning about simple-arithmetic-defect
like in page
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval
should contain warning saying 'tips:did you know that
in javascript 2.9-2.8 = 0.10000000000000009.please make your own
subtraction-function,addition-function,multiplication-function'
-->

<script language="javascript">
//simple-arithmetic-defect
document.writeln('simple-arithmetic-defect');
document.writeln('<br>(1)defect:2.9+2.8='+(2.9+2.8)); // 5.699999999999999 <-- defect
document.writeln('<br>(2)defect:2.9-2.8='+(2.9-2.8)); // 0.10000000000000009 <-- defect
document.writeln('<br>(3)defect:2.9-2='+(2.9-2)); // 0.8999999999999999 <-- defect
document.writeln('<br>(4)not defect:2.9X2='+(2.92)); // 5.8 <-- not defect
document.writeln('<br>(5)defect:2.9X2.3='+(2.9
2.3)); // 6.669999999999999 <-- defect
document.writeln('<br>(6)not defect:2.8/1.4='+(2.8/1.4)); // 2 <-- not defect
document.writeln('<br>(7)not defect:2.8/4='+(2.8/4)); // 0.7 <-- not defect
document.writeln('<br>(7)not defect:2.8/3='+(2.8/3)); // 0.9333333333333332 <-- not defect

//eval-defect
document.writeln('<br><br>eval-defect');
document.writeln('<br>(1)defect:2.9+2.8='+eval(2.9+2.8)); // 5.699999999999999 <-- defect
document.writeln('<br>(2)defect:2.9-2.8='+eval(2.9-2.8)); // 0.10000000000000009 <-- defect
document.writeln('<br>(3)defect:2.9-2='+eval(2.9-2)); // 0.8999999999999999 <-- defect
document.writeln('<br>(4)not defect:2.9X2='+eval(2.92)); // 5.8 <-- not defect
document.writeln('<br>(5)defect:2.9X2.3='+eval(2.9
2.3)); // 6.669999999999999 <-- defect
document.writeln('<br>(6)not defect:2.8/1.4='+eval(2.8/1.4)); // 2 <-- not defect
document.writeln('<br>(7)not defect:2.8/4='+eval(2.8/4)); // 0.7 <-- not defect
document.writeln('<br>(7)not defect:2.8/3='+eval(2.8/3)); // 0.9333333333333332 <-- not defect
</script>

(In reply to arnon81 from comment #46)

11 mar 2019 4:56 pm edt:
(1)to Waldemar Horwat's comment:
'Every other language that uses standard IEEE double-precision arithmetic will
also give this result. This includes Java and most implementations of C and C++.'

now c produce better result:
//math_test.c
//compile-command:gcc -o math_test math_test.c
#include <stdio.h>
int main ()
{
/* javascript-eval-result,javascript-simple-arithmetic-result:
(1)defect:2.9+2.8=5.699999999999999
(2)defect:2.9-2.8=0.10000000000000009
(3)defect:2.9-2=0.8999999999999999
(4)not defect:2.9X2=5.8
(5)defect:2.9X2.3=6.669999999999999
(6)not defect:2.8/1.4=2
(7)not defect:2.8/4=0.7
(7)not defect:2.8/3=0.9333333333333332
/
printf("2.9+2.8=%f",2.9+2.8); // 2.9+2.8=5.700000
printf("\n2.9-2.8=%f",2.9-2.8); // 2.9-2.8=0.100000
printf("\n2.9-2=%f",2.9-2); // 2.9-2=0.900000
printf("\n2.9x2=%f",2.9
2); // 2.9x2=5.800000
printf("\n2.9x2.3=%f",2.9*2.3); // 2.9x2.3=6.670000
printf("\n2.8/1.4=%f",2.8/1.4); // 2.8/1.4=2.000000
printf("\n2.8/4=%f",2.8/4); // 2.8/4=0.700000
printf("\n2.8/3=%f",2.8/3); // 2.8/3=0.933333
printf("\n");

return 1;
}

(2)to brendan eich's comment 'Note that ECMA-262 Edition 3 added Number.prototype.toFixed, which takes a
precision argument telling how many digits after the decimal point to show. Use
this method well':
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed
from google(Number.prototype.toFixed)result 1
will also round-up result for 2.8/3=0.9333333333333332=0.9.
if that result remain 0.9333333333333332 then that's better because:
linuxmint-18.2->gnu-calculator says:
0.9333333333333332 x 3 = 2.8
0.9 x 3 = 2.7
0.93 x 3 = 2.79.

a javascript-htm-test-file:
<!--- defect_eval.htm:
(1)https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval from google(javascript evalulate math)
should contain warning about this eval-defect:
(2)mozilla should write warning about simple-arithmetic-defect
like in page
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval
should contain warning saying 'tips:did you know that
in javascript 2.9-2.8 = 0.10000000000000009.please make your own
subtraction-function,addition-function,multiplication-function'
-->

<script language="javascript">
//simple-arithmetic-defect
document.writeln('simple-arithmetic-defect');
document.writeln('<br>(1)defect:2.9+2.8='+(2.9+2.8)); // 5.699999999999999 <-- defect
document.writeln('<br>(2)defect:2.9-2.8='+(2.9-2.8)); // 0.10000000000000009 <-- defect
document.writeln('<br>(3)defect:2.9-2='+(2.9-2)); // 0.8999999999999999 <-- defect
document.writeln('<br>(4)not defect:2.9X2='+(2.92)); // 5.8 <-- not defect
document.writeln('<br>(5)defect:2.9X2.3='+(2.9
2.3)); // 6.669999999999999 <-- defect
document.writeln('<br>(6)not defect:2.8/1.4='+(2.8/1.4)); // 2 <-- not defect
document.writeln('<br>(7)not defect:2.8/4='+(2.8/4)); // 0.7 <-- not defect
document.writeln('<br>(7)not defect:2.8/3='+(2.8/3)); // 0.9333333333333332 <-- not defect

//eval-defect
document.writeln('<br><br>eval-defect');
document.writeln('<br>(1)defect:2.9+2.8='+eval(2.9+2.8)); // 5.699999999999999 <-- defect
document.writeln('<br>(2)defect:2.9-2.8='+eval(2.9-2.8)); // 0.10000000000000009 <-- defect
document.writeln('<br>(3)defect:2.9-2='+eval(2.9-2)); // 0.8999999999999999 <-- defect
document.writeln('<br>(4)not defect:2.9X2='+eval(2.92)); // 5.8 <-- not defect
document.writeln('<br>(5)defect:2.9X2.3='+eval(2.9
2.3)); // 6.669999999999999 <-- defect
document.writeln('<br>(6)not defect:2.8/1.4='+eval(2.8/1.4)); // 2 <-- not defect
document.writeln('<br>(7)not defect:2.8/4='+eval(2.8/4)); // 0.7 <-- not defect
document.writeln('<br>(7)not defect:2.8/3='+eval(2.8/3)); // 0.9333333333333332 <-- not defect
</script>

addition 11 mar 2019 5:33 pm edt--------------
#reword# /* javascript-eval-result,javascript-standard-arithmetic-result:
#to# /* javascript-eval-result,javascript-simple-arithmetic-result:
i write this addition by clicking 'reply to this comment' on an icon located right-side of my comment.

http://wortel.ucoz.com/calculator.htm#17_apr_2019_6_29_pm_edt
maybe has correct-arithmetic,function division may produce many decimal-digit if those decimal-digit are all different not repetitive.
arithmetic-code is located in
find '//start math-arithmetic-function','//end math-arithmetic-function'

You need to log in before you can comment on or make changes to this bug.