Math.IEEERemainder() not implemented?

200 views
Skip to first unread message

Ray Cromwell

unread,
Mar 17, 2008, 4:54:46 PM3/17/08
to google-web-toolkit-contributors

I just implemented some logic that needs this function, and I noticed it's not implemented. When I looked at the JRE emul source, it claims NYI because JS doesn't support it, but I tried the built in '%' operator in FF, IE6, and Safari, and it returns the correct answer to more digits of precision that I need, so is this an oversight, or is there some edge case where the '%' operator won't work.

For example, 2.47 % 1.2 returns 0.070000... on FF, Safari, and IE6. It is also the return value of Math.IEEERemainder(2.47, 1.2) on JDK5 (tested).

For now, I'll use a JSNI function, but if this does work, it would be nice to see it go into 1.4.62 and 1.5.

-Ray

Ray Cromwell

unread,
Mar 17, 2008, 5:08:15 PM3/17/08
to Google Web Toolkit Contributors

Oh, maybe 1.4.62/3 is not possible (didn't exist then), but for 1.5 it
looks implementable.

-Ray

Scott Blum

unread,
Mar 18, 2008, 11:53:33 AM3/18/08
to Google-Web-Tool...@googlegroups.com, Lex Spoon, Freeland Abbott
Ray: got a patch and test case?  I'm sure Freeland or Lex would be happy to review.

Lex Spoon

unread,
Mar 18, 2008, 1:56:00 PM3/18/08
to Google-Web-Tool...@googlegroups.com
Before getting into it, might I ask if % will work for you?  Java and JavaScript both support % on floats, and GWT will convert a Java % to a JavaScript %.

In more detail, % and IEEERemainder are different, so they need different implementations.  There is some discussion of the difference within the Java spec:

The result of a floating-point remainder operation as computed by the % operator is not the same as that produced by the remainder operation defined by IEEE 754. The IEEE 754 remainder operation computes the remainder from a rounding division, not a truncating division, and so its behavior is not analogous to that of the usual integer remainder operator. Instead, the Java programming language defines % on floating-point operations to behave in a manner analogous to that of the integer remainder operator; this may be compared with the C library function fmod. The IEEE 754 remainder operation may be computed by the library routine Math.IEEEremainder.
-- http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.17.3

As a quick example, "5.0 % 6.0" is 5.0, which is analogous to the integer computation "5 % 6".  To contrast, IEEERemainder(5.0, 6.0) is -1.  The first answer corresponds to "5 = 6*0+1".  The second corresponds to "5  6*1+(-1)".  When determining the third number in these equations (0 vs. 1), one operation truncates while the other one rounds off.

 
All this said, IEEERemainder can probably be implemented in GWT.  Probably it suffices to do a % and then check the sign of the result compared to the expected sign given the arguments.  The difference compared to % sounds obscure to me, though, so if we can deprioritize it that would be nice.

-Lex


Ray Cromwell

unread,
Mar 18, 2008, 3:30:45 PM3/18/08
to Google-Web-Tool...@googlegroups.com

Lex, it turns out I don't need the IEEERemainder semantics, and my initial test cases in Javascript were all passing because none of them depended on actual correct IEEE remainder semantics. I've ported some code that used IEEERemainder, and I didn't look to see if it really needed it. (I wasn't really aware of the different between that and %/fmod) So let's deprioritize this for now. I started working on an implementation and some test cases, but I'll table them for now. I've looked at the implementations in fdlibm and GNU Classpath StrictMath, and there's some funky John Carmack-Fast-Inverse-Square-Root-like methods in those libs that I don't completely understand how they work.

It seems like some of the methods, like getExponent() could also be implemented. For example, given a value d, e=Math.floor(Math.log(d)/Math.log(2)) will return an exponent near the correct value. You can then iterate e until d < Math.pow(2,e). Handling denormalized values may present a tricky problem, which may or may not be solvable to perfection, but I think GWT developers may not be looking for IEEE754 perfection. We've lived a long time with a non-compliant 'long' (I know, fixed in 1.5 thanks to Scott), but perhaps we can live with non-perfect implementations of 1.5/1.6 Math functions until more emulation code is written.

Anyway, enclosed is a patch to the EmulSuite that tests the IEEEremainder() function. It passes on JDK1.5, but the last test fails on GWT if IEEEremainder() is implemented as "return f1 % f2;"

If others of the GWT team are interested, I could do an actual implementation like fdlibm's, but otherwise, shelve it for later.

-Ray
MathTest_ieeeremainder.patch

Ray Cromwell

unread,
Mar 18, 2008, 4:39:31 PM3/18/08
to Google-Web-Tool...@googlegroups.com

BTW Lex,
  here is a patch to implement of getExponent() along with some unit tests. It also includes a 'stub' IEEEremainder() implementation using modulo.

-Ray
ieeeremainder-and-getexponent-impltest.patch

Ray Cromwell

unread,
Mar 18, 2008, 5:13:21 PM3/18/08
to Google-Web-Tool...@googlegroups.com

Lex,
  Just playing around with some sample code and comparing it to the real IEEEremainder results, I think I've come up with a function that correctly implements IEEEremainder() using '%',
can anyone spot the flaw?

public static double IEEEremainder(double f1, double f2) {
   double r = f1 % f2;
   if(Double.isNaN(r) || r == f2 || r <= f2 / 2.0) {
      return r;
   }
   else {
      return r - f2;
   }
}

  Essentially, if the remainder is greater than half the modulus, what happens with the real IEEEremainder function is that it wants to bump the quotient by +1.

As an example. 8.2 % 3.2 returns = 1.799999. That's because 8.2 can be written as 3.2 * q + r = 8.2, where q=2, and r = 1.799999. That is, 3.2 evenly divides 6.4 2 times.  But
IEEEremainder prefers q=3, r=-1.4000000000, or, 3.2 divides 9.6 with a remainder of -1.40000, we get 8.4.

As we can see, 8.2 is closer to 9.6 than to 6.4, so IEEEremainder would prefer that the numerator is 'rounded up' to 9.6, but another way to look at it is whether the remainder is greater than 1/2 the modulus. If so, it means that the numerator is closest to the next higher multiple of the modulus.

Thus, we simple check if (f1 % f2) > f2 / 2. If so, we pretend that the q=q+1, and recompute r.

If you think that this logic is right, I will go ahead and resubmit another patch, with implementations of both IEEEremainder and getExpontent.

-Ray

Ray Cromwell

unread,
Mar 18, 2008, 5:30:13 PM3/18/08
to Google-Web-Tool...@googlegroups.com

Opps, I just noticed I've got to handle signs, here's a fixed version


public static double IEEEremainder(double f1, double f2) {
   double r = Math.abs(f1 % f2);
   if(Double.isNaN(r) || r == f2 || r <= Math.abs(f2) / 2.0) {
      return r;
   }
   else {
      return Math.signum(f1) * (r - f2);
   }
}

-Ray
Reply all
Reply to author
Forward
0 new messages