Welcome! Please see the About page for a little more info on how this works.

+1 vote
in ClojureCLR by

I encountered this possible bug while running a property-based test suite in a ClojureCLR project. Given a comparison between NaN in an if expression, it seemingly takes the wrong branch.

Clojure (CLR)

λ cljr
Clojure core loaded in 837 milliseconds.
Starting main
Clojure core loaded in 409 milliseconds.
Clojure 1.12.2
user=> (<= ##NaN ##NaN)
false
user=> (if (<= ##NaN ##NaN) true false)
true
user=> (let [t (<= ##NaN ##NaN)] (if t true false))
false

user=> (>= ##NaN ##NaN)
false
user=> (if (>= ##NaN ##NaN) true false)
true
user=> (let [t (>= ##NaN ##NaN)] (if t true false))
false

I wasn't able to replicate the issue on Clojure (JVM), C#, or F#.

Clojure (JVM)

λ clj
Clojure 1.12.0
user=> (<= ##NaN ##NaN)
false
user=> (if (<= ##NaN ##NaN) true false)
false
user=> (let [t (<= ##NaN ##NaN)] (if t true false))
false

C#

using System;
					
public class Program
{
	public static void Main()
	{
		Console.WriteLine(Double.NaN <= Double.NaN);
		if (Double.NaN <= Double.NaN) {
			Console.WriteLine(true);
		} else {
			Console.WriteLine(false);
		}
		var t = Double.NaN <= Double.NaN;
		if (t) {
			Console.WriteLine(true);
		} else {
			Console.WriteLine(false);
		}
	}
}

False
False
False

F#

λ dotnet fsi

> nan <= nan;;                                                                
val it: bool = false

> if (nan <= nan) then true else false;;                          
val it: bool = false

> let t = nan <= nan;;
val t: bool = false

> if t then true else false;;
val it: bool = false

1 Answer

+1 vote
ago by

It's definitely a bug. Will be fixed in the next release. (I'll have a new alpha out this week, but plan to do a GA release toward the end of the week.)

For those who like details:

It's a bug that only occurs when calling a one of <, <=, >, >= on two arguments in a context where both arguments have known types and the types are both double, and the context of the call is the test in a conditional. So only when we have something like (if (<= ^double x ^double y) ... ). And the generated code gives an incorrect answer only when one or both of the arguments is NaN.

Why? (Asks no one.)

Both the ClojureJVM and ClojureCLR compilers detect calls to numeric comparison operators as the test of a conditional and replace a static method call with an equivalent sequence of direct bytecode/MSIL instructions. The ClojureCLR code copied the comparator code for integer arguments when doing the double, which involved a negation. For integers, the negation of a <= is >. That is not true for doubles, when an argument is NaN. Brain cramp.

...