Search code examples
javaieee-754

Cast long to double with non-default rounding mode


In Java, when a long value is cast to double value, the IEEE754 round-to-nearest rounding mode is applied when lossless conversion is not possible.

For example, cast from 1L << 55 or (1L << 55) + 8 to double are lossless. However, any number in between cannot be accurately represented as double. The IEEE-754 round-to-nearest (ties to even) rounding mode is applied by default. As a result, (1L << 55) + 4) or below will round down where as (1L << 55) + 5 or up will round up.

Is there any function in standard library or guava that allows me to cast a long to a double using Round toward +∞ or Round toward -∞ mode (chosen on a per-callsite basis)? Assuming there isn't one, how do I write such two functions myself efficiently?


Solution

  • How about this:

    static double longRoundUp(long lng)
    {
        double d = (double)lng;     
        return lng <= (long)d ? d : Math.nextUp(d);
    }
    
    static double longRoundDown(long lng)
    {
        double d = (double)lng;     
        return lng >= (long)d ? d : Math.nextDown(d);
    }
    

    Test:

    long l1 = (1L << 55);
    long l2 = (1L << 55) + 8;
    long l3 = (1L << 55) + 4;
    long l4 = (1L << 55) + 5;
    
    System.out.format("Up %d %.0f%n", l1, longRoundUp(l1));
    System.out.format("Up %d %.0f%n", l2, longRoundUp(l2));
    System.out.format("Up %d %.0f%n", l3, longRoundUp(l3));
    System.out.format("Up %d %.0f%n", l4, longRoundUp(l4));
    
    System.out.println();
    System.out.format("Down %d %.0f%n", l1, longRoundDown(l1));
    System.out.format("Down %d %.0f%n", l2, longRoundDown(l2));
    System.out.format("Down %d %.0f%n", l3, longRoundDown(l3));
    System.out.format("Down %d %.0f%n", l4, longRoundDown(l4));
    

    Output:

    Up 36028797018963968 36028797018963968
    Up 36028797018963976 36028797018963976
    Up 36028797018963972 36028797018963976
    Up 36028797018963973 36028797018963976
    
    Down 36028797018963968 36028797018963968
    Down 36028797018963976 36028797018963976
    Down 36028797018963972 36028797018963968
    Down 36028797018963973 36028797018963968