2

The javadoc for Math.rint says: "If the argument is NaN or an infinity or positive zero or negative zero, then the result is the same as the argument." However, the following is false:

public static void main(String[] args) throws Throwable {
    double nan = Double.NaN;
    System.out.println(Double.doubleToRawLongBits(-nan) == Double.doubleToRawLongBits(Math.rint(-nan)));
}

I am writing a compiler and I need the bits on NaN preserved. Is this a bug in the docs or in the runtime? Or does "same" not mean the same to me as it does in Java?

I assume I have to Double.isNaN before the rint call and actually keep the same arguments to preserve my compiler's semantics.

EDIT: This is not a duplicate of this question. My question is about the javadoc and/or the JVM being wrong in its rint implementation, that one is about whether something is cross platform. Please do not mark the question as duplicate just because both deal w/ alternate forms of NaN on the JVM.

Community
  • 1
  • 1
Chad Retz
  • 1,241
  • 2
  • 14
  • 16
  • @Pshemo, the OP isn't doing `==` on two NaNs, they're doing `==` on two `long`s. – Louis Wasserman Mar 30 '17 at 22:26
  • @LouisWasserman My bad. Deleted. – Pshemo Mar 30 '17 at 22:26
  • My understanding is that there are multiple bit patterns that can represent `NaN`, so `Double.doubleToRawLongBits(Double.NaN)` isn't well-defined. I may be wrong. – Dawood ibn Kareem Mar 30 '17 at 22:29
  • 1
    Definitely there are many possible outputs on NaNs and that's what the OP is running into. I would be moderately surprised if there were anything that could be done about this, and if Java cared about the exact NaN that got returned. – Louis Wasserman Mar 30 '17 at 22:31
  • Just read the Javadoc and some of the code, and I was wrong. It looks like `Double.doubleToRawLongBits(Double.NaN)` is well defined but `Double.doubleToRawLongBits(-Double.NaN)` isn't. – Dawood ibn Kareem Mar 30 '17 at 23:05
  • @DavidWallace - Can you link to where it says it's not well defined? Or do you mean by its omission of -NaN? There are many other NaN values too. The method is very clear in why it exists and its handling of NaN. (Also, `-Double.NaN` won't work because of how the compiler inlines it, you have to `DNEG` it at runtime). – Chad Retz Mar 31 '17 at 13:04
  • 1
    I believe that even if you add an `if (Double.isNaN(x)) return x;` check, there's still no guarantee of preserving exactly the same NaN bits, at least for signalling NaNs, which are finicky like that. I'd be curious to see what the maintainers would say if you reported the `Math.rint` behavior here as a bug, but I suspect they would treat it, at best, as a documentation issue. – Boann Mar 31 '17 at 13:20
  • 1
    @Boann - Empirically I have confirmed that it does preserve the bits on eager return like that (and what I am having my compiler do). I think you are right that the maintainers will just fix the docs to be like `Math.abs` and say they return `NaN` instead of the exact argument. – Chad Retz Mar 31 '17 at 13:43
  • Bug opened at http://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8177950. Sadly they're not paying attention and are just dismissing whilst trying to teach me about NaN. – Chad Retz Apr 03 '17 at 06:01
  • Better link to the bug there: https://bugs.openjdk.java.net/browse/JDK-8177950?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel. I don't agree with the closure because it could be an easy doc fix, but I've submitted various Java bugs and learned that such subtle issues are not a priority, for better or worse. – Boann Apr 05 '17 at 00:05

0 Answers0