Closed Bug 264912 Opened 20 years ago Closed 15 years ago

Javascript arithmetic is incorrect under Linux/x86 due to extended precision

Categories

(Core :: JavaScript Engine, defect)

x86
Linux
defect
Not set
normal

Tracking

()

RESOLVED WORKSFORME

People

(Reporter: vincent-moz, Unassigned)

References

()

Details

Attachments

(2 files, 2 obsolete files)

User-Agent:       Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a5) Gecko/20041018
Build Identifier: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a5) Gecko/20041018

The Javascript specification requires that the compuations are performed using
the IEEE-754 double-precision arithmetic (with exact rounding to the nearest);
see Section 8.5 (The Number Type). The example shown at the above URL doesn't
work under Linux/x86. Here's the Javascript source:

var x, y, z, d;
x = 9007199254740994; // 2^53 + 2
y = 1 - 1/65536;
z = x + y;
d = z - x;
document.write(d);

It should write 0, but under Linux/x86, it writes 2. This can be explained by
the fact that with the traditional x86 FPU (i.e. when SSE2 is not used), the FPU
is configured by default to round results in extended precision under Linux. The
solution would be to configure the traditional x86 FPU in double-precision
rounding when Mozilla is started (at the right place -- perhaps not too early).
My page (above URL) gives information about this problem; see also S. W.
Whiteley's article (link on my page). There could still be problems related to
the overflows (however, this would be less important).

Reproducible: Always
Steps to Reproduce:
1. Open http://www.vinc17.org/research/extended.en.html#bugs-js
Actual Results:  
I get: "Test of the Javascript arithmetic of your browser: 2. The number 0 is
the correct result. [...]"


Expected Results:  
I should have got: "Test of the Javascript arithmetic of your browser: 0. The
number 0 is the correct result. [...]"


I don't know if many applications are affected by this bug. If some of them use
algorithms based on exact rounding (such as the ones to perform multiple
precision based on floating-point instead of integer arithmetic), they may fail.

Also, I have not tried builtin XSLT, but it could have the same problem, with
the same global fix.
Depends on: 109286
Vincent Lefevre, why you didn't try to make some kind of patch ?

I'm interesed in this, but now have no time to dig into src and
to study theory. I plan to make this on summer.
I don't know what file I should modify and I don't have the time at the moment
to learn Mozilla's internals.
As usual comments say all, but nobody reads it:
<http://lxr.mozilla.org/mozilla/source/js/src/jsdtoa.c>
This file says: "On a machine with IEEE extended-precision registers, it is
necessary to specify double-precision (53-bit) rounding precision before
invoking strtod or dtoa." This is correct but not sufficient. Setting double
precision permanently would be the best solution IMHO, hoping that there would
be no bad side effects (some users said that this could affect the libm, but I
do not know any example). There's more discussion on
http://www.srware.com/linux_numerics.txt (which I've linked from my page) and an
example to configure the FPU in double precision, using <fpu_control.h>.
(In reply to comment #4)
> This file says: "On a machine with IEEE extended-precision registers, it is
> necessary to specify double-precision (53-bit) rounding precision before
> invoking strtod or dtoa." This is correct but not sufficient. Setting double
> precision permanently would be the best solution IMHO, hoping that there would
> be no bad side effects (some users said that this could affect the libm, but I
> do not know any example). There's more discussion on
> http://www.srware.com/linux_numerics.txt (which I've linked from my page) and
> an example to configure the FPU in double precision, using <fpu_control.h>.

I read that link and others from your's web-site before any searching in src ;D
It's very interesting point of glibc developer mr. Drepper.

So, any side effects with "libm" may be checked with some tests.
Also i think that "glibc" doesn't reset fpu on every math operation,
thus permanent setting fpu in some header file, f.e

<http://lxr.mozilla.org/mozilla/source/js/src/jslibmath.h>
 72 #elif defined(linux)
 73 #define JS_USE_FDLIBM_MATH 1
 74                                 <here
 75 #elif defined(OSF1)

would be enough. "Setting" in header file - it is some FLAG, and in source.c
file - it will be some function, that will be run, if flag is defined. Maybe
some other libc will want to have extended but not double precision by default.
So GNU+Linux....

In past days i've read _manu_ on floating point, mainly intel's one.
And may be not in 95% of programmers that do not know it.
Referenced here <http://www.cs.berkeley.edu/~wkahan/JAVAhurt.pdf> by author
of IEEE 754.

Now about floating point arithmetic. Start was lame, so i correct it.

1. Please follow
     <http://sourceware.org/ml/libc-alpha/2001-08/msg00242.html>
   this thread in glibc mailing list for more info about
     <http://www.srware.com/linux_numerics.txt> and friends.

   "If you rely on rounding use the appropriate function.  Use round()
   instead of a cast to int.  The latter is required to truncate, the
   former, as the name suggests, rounds.  And yes, round() is a standard
   function."
     -- <http://sourceware.org/ml/libc-alpha/2001-08/msg00243.html>
     <http://sourceware.org/ml/libc-alpha/2001-08/msg00247.html>
   Cast double to int is stupid, after i read ISO/IEC 9899:1999 on
   this topic, now i see. Implementation defined behaviour, period.

2. On Intel x87 read this link:
     <http://webster.cs.ucr.edu/AoA/Linux/HTML/MoreDataRepresentation.html>
   after "Figure 4.4 80-bit Extended Precision Floating Point Format"
   REM: in reply to me author told me, that all info is from Intel IA-32
   manuals this copy of Pentium docs:
     <http://webster.cs.ucr.edu/Page_TechDocs/index.html>
   Intel's:
     <http://developer.intel.com/design/pentium4/manuals/253668.htm>
   Only one thing i couldn't find in Intel docs is:
    "Intel provided native 64 bit operations on the Pentium to better
    compete against the RISC chips."
    author of webster didn't reply to me, when i asked for pointing
    me to manuals on this topic. Maybe i'll try glibc mailing-list.

3. Mozillka.
   JS uses SUN's math fdlibm on linux, why ?
   GLIBC has very good x87 optimized libm. Maybe that's why fdlibm is
   double precise, glibc is extended precise.
   So why mozilla doesn't swith x87 FPU into double precision mode ?
     <http://lxr.mozilla.org/mozilla/source/js/src/jslibmath.h>:
     <code>
         72 #elif defined(linux)
         73 #define JS_USE_FDLIBM_MATH 1
     </code>
   glibc says on:
    
<http://sources.redhat.com/cgi-bin/cvsweb.cgi/~checkout~/libc/sysdeps/i386/fpu_control.h?rev=1.11.2.1&content-type=text/plain&cvsroot=glibc>
   or simply
     <$PATH/sysdeps/i386/fpu_control.h>:
     <code>
         /* precision control */
         #define _FPU_EXTENDED 0x300     /* libm requires double extended
precision.  */
         ...
         /* The fdlibm code requires strict IEEE double precision arithmetic,
            and no interrupts for exceptions, rounding to nearest.  */

         #define _FPU_DEFAULT  0x037f
     </code>

4. If ECMAScript says double precision, it's just says to use C's double type,
   but not long double for final results.

So, guys mozilla is wrong. Some decision is needed what to do in sources, thus
patches will be useful.
Result on testcase:
<http://flower.upol.cz/~olecom/bugs/m-264912_fpu/original-test-on_vinc17.org.png>

If somebody wants to check it, but cann't build mozilla, here's library
(it works on my system)
<http://flower.upol.cz/~olecom/bugs/m-264912_fpu/libmozjs.so>
Due to changes in JS in 17 of May this library will not work on latest builds
for sure.
(In reply to comment #2)
On <http://www.vinc17.org/research/extended.en.html> i saw many (but not manu ;)
links to Debian BTS, maybe we should make them to know this too ?

Also, i would like to do mozilla's JS code more glibc friendly, this task
is for summer for sure. But i don't know if mozilla hackers are willing to
accept this. Making this will prevent all GNU compatibility issues, maybe
even with GNU/Hurd.

--
Small one. Maybe it will be useful as start.

On my site there's also patch for mm1.7.8/ff1.0.4
from Debian's sources and some tests links.
Attachment #183883 - Attachment is obsolete: true
With this one, bug maybe closed.

Btw, fdlibm is _very_ outdated, if anybody cares, i can fill new
bugreport.

Also, please don't shoot me, i couldn't look on that gotos (i'm hiding ;)
<http://www.acm.org/classics/oct95/>
Attachment #184101 - Attachment is obsolete: true
-> default qa
QA Contact: pschwartau → general
(In reply to comment #10)
> Created an attachment (id=184298) [details]
> Common FPU setup interface, setup for linux, cleaning build, and some gotos
> 
> With this one, bug maybe closed.
> 
> Btw, fdlibm is _very_ outdated, if anybody cares, i can fill new
> bugreport.

I think you shouldn't change the breaks into a do {} while(0); it clutters your patch and has no link whatsoever with the present bug. Also, please don't gzip your patch.
This works for me using - Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.3a1pre) Gecko/20091222 Minefield/3.7a1pre

and

Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2b6pre) Gecko/20091222 Namoroka/3.6b6pre

The broken behavior is present on Gecko 1.9.1.
Status: UNCONFIRMED → RESOLVED
Closed: 15 years ago
Resolution: --- → WORKSFORME
Note that the behavior may depend on compiler options (I wonder whether some platforms use SSE2 by default, for which the behavior is correct). So, I'd like to know more about the builds: Did you build these versions yourself, and under the same conditions?
I tested with builds from the Mozilla ftp, latest-mozilla-central, latest-mozilla-1.9.2 and Firefox 3.5.6 also downloaded from Mozilla.
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: