Closed Bug 42134 Opened 24 years ago Closed 24 years ago

JavaScript should be more lenient comparing (==) floats

Categories

(Core :: JavaScript Engine, defect, P3)

defect

Tracking

()

VERIFIED INVALID

People

(Reporter: shashi, Assigned: rogerl)

Details

Attachments

(3 files)

The summary I have given does not give an accurate picture of what I am seeing.
I have created two test cases that illustrate the problem so let me upload them
first and then give you the blow-by-blow details.
Attached file Testcase 1
Attached file Testcase 2
Testcase #1 - In this document, I have the following JS code:

function MoveText1(start, finish, step, speed){
if (start < finish){      	
document.getElementById("text1").style.left = start+"px";
start=start+step;
setTimeout("MoveText1("+start+","+finish+","+step+","+speed+")",speed);
}
if (start == 150) {
document.getElementById("text2").style.visibility = "visible";
}
}

This code is started via <body onLoad="MoveText1(0,250,10,5)">. Of key issue is
the second "if" statement. When start hits 150, I want a layer to become
visible. When the testcase is viewed, everything works the way it should.

Testcase #2 - In this document, the JS looks like this:

function FadeText1(start, finish, step, speed){
if (start < finish){      	
document.getElementById("text1").style.opacity = start;
start=start+step;
setTimeout("FadeText1("+start+","+finish+","+step+","+speed+")",speed);
}
if (start == 0.33) {
document.getElementById("text2").style.visibility = "visible";
}
}
<body onLoad="FadeText1(0.00,0.99,0.03,1)">

As the second "if" states, when start hits 0.33 a layer should become visible.
Viewing the testcase, you will see that *nothing* happens when the target number
is reached.

The two JS functions are identical in structure so it seems strange that it
works in one instance and not another. It looks to me like it comes down to that
"start" number...for some reason Mozilla can't handle decimals...yet it is able
to perform the fade routine without problems using those same decimals. Strange
indeed.
Here are the values that JavaScript is getting for start on each succesive
call to FadeText1():

0
0.03
0.06
0.09
0.12
0.15
0.18
0.21
0.24
0.27
0.30000000000000004
0.33000000000000007 <---- Uh oh!
0.3600000000000001
So it looks like that the JavaScript floating point equality operator is
being too sensitive: the difference between the target value (0.33) and the
actual value (diff=7e-17) is about two ten-quadrillionths of the target
value.

If you replace

if (start == 0.33)

with

if ((start > 0.32999999) && (start < 0.3300001))

then Testcase 2 works fine.

Confirming on Linux build 2000060908; someone should mark this for all
platofrms. Also, someone should change the summary.
Status: UNCONFIRMED → NEW
Ever confirmed: true
Changing to all/all per Matt Cline's comments.  Lowering severity to normal, 
because critical is reserved for things like crashes.

In C/C++, it's the programmer's responsibility to use tolerances instead of == 
to compare floating-point values.  It would make sense for the JavaScript spec 
to say exactly how floats should work in order to guarantee that something that 
works on one platform would work on another, but I don't know if it does or not.
Severity: critical → normal
OS: Windows 98 → All
Hardware: PC → All
Summary: JavaScript is unable to deal with certain arguments → JavaScript should be more lenient comparing (==) floats
Are there any browsers that *do* give a match?  I couldn't figure out how to 
test all of the browsers I have using the second testcase (only mozilla did 
anything at all), but based on another testcase that doesn't use settimeout or 
divs, it seems that all browsers are handling the floating-point part in the 
same way.  shashi@narain.com, have you tested this on other browsers?
Attached file another testcase
This is in reply to what Matthew Cline wrote on 2000-06-10 20:55 ---

Excellent catch on the values being passed to JavaScript :-)

>So it looks like that the JavaScript floating point equality operator is
>being too sensitive.

I don't think this is the problem. If I use the equality opertor, it means that 
I am expecting a *specific* number and this is born out of how I structured my 
JS code. I made very sure that 0.33 *will* be reached. But as your value 
analysis clearly shows, Moz never hits 0.33
This is in reply yo what Jesse Ruderman wrote on 2000-06-10 22:05 ---

>have you tested this on other browsers?

Before uploading, I ran my two test cases through IE5. The first TC worked fine 
but the second did not because I used the SVG opacity property which is not 
supported in IE5.

Your test case was alot better at getting to the essence of this bug. I agree 
with you that it has something to do with the floating-point. The additions used 
in my JS code are simple...start at 0.00 and keep adding 0.03 until you get to 
0.99. Everything works fine from 0.00 to 0.27 but at this point something 
bizarre happens. Adding 0.03, any 6th grader will tell you that the answer is 
0.30. Moz believes it is 0.30000000000000004...has some new mathmetical concept 
been introduced that I am unaware of :-)

To make things even funnier, using the erroneous value of 0.30000000000000004 
and adding 0.03 to it, Moz gives out 0.33000000000000007 which is also wrong!!! 
Out of curiosity, I ran Jesse's test case in IE5 and it gives the *same* numbers 
as Moz does.

In all seriousness, what is going on here??? How did such simple mathmatics 
become so complex??? The bottom line is 0.27 + 0.03 = 0.30 not some number 
running 17 decimal places long. The implications of this bug are rather far 
reaching and affect alot of things.
It's been two weeks since my last comment and nothing seems to have happened
with this bug (it's still "new" and unassigned). Just writing in to check and
see if this bug has not fallen through the cracks.
Sorry for the delay - taking over QA for the JavaScript Engine group -
I'll try to get an answer for you as soon as possible!
Hi Shashi,

I discussed this issue with all the engineers on the JavaScript Engine team.
They informed me that this issue occurs because JavaScript conforms to the 
ISO standard 16262 (ECMAScript) and the ANSI/IEEE standard 754. 

Your "step" increment is 0.03, which does not have an exact binary 
representation. Therefore any loops done with this increment value
will eventually incur errors. The behavior of JavaScript is to maintain
as exact a numerical representation as possible at each stage of an 
arithmetical operation, and not arbitrarily discard any digits.

I'm afraid I have to mark this bug as invalid. Please see bug 20140,
which deals with the same issue (also marked invalid), and which has 
a more complete explanation -

Again, sorry for the delay -
Status: NEW → RESOLVED
Closed: 24 years ago
Resolution: --- → INVALID
Phil --

No apologies neccessary :-) I took a look at bug 20140 and now understand what 
is happening here. I fully agree with you that this "bug" is invalid.

In the last comment posted on 20140, waldmer@netscape.com said:

"In JS1.5 you can use Number.toFixed to round the answer to the number of 
decimal places you desire."

This will work absolutely perfectly!!! Just to make sure...will Moz be 
supporting JS1.5???

Yes, that is correct: Moz is currently based on JavaScript 1.5
Marking Verified Invalid -
Status: RESOLVED → VERIFIED
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: