Tr : double a%b returns NaN for some (a,b) (|a| < inf, |b|>0)

Joseph Darcy joe.darcy at oracle.com
Tue Feb 12 14:20:22 PST 2013


Hello,

A quick note below,


On 2/12/2013 10:34 AM, Jeff Hain wrote:
>
> Vladimir wrote:
>> First, could you show what java versions you tried (java -version)? And what OS you are using?
>
> On Windows 7/Core i7 980X, it happens with the following 64 bits versions of Java:
> - 1.5.0_22-b03
> - 1.6.0_21-ea-b05
> - 1.6.0_29-ea-b08 (and also crashes at some point but this version seems to crash a lot, so might be unrelated)
> - 1.6.0_38-b05 ("Java HotSpot(TM) 64-Bit Server VM")
> but not with:
> - 1.7.0_11-b21
> - 1.8.0-ea-b73
>
>
> On Windows XP/T2300, it does not happen with:
> - 1.6.0_38
> - 1.6.0_39
> - 1.7.0_10
>
>
>
>> Second, could you try to run with -Xint? It will run in Interpreter mode only without JIT compilation.
> Still happens.
>
>
>
>> Third, run only Client (-client) or Server (-server) VM. It will use different JIT compilers.
>> Note, that there is no Client 64bit VM. If you have latest jdk7update (7u10 or 7u12) or jdk8 you can specify next flags to use only Client's JIT compiler: -XX:+TieredCompilation -XX:TieredStopAtLevel=1.
> Only using 64 bits VMs.
>
>
>
> Here is some code that can reproduce the problem,
> and the output I get whether it happens or not:
>
>
>
> public class ModNaN {
>      /* Windows 7/Core i7 980X/1.6.0_38 (64):
> NaNs
> 8.98846567431158E307 % 1.295163E-318 = NaN
> 1.7976931348623157E308 % 2.59032E-318 = NaN
> 1.7976931348623157E308 % 1.060997895E-314 = NaN
> 1.7976931348623157E308 % 6.767486E-317 = NaN
> 1.7976931348623157E308 % 7.528725E-318 = NaN
> non-NaNs
> 8.98846567431158E307 % 1.29516E-318 = 2.53E-321
> 1.7976931348623157E308 % 2.590327E-318 = 0.0
> 1.7976931348623157E308 % 1.060965516E-314 = 9.35818525E-315
>       */
>      /* Windows 7/Core i7 980X/1.7.0_11 (64):
> NaNs
> 8.98846567431158E307 % 1.295163E-318 = 0.0
> 1.7976931348623157E308 % 2.59032E-318 = 2.57135E-318
> 1.7976931348623157E308 % 1.060997895E-314 = 5.31535078E-315
> 1.7976931348623157E308 % 6.767486E-317 = 1.142612E-317
> 1.7976931348623157E308 % 7.528725E-318 = 4.64634E-318
> non-NaNs
> 8.98846567431158E307 % 1.29516E-318 = 2.53E-321
> 1.7976931348623157E308 % 2.590327E-318 = 0.0
> 1.7976931348623157E308 % 1.060965516E-314 = 9.35818525E-315
>       */
>      public static void main(String[] args) {
>          System.out.println("NaNs");
>          for (double[] ab : new double[][]{
>                  new double[]{Double.longBitsToDouble(0x7FE0000000000000L),Double.longBitsToDouble(0x0000000000040000L)},
>                  new double[]{Double.longBitsToDouble(0x7FEFFFFFFFFFFFFFL),Double.longBitsToDouble(0x000000000007FFFFL)},
>                  //
>                  new double[]{Double.longBitsToDouble(0x7FEFFFFFFFFFFFFFL),Double.longBitsToDouble(0x000000007FFFFFFFL)},
>                  new double[]{Double.longBitsToDouble(0x7FEFFFFFFFFFFFFFL),6.767486E-317},
>                  new double[]{Double.longBitsToDouble(0x7FEFFFFFFFFFFFFFL),7.528725E-318},
>          }) {
>              double a = ab[0];
>              double b = ab[1];
>              double mod = a % b;
>              System.out.println(a+" % "+b+" = "+mod);
>          }
>
>          System.out.println("non-NaNs");
>          for (double[] ab : new double[][]{
>                  new double[]{Double.longBitsToDouble(0x7FE0000000000000L),Double.longBitsToDouble(0x000000000003FFFFL)},
>                  new double[]{Double.longBitsToDouble(0x7FEFFFFFFFFFFFFFL),Double.longBitsToDouble(0x0000000000080000L)},
>                  //
>                  new double[]{Double.longBitsToDouble(0x7FEFFFFFFFFFFFFFL),Double.longBitsToDouble(0x000000007FFEFFFFL)},
>          }) {
>              double a = ab[0];
>              double b = ab[1];
>              double mod = a % b;
>              System.out.println(a+" % "+b+" = "+mod);
>          }
>      }
> }

For the non-NaN floating-point values, I recommend using hexadecimal 
floating-point syntax rather than calling Double.longBitsToDouble on a 
hex string value; see Double.toHexString for details.  And to be clear, 
the value of the basic arithmetic operations are fully defined by the 
Java Language Specification in this case so there shouldn't be a 
difference across platforms, but you can add the "strictfp" modifier to 
remove one source of possible variance.

-Joe


More information about the hotspot-dev mailing list