diff --git a/src/tint/number.h b/src/tint/number.h index 4e3e6fd317..e1300193c3 100644 --- a/src/tint/number.h +++ b/src/tint/number.h @@ -16,6 +16,7 @@ #define SRC_TINT_NUMBER_H_ #include +#include #include #include #include @@ -135,61 +136,6 @@ inline std::ostream& operator<<(std::ostream& out, Number num) { return out << num.value; } -/// Equality operator. -/// @param a the LHS number -/// @param b the RHS number -/// @returns true if the numbers `a` and `b` are exactly equal. -template -bool operator==(Number a, Number b) { - using T = decltype(a.value + b.value); - return std::equal_to()(static_cast(a.value), static_cast(b.value)); -} - -/// Inequality operator. -/// @param a the LHS number -/// @param b the RHS number -/// @returns true if the numbers `a` and `b` are exactly unequal. -template -bool operator!=(Number a, Number b) { - return !(a == b); -} - -/// Equality operator. -/// @param a the LHS number -/// @param b the RHS number -/// @returns true if the numbers `a` and `b` are exactly equal. -template -std::enable_if_t, bool> operator==(Number a, B b) { - return a == Number(b); -} - -/// Inequality operator. -/// @param a the LHS number -/// @param b the RHS number -/// @returns true if the numbers `a` and `b` are exactly unequal. -template -std::enable_if_t, bool> operator!=(Number a, B b) { - return !(a == b); -} - -/// Equality operator. -/// @param a the LHS number -/// @param b the RHS number -/// @returns true if the numbers `a` and `b` are exactly equal. -template -std::enable_if_t, bool> operator==(A a, Number b) { - return Number(a) == b; -} - -/// Inequality operator. -/// @param a the LHS number -/// @param b the RHS number -/// @returns true if the numbers `a` and `b` are exactly unequal. -template -std::enable_if_t, bool> operator!=(A a, Number b) { - return !(a == b); -} - /// The partial specification of Number for f16 type, storing the f16 value as float, /// and enforcing proper explicit casting. template <> @@ -295,6 +241,70 @@ utils::Result CheckedConvert(Number num) { return TO(value); // Success } +/// Equality operator. +/// @param a the LHS number +/// @param b the RHS number +/// @returns true if the numbers `a` and `b` are exactly equal. Also considers sign bit. +template +bool operator==(Number a, Number b) { + // Use the highest-precision integer or floating-point type to perform the comparisons. + using T = + std::conditional_t || IsFloatingPoint, AFloat::type, AInt::type>; + auto va = static_cast(a.value); + auto vb = static_cast(b.value); + if constexpr (IsFloatingPoint) { + if (std::signbit(va) != std::signbit(vb)) { + return false; + } + } + return std::equal_to()(va, vb); +} + +/// Inequality operator. +/// @param a the LHS number +/// @param b the RHS number +/// @returns true if the numbers `a` and `b` are exactly unequal. Also considers sign bit. +template +bool operator!=(Number a, Number b) { + return !(a == b); +} + +/// Equality operator. +/// @param a the LHS number +/// @param b the RHS number +/// @returns true if the numbers `a` and `b` are exactly equal. +template +std::enable_if_t, bool> operator==(Number a, B b) { + return a == Number(b); +} + +/// Inequality operator. +/// @param a the LHS number +/// @param b the RHS number +/// @returns true if the numbers `a` and `b` are exactly unequal. +template +std::enable_if_t, bool> operator!=(Number a, B b) { + return !(a == b); +} + +/// Equality operator. +/// @param a the LHS number +/// @param b the RHS number +/// @returns true if the numbers `a` and `b` are exactly equal. +template +std::enable_if_t, bool> operator==(A a, Number b) { + return Number(a) == b; +} + +/// Inequality operator. +/// @param a the LHS number +/// @param b the RHS number +/// @returns true if the numbers `a` and `b` are exactly unequal. +template +std::enable_if_t, bool> operator!=(A a, Number b) { + return !(a == b); +} + /// Define 'TINT_HAS_OVERFLOW_BUILTINS' if the compiler provide overflow checking builtins. /// If the compiler does not support these builtins, then these are emulated with algorithms /// described in: diff --git a/src/tint/number_test.cc b/src/tint/number_test.cc index 6a48f9d7eb..81acc0489c 100644 --- a/src/tint/number_test.cc +++ b/src/tint/number_test.cc @@ -65,6 +65,79 @@ constexpr double kLowestF16NextULP = -kHighestF16NextULP; // warning. TINT_BEGIN_DISABLE_WARNING(CONSTANT_OVERFLOW); +TEST(NumberTest, Equality) { + EXPECT_TRUE(0_a == 0_a); + EXPECT_TRUE(10_a == 10_a); + EXPECT_TRUE(-10_a == -10_a); + + EXPECT_TRUE(0_i == 0_i); + EXPECT_TRUE(10_i == 10_i); + EXPECT_TRUE(-10_i == -10_i); + + EXPECT_TRUE(0_u == 0_u); + EXPECT_TRUE(10_u == 10_u); + + EXPECT_TRUE(0._a == 0._a); + EXPECT_TRUE(-0._a == -0._a); + EXPECT_TRUE(10._a == 10._a); + EXPECT_TRUE(-10._a == -10._a); + + EXPECT_TRUE(0_f == 0_f); + EXPECT_TRUE(-0_f == -0_f); + EXPECT_TRUE(10_f == 10_f); + EXPECT_TRUE(-10_f == -10_f); + + EXPECT_TRUE(0_h == 0_h); + EXPECT_TRUE(-0_h == -0_h); + EXPECT_TRUE(10_h == 10_h); + EXPECT_TRUE(-10_h == -10_h); +} + +TEST(NumberTest, Inequality) { + EXPECT_TRUE(0_a != 1_a); + EXPECT_TRUE(10_a != 11_a); + EXPECT_TRUE(11_a != 10_a); + EXPECT_TRUE(-10_a != -11_a); + EXPECT_TRUE(-11_a != -10_a); + + EXPECT_TRUE(0_i != 1_i); + EXPECT_TRUE(1_i != 0_i); + EXPECT_TRUE(10_i != 11_i); + EXPECT_TRUE(11_i != 10_i); + EXPECT_TRUE(-10_i != -11_i); + EXPECT_TRUE(-11_i != -10_i); + + EXPECT_TRUE(0_u != 1_u); + EXPECT_TRUE(1_u != 0_u); + EXPECT_TRUE(10_u != 11_u); + EXPECT_TRUE(11_u != 10_u); + + EXPECT_TRUE(0._a != -0._a); + EXPECT_TRUE(-0._a != 0._a); + EXPECT_TRUE(10._a != 11._a); + EXPECT_TRUE(11._a != 10._a); + EXPECT_TRUE(-10._a != -11._a); + EXPECT_TRUE(-11._a != -10._a); + + EXPECT_TRUE(0_f != -0_f); + EXPECT_TRUE(-0_f != 0_f); + EXPECT_TRUE(-0_f != -1_f); + EXPECT_TRUE(-1_f != -0_f); + EXPECT_TRUE(10_f != -10_f); + EXPECT_TRUE(-10_f != 10_f); + EXPECT_TRUE(10_f != 11_f); + EXPECT_TRUE(-10_f != -11_f); + + EXPECT_TRUE(0_h != -0_h); + EXPECT_TRUE(-0_h != 0_h); + EXPECT_TRUE(-0_h != -1_h); + EXPECT_TRUE(-1_h != -0_h); + EXPECT_TRUE(10_h != -10_h); + EXPECT_TRUE(-10_h != 10_h); + EXPECT_TRUE(10_h != 11_h); + EXPECT_TRUE(-10_h != -11_h); +} + TEST(NumberTest, CheckedConvertIdentity) { EXPECT_EQ(CheckedConvert(0_a), 0_a); EXPECT_EQ(CheckedConvert(0_a), 0.0_a); @@ -211,7 +284,7 @@ TEST(NumberTest, QuantizeF16) { EXPECT_EQ(f16(lowestNegativeSubnormalF16PlusULP), -0x0.ff8p-14); EXPECT_EQ(f16(highestNegativeSubnormalF16MinusULP), highestNegativeSubnormalF16); EXPECT_EQ(f16(highestNegativeSubnormalF16), highestNegativeSubnormalF16); - EXPECT_EQ(f16(highestNegativeSubnormalF16PlusULP), 0.0); + EXPECT_EQ(f16(highestNegativeSubnormalF16PlusULP), -0.0); // Test the mantissa discarding. EXPECT_EQ(f16(-0x0.064p-14), -0x0.064p-14); EXPECT_EQ(f16(-0x0.067fecp-14), -0x0.064p-14);