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) );
}

Reply via email to