[gwt-contrib] RR:Double.doubleToLongBits/Double.longBitsToDouble patch

3 views
Skip to first unread message

Ray Cromwell

unread,
Mar 24, 2008, 5:02:59 PM3/24/08
to Google-Web-Tool...@googlegroups.com, Lex Spoon

Damn, forgot to attach it:

-Ray

On Mon, Mar 24, 2008 at 2:00 PM, Ray Cromwell <cromw...@gmail.com> wrote:


Freeland,
  Here is a revised version of the patch,  abstracted to work with arbitrary bit sites (you could cut/paste this code into Float to get a similar implementation). All former magic constants are now constant identifiers. I fixed some checkstyle issues, some bugs (mentioned in last post), and added extensive documentation so that what it's doing can be followed line by line for verification.

  One thing I was not able to do was to make the MAX_EXPONENT / MIN_EXPONENT constants dependent upon my code because gwt's checkstyle rules force private static fields to come after public, and that would create an illegal forward reference, otherwise, MAX_EXPONENT could be (1L << EXPONENT_BITSIZE) - 1 - EXPONENT_BIAS - 1 (e.g. 2048 - 1 - 1023 - 1 = 1023, a value of 1024 is reserved for NaN/Infinity). Note: If this patch is approved, then I will be submitting a patch to Math.java which includes a working getExponent() method which could also be used (e.g. getExponent(MAX_VALUE) )

  I did not update the tests yet, because I want to lock down the implementation first, then I'll go add extensive permutations.

-Ray

On Fri, Mar 21, 2008 at 1:58 PM, Freeland Abbott <gwt.team...@gmail.com> wrote:
(Patched in at r2201, if it matters for line numberings...)

Style question, I at least prefer capital "L" to indicate long constants, as lowercase 'l' looks like 1... does GWT code insist one way or the other?

doubleToLongBits,
  • l.56, the "special cases" tests should be together... in particular, the test for Infinity should be near the test for NaN, and before the (irrelevant to that case) call to Math.abs().
  • l.82, what's the "&& guess > 1024" clause for?  I get that we're checking whether our putative mantissa is too small (fractional) and we should ramp down the exponent to raise it to at least one, but where does the 1024 come from?  If the double is (fraction x 2^512), why wouldn't we want to adjust to (2*fraction x 2^256)?
  • generally, we probably want symbolics for most of the constants.  I know why most are there, but balked at 1024 and at 10231... oh, duh, that last is 1023L, and that's also where 1024 comes from.  But I shouldn't have had to figure that out. ;-)
longBitsToDouble,
  • name the input something other than 'l', for the same looks-like-a-1 reason I prefer constants ending in L,
  • l.134 typo "out" -> "our" ?
Otherwise, I'm pretty convinced.

  •  



On Wed, Mar 19, 2008 at 6:57 PM, Ray Cromwell <cromw...@gmail.com> wrote:

Opps, the test cases are misnamed and wrong (assertEquals on double comparisons), here's the fix.

-Ray


On Wed, Mar 19, 2008 at 3:41 PM, Ray Cromwell <cromw...@gmail.com> wrote:

Ask and ye shall receive... :)

Attached is the implementation of Double.doubleToLongBits and Double.longBitsToDouble, plus patch to DoubleTest.java to include tests against actual values returned from JDK1.6 execution of those methods.

-Ray


On Wed, Mar 19, 2008 at 2:15 PM, Bruce Johnson <br...@google.com> wrote:
That would rule. Time may be running short for GWT 1.5, but we'd be grateful for patches whether it makes it in or not.


On Wed, Mar 19, 2008 at 4:55 PM, Ray Cromwell <cromw...@gmail.com> wrote:

Now that the GWT compiler supports long types in 1.5 with 64 bit accuracy, is there any interest to have implementations of the following methods?

Double.doubleToLongBits()
Double.longBitsToDouble()
Math.getExponent()
Math.IEEEremainder()
Math.cbrt()
Math.ulp()
Math.nextAfter()
Math.nextUp()

I have reasonably efficient implementations of the first 4 functions (meaning not brute force loops) which are probably not bit-for-bit ulp-for-ulp correct vs x86 or fdlibm, but I haven't found a failure case yet. The first 2 enable the last 3 to be implemented easily. Of course, doubleToLongBits won't be as efficient as C (not are the emulated longs), but if you need 2-way reversible longbits->double functions, they might suffice.

Here is a sample implementation of doubleToLongBits(), it contains loops, but the initial guess gets the approximation within a factor of 10, so the loop will usually only a few iterations, usually 2. The implementations of
getExponent() and IEEEremainder() are efficient. Whether they are 100% correct remains to be seen, but they seem to be very good approximations.

-Ray


public static long doubleToLongBits(final double v) {
    if (Double.isNaN(v)) {
      // IEEE754, NaN exponent bits all 1s, and mantissa is non-zero
      return 0x0FFFl << 51;
    }

    long sign = (v < 0 ? 0x1l << 63 : 0);
    long exponent = 0;

    double absV = Math.abs(v);
    // IEEE754 infinite numbers, exponent all 1s, mantissa is 0
    if (Double.isInfinite(v)) {
      exponent = 0x07FFl << 52;
    } else {
      if (absV == 0.0) {
        // IEEE754, exponent is 0, mantissa is zero
        // we don't handle negative zero at the moment, it is treated as
        // positive zero
        exponent = 0l;
      } else {
        // get an approximation to the exponent
        int guess = (int) Math.floor(Math.log(absV) / Math.log(2));
        // force it to -1023, 1023 interval (<= -1023 = denorm/zero)
        guess = Math.max(-1023, Math.min(guess, 1023));
     
        // divide away exponent guess
        double exp = Math.pow(2, guess);
        absV = absV / exp;
       
        // while the number is still bigger than a normalized number
        // increment exponent guess
        while (absV > 2.0) {
          guess++;
          absV /= 2.0;
        }
        // if the number is smaller than a normalized number
        // decrement exponent
        while (absV < 1 && guess > 1024) {
          guess--;
          absV *= 2;
        }
        exponent = (guess + 1023l) << 52;
      }
    }
    // if denorm
    if (exponent <= 0) {
      absV /= 2;
    }

    // the input value has now been stripped of its exponent
    // and is in the range [0,2), we strip off the leading decimal
    // and use the remainer as a percentage of the significand value (2^52)
    long mantissa = (long)((absV % 1) * Math.pow(2, 52));
    return sign | exponent | (mantissa & 0xfffffffffffffl);
  }
















doubletolongbits_impl_and_test_fixed2.patch
Reply all
Reply to author
Forward
0 new messages