diff --git a/src/exact_value.cpp b/src/exact_value.cpp index 2f82a52cf..5c436fee6 100644 --- a/src/exact_value.cpp +++ b/src/exact_value.cpp @@ -1019,6 +1019,10 @@ gb_internal bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) f64 b = x.value_complex->imag; f64 c = y.value_complex->real; f64 d = y.value_complex->imag; + if (isnan(a) || isnan(b) || isnan(c) || isnan(d)) { + return op == Token_NotEq; + } + switch (op) { case Token_CmpEq: return cmp_f64(a, c) == 0 && cmp_f64(b, d) == 0; case Token_NotEq: return cmp_f64(a, c) != 0 || cmp_f64(b, d) != 0; @@ -1026,6 +1030,29 @@ gb_internal bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) break; } + case ExactValue_Quaternion: { + Quaternion256 a = *x.value_quaternion; + Quaternion256 b = *y.value_quaternion; + if (isnan(a.real) || isnan(a.imag) || isnan(a.jmag) || isnan(a.kmag) || + isnan(b.real) || isnan(b.imag) || isnan(b.jmag) || isnan(b.kmag)) { + return op == Token_NotEq; + } + + switch (op) { + case Token_CmpEq: + return cmp_f64(a.real, b.real) == 0 && + cmp_f64(a.imag, b.imag) == 0 && + cmp_f64(a.jmag, b.jmag) == 0 && + cmp_f64(a.kmag, b.kmag) == 0; + case Token_NotEq: + return cmp_f64(a.real, b.real) != 0 || + cmp_f64(a.imag, b.imag) != 0 || + cmp_f64(a.jmag, b.jmag) != 0 || + cmp_f64(a.kmag, b.kmag) != 0; + } + break; + } + case ExactValue_String: { String a = x.value_string; String b = y.value_string; diff --git a/tests/internal/test_quaternion_comparison.odin b/tests/internal/test_quaternion_comparison.odin new file mode 100644 index 000000000..93de83b8e --- /dev/null +++ b/tests/internal/test_quaternion_comparison.odin @@ -0,0 +1,130 @@ +package test_internal + +import "core:testing" + +// Each constant case is paired with the same comparison on variables: the folded answer +// has to be the answer the backend produces. + +@(test) +compare_constant_quaternions :: proc(t: ^testing.T) { + I :: quaternion128(0+1i+0j+0k) + J :: quaternion128(0+0i+1j+0k) + K :: quaternion128(0+0i+0j+1k) + R :: quaternion128(1+0i+0j+0k) + + testing.expect_value(t, R == 1, true) + testing.expect_value(t, 1 == R, true) + testing.expect_value(t, R != 1, false) + testing.expect_value(t, I == J, false) + testing.expect_value(t, J == K, false) + testing.expect_value(t, K == R, false) + testing.expect_value(t, I != J, true) + testing.expect_value(t, I == I, true) + + // every lane must take part, not just the real one + A :: quaternion128(2+3i+4j+5k) + testing.expect_value(t, A == quaternion128(2+3i+4j+5k), true) + testing.expect_value(t, A == quaternion128(9+3i+4j+5k), false) + testing.expect_value(t, A == quaternion128(2+9i+4j+5k), false) + testing.expect_value(t, A == quaternion128(2+3i+9j+5k), false) + testing.expect_value(t, A == quaternion128(2+3i+4j+9k), false) + + // promotion of the other operand, from integer, float and complex + testing.expect_value(t, R == 1.0, true) + testing.expect_value(t, quaternion128(2+3i+0j+0k) == 2+3i, true) + testing.expect_value(t, quaternion128(2+3i+0j+0k) == 2+4i, false) + + testing.expect_value(t, quaternion64(0) == 0, true) + testing.expect_value(t, quaternion256(0) == 0, true) + testing.expect_value(t, quaternion128(0) == quaternion128(-0.0), true) +} + +@(test) +compare_variable_quaternions :: proc(t: ^testing.T) { + I := quaternion128(0+1i+0j+0k) + J := quaternion128(0+0i+1j+0k) + K := quaternion128(0+0i+0j+1k) + R := quaternion128(1+0i+0j+0k) + + testing.expect_value(t, R == 1, true) + testing.expect_value(t, 1 == R, true) + testing.expect_value(t, R != 1, false) + testing.expect_value(t, I == J, false) + testing.expect_value(t, J == K, false) + testing.expect_value(t, K == R, false) + testing.expect_value(t, I != J, true) + testing.expect_value(t, I == I, true) + + A := quaternion128(2+3i+4j+5k) + testing.expect_value(t, A == quaternion128(2+3i+4j+5k), true) + testing.expect_value(t, A == quaternion128(9+3i+4j+5k), false) + testing.expect_value(t, A == quaternion128(2+9i+4j+5k), false) + testing.expect_value(t, A == quaternion128(2+3i+9j+5k), false) + testing.expect_value(t, A == quaternion128(2+3i+4j+9k), false) + + testing.expect_value(t, R == 1.0, true) + testing.expect_value(t, quaternion128(2+3i+0j+0k) == 2+3i, true) + testing.expect_value(t, quaternion128(2+3i+0j+0k) == 2+4i, false) + + q64 := quaternion64(0) + q256 := quaternion256(0) + testing.expect_value(t, q64 == 0, true) + testing.expect_value(t, q256 == 0, true) + testing.expect_value(t, quaternion128(0) == quaternion128(-0.0), true) +} + +@(test) +compare_constant_quaternion_nans :: proc(t: ^testing.T) { + NaN :: f64(0h7ff8_0000_0000_0000) + Q :: quaternion(w=NaN, x=0, y=0, z=0) + L :: quaternion(w=0, x=0, y=0, z=NaN) + + testing.expect_value(t, Q == Q, false) + testing.expect_value(t, Q != Q, true) + testing.expect_value(t, L == L, false) + testing.expect_value(t, L != L, true) + testing.expect_value(t, Q == 0, false) + testing.expect_value(t, Q != 0, true) +} + +@(test) +compare_variable_quaternion_nans :: proc(t: ^testing.T) { + NaN := f64(0h7ff8_0000_0000_0000) + Q := quaternion(w=NaN, x=0, y=0, z=0) + L := quaternion(w=0, x=0, y=0, z=NaN) + + testing.expect_value(t, Q == Q, false) + testing.expect_value(t, Q != Q, true) + testing.expect_value(t, L == L, false) + testing.expect_value(t, L != L, true) + testing.expect_value(t, Q == 0, false) + testing.expect_value(t, Q != 0, true) +} + +@(test) +compare_constant_complex_nans :: proc(t: ^testing.T) { + NaN :: f64(0h7ff8_0000_0000_0000) + C :: complex(NaN, 0) + D :: complex(0, NaN) + + testing.expect_value(t, C == C, false) + testing.expect_value(t, C != C, true) + testing.expect_value(t, D == D, false) + testing.expect_value(t, D != D, true) + testing.expect_value(t, C == 0, false) + testing.expect_value(t, C != 0, true) +} + +@(test) +compare_variable_complex_nans :: proc(t: ^testing.T) { + NaN := f64(0h7ff8_0000_0000_0000) + C := complex(NaN, 0) + D := complex(0, NaN) + + testing.expect_value(t, C == C, false) + testing.expect_value(t, C != C, true) + testing.expect_value(t, D == D, false) + testing.expect_value(t, D != D, true) + testing.expect_value(t, C == 0, false) + testing.expect_value(t, C != 0, true) +}