On Mon, 19 Mar 2012 09:29:34 +0100, Timon Gehr <timon.g...@gmx.ch> wrote:
The current limitations make it impossible to define (for example) a floating point type with NaN that behaves like built-in float/double/real.
As it turns out, this is possible. opCmp can return a float, and things work just fine (!<, !>=, etc). The problem appears with opEquals. This is the generated assembly: fldz fucompp fnstsw ax sahf jne <somewhere> So it compares the result to 0.0, copies status flags to the CPU, then checks if any of the flags are set. If the returned value *is* equal to 0.0, the C3 flag is set. The result is that the jump is taken only when the returned value is *less* than 0.0. I have a feeling this is wrong. Should I file this in BugZilla? Anyways. With this newly-won knowledge, we can design an opEquals that returns a float, and behaves correctly (until the above bug [if I'm right] is fixed): struct MyInt { int n; float opEquals(MyInt other) const { if (n == int.min || other.n == int.min) { return float.nan; } return n == other.n ? -1.0 : 1.0; // Note workaround. //return n - other.n; // Should work. } float opCmp(MyInt other) const { if (n == int.min || other.n == int.min) { return float.nan; } return n - other.n; } } unittest { assert( MyInt(int.min) != MyInt(int.min) ); assert( MyInt(0) == MyInt(0) ); assert( MyInt(int.min) !< MyInt(0) ); assert( MyInt(int.min) !> MyInt(0) ); assert( MyInt(int.min) !<= MyInt(0) ); assert( MyInt(int.min) !>= MyInt(0) ); assert( MyInt(0) !< MyInt(int.min) ); assert( MyInt(0) !> MyInt(int.min) ); assert( MyInt(0) !<= MyInt(int.min) ); assert( MyInt(0) !>= MyInt(int.min) ); assert( MyInt(1) > MyInt(0) ); assert( MyInt(1) >= MyInt(0) ); assert( MyInt(0) < MyInt(1) ); assert( MyInt(0) <= MyInt(1) ); }