3

According to IEEE 754 NaN equal comparison with any number should be false (both Java and JavaScript languages). But in the following code, using javax scriptEngine for JavaScript, a variable set to NaN compared with itself returns true.

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

public class Main {

    public static void main(String[] args) throws ScriptException {
        final ScriptEngineManager mgr = new ScriptEngineManager();
        final ScriptEngine engine = mgr.getEngineByName("JavaScript");
        System.out.println("neq: " + engine.eval("a1 = NaN; a1!=a1;"));
        System.out.println("eq: " + engine.eval("a1 = NaN; a1==a1;"));
        System.out.println("nid: " + engine.eval("a1 = NaN; a1!==a1;"));
        System.out.println("id: " + engine.eval("a1 = NaN; a1===a1;"));
    }
}

Output :

neq: true
eq: true
nid: true
id: false

Using oracle JDK :

java version "1.8.0_60"
Java(TM) SE Runtime Environment (build 1.8.0_60-b27)
Java HotSpot(TM) 64-Bit Server VM (build 25.60-b23, mixed mode)

My understanding is the 'eq' expression should return false.

Why is a1 == a1 True instead of False when a1 is NaN ?

fleroux
  • 31
  • 3
  • [Why NaN === NaN is false?](https://stackoverflow.com/questions/19955898/why-nan-nan-is-false) – Andreas Oct 29 '15 at 12:21
  • 1
    In Java, [`Double.valueOf(Double.NaN).equals(Double.NaN)`](http://docs.oracle.com/javase/7/docs/api/java/lang/Double.html#equals%28java.lang.Object%29), but `!(Double.NaN == Double.NaN)`. I'm guessing JavaScript `==` for numbers maps to `.equals`. This looks like a bug in the script engine. – Mike Samuel Oct 29 '15 at 13:00

2 Answers2

2

Whatever causes this behavior seems to be a side-effect of the assignment or, more specific, of the reassignment (within the same script). I modified your test case to

final ScriptEngineManager mgr = new ScriptEngineManager();
ScriptEngine engine = mgr.getEngineByName("JavaScript");
System.out.println("neq: " + engine.eval("a1 = NaN; a1!=a1;"));
System.out.println("eq: " + engine.eval("a1 = NaN; a1==a1;"));
System.out.println();
engine = mgr.getEngineByName("JavaScript");
System.out.println("eq: " + engine.eval("a1 = NaN; a1==a1;"));
System.out.println("neq: " + engine.eval("a1 = NaN; a1!=a1;"));
System.out.println();
engine = mgr.getEngineByName("JavaScript");
engine.eval("a1 = NaN;");
System.out.println("neq: " + engine.eval("a1!=a1;"));
System.out.println("eq: " + engine.eval("a1==a1;"));
System.out.println();
engine = mgr.getEngineByName("JavaScript");
engine.eval("a1 = NaN;");
System.out.println("eq: " + engine.eval("a1==a1;"));
System.out.println("neq: " + engine.eval("a1!=a1;"));

and got:

neq: true
eq: true

eq: false
neq: false

neq: false
eq: true

eq: true
neq: false

So when a1 does not get reassigned within an engine, it exhibits a consistent (not necessarily correct) behavior, while with the reassignment, the result is not just wrong but entirely inconsistent.

Holger
  • 243,335
  • 30
  • 362
  • 661
  • 1
    Nice, this sounds like a bug of Nashorn here. I can't find anything related to this in the JDK bug tracker. – Tunaki Oct 29 '15 at 13:11
  • 1
    I did some more experiments and it gets even more confusing. It’s entirely unpredictable when it will exhibit which behavior. The only constant is that when it switches to a reproducible behavior, it’s the wrong one. I have the strong feeling that we have more than one bug here. – Holger Oct 29 '15 at 13:16
0

If I add this piece of code

    engine.eval("a1 = NaN;");
    System.out.println("eq: " + engine.eval("a1==a1;"));
    System.out.println("neq: " + engine.eval("a1!=a1;"));
    System.out.println();
    engine.eval("a1 = NaN;a2 = NaN");
    System.out.println("eq: " + engine.eval("a1==a2;"));
    System.out.println("neq: " + engine.eval("a1!=a2;"));
    System.out.println();

it shows that even without reassignment the result is inconsistent. I get:

eq: true neq: false

eq: false neq: true

  • Maybe it is just that the first call to eval() produces the right output, and starting from the second call it produces wrong output. This could explain why assigning in a separate call seems to produce consistent results. – Thierry Pauwels Oct 29 '15 at 17:20