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 (deleted) —
Attached file Testcase 2 (deleted) —
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 (deleted) —
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: