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