From 70e457cbbaa99d11a7badee88f745a92cef7b4f7 Mon Sep 17 00:00:00 2001 From: lilinus Date: Sat, 27 Apr 2024 21:54:09 +0200 Subject: [PATCH 1/2] Optimize In128 comparison operators --- .../src/System/Int128.cs | 44 ++++--------------- .../System/Int128Tests.GenericMath.cs | 24 ++++++++++ 2 files changed, 32 insertions(+), 36 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Int128.cs b/src/libraries/System.Private.CoreLib/src/System/Int128.cs index c1e6c459f7b54..61a56fac5e315 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Int128.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Int128.cs @@ -1043,57 +1043,29 @@ public static Int128 Log2(Int128 value) /// public static bool operator <(Int128 left, Int128 right) { - if (IsNegative(left) == IsNegative(right)) - { - return (left._upper < right._upper) - || ((left._upper == right._upper) && (left._lower < right._lower)); - } - else - { - return IsNegative(left); - } + return ((long)left._upper < (long)right._upper) + || ((left._upper == right._upper) && (left._lower < right._lower)); } /// public static bool operator <=(Int128 left, Int128 right) { - if (IsNegative(left) == IsNegative(right)) - { - return (left._upper < right._upper) - || ((left._upper == right._upper) && (left._lower <= right._lower)); - } - else - { - return IsNegative(left); - } + return ((long)left._upper < (long)right._upper) + || ((left._upper == right._upper) && (left._lower <= right._lower)); } /// public static bool operator >(Int128 left, Int128 right) { - if (IsNegative(left) == IsNegative(right)) - { - return (left._upper > right._upper) - || ((left._upper == right._upper) && (left._lower > right._lower)); - } - else - { - return IsNegative(right); - } + return ((long)left._upper > (long)right._upper) + || ((left._upper == right._upper) && (left._lower > right._lower)); } /// public static bool operator >=(Int128 left, Int128 right) { - if (IsNegative(left) == IsNegative(right)) - { - return (left._upper > right._upper) - || ((left._upper == right._upper) && (left._lower >= right._lower)); - } - else - { - return IsNegative(right); - } + return ((long)left._upper > (long)right._upper) + || ((left._upper == right._upper) && (left._lower >= right._lower)); } // diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int128Tests.GenericMath.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int128Tests.GenericMath.cs index 10c49230717d4..66de69ce2eec7 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int128Tests.GenericMath.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int128Tests.GenericMath.cs @@ -1012,6 +1012,12 @@ public static void op_GreaterThanTest() Assert.True(ComparisonOperatorsHelper.op_GreaterThan(MaxValue, 1)); Assert.False(ComparisonOperatorsHelper.op_GreaterThan(MinValue, 1)); Assert.False(ComparisonOperatorsHelper.op_GreaterThan(NegativeOne, 1)); + + Assert.True(ComparisonOperatorsHelper.op_GreaterThan(Zero, NegativeOne)); + Assert.True(ComparisonOperatorsHelper.op_GreaterThan(One, NegativeOne)); + Assert.True(ComparisonOperatorsHelper.op_GreaterThan(MaxValue, NegativeOne)); + Assert.False(ComparisonOperatorsHelper.op_GreaterThan(MinValue, NegativeOne)); + Assert.False(ComparisonOperatorsHelper.op_GreaterThan(NegativeOne, NegativeOne)); } [Fact] @@ -1022,6 +1028,12 @@ public static void op_GreaterThanOrEqualTest() Assert.True(ComparisonOperatorsHelper.op_GreaterThanOrEqual(MaxValue, 1)); Assert.False(ComparisonOperatorsHelper.op_GreaterThanOrEqual(MinValue, 1)); Assert.False(ComparisonOperatorsHelper.op_GreaterThanOrEqual(NegativeOne, 1)); + + Assert.True(ComparisonOperatorsHelper.op_GreaterThanOrEqual(Zero, NegativeOne)); + Assert.True(ComparisonOperatorsHelper.op_GreaterThanOrEqual(One, NegativeOne)); + Assert.True(ComparisonOperatorsHelper.op_GreaterThanOrEqual(MaxValue, NegativeOne)); + Assert.False(ComparisonOperatorsHelper.op_GreaterThanOrEqual(MinValue, NegativeOne)); + Assert.True(ComparisonOperatorsHelper.op_GreaterThanOrEqual(NegativeOne, NegativeOne)); } [Fact] @@ -1032,6 +1044,12 @@ public static void op_LessThanTest() Assert.False(ComparisonOperatorsHelper.op_LessThan(MaxValue, 1)); Assert.True(ComparisonOperatorsHelper.op_LessThan(MinValue, 1)); Assert.True(ComparisonOperatorsHelper.op_LessThan(NegativeOne, 1)); + + Assert.False(ComparisonOperatorsHelper.op_LessThan(Zero, NegativeOne)); + Assert.False(ComparisonOperatorsHelper.op_LessThan(One, NegativeOne)); + Assert.False(ComparisonOperatorsHelper.op_LessThan(MaxValue, NegativeOne)); + Assert.True(ComparisonOperatorsHelper.op_LessThan(MinValue, NegativeOne)); + Assert.False(ComparisonOperatorsHelper.op_LessThan(NegativeOne, NegativeOne)); } [Fact] @@ -1042,6 +1060,12 @@ public static void op_LessThanOrEqualTest() Assert.False(ComparisonOperatorsHelper.op_LessThanOrEqual(MaxValue, 1)); Assert.True(ComparisonOperatorsHelper.op_LessThanOrEqual(MinValue, 1)); Assert.True(ComparisonOperatorsHelper.op_LessThanOrEqual(NegativeOne, 1)); + + Assert.False(ComparisonOperatorsHelper.op_LessThanOrEqual(Zero, NegativeOne)); + Assert.False(ComparisonOperatorsHelper.op_LessThanOrEqual(One, NegativeOne)); + Assert.False(ComparisonOperatorsHelper.op_LessThanOrEqual(MaxValue, NegativeOne)); + Assert.True(ComparisonOperatorsHelper.op_LessThanOrEqual(MinValue, NegativeOne)); + Assert.True(ComparisonOperatorsHelper.op_LessThanOrEqual(NegativeOne, NegativeOne)); } // From 75a3579c4bc171cf1440357406d13bed2c5b12b3 Mon Sep 17 00:00:00 2001 From: lilinus Date: Sun, 5 May 2024 12:19:22 +0200 Subject: [PATCH 2/2] Document how Int128 comparison operators work --- .../System.Private.CoreLib/src/System/Int128.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/libraries/System.Private.CoreLib/src/System/Int128.cs b/src/libraries/System.Private.CoreLib/src/System/Int128.cs index 61a56fac5e315..0196af5fd5161 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Int128.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Int128.cs @@ -1043,6 +1043,13 @@ public static Int128 Log2(Int128 value) /// public static bool operator <(Int128 left, Int128 right) { + // If left and right have different signs: Signed comparison of _upper gives result since it is stored as two's complement + // If signs are equal and left._upper < right._upper: left < right for negative and positive values, + // since _upper is upper 64 bits in two's complement. + // If signs are equal and left._upper > right._upper: left > right for negative and positive values, + // since _upper is upper 64 bits in two's complement. + // If left._upper == right._upper: unsigned comparison of _lower gives the result for both negative and positive values since + // lower values are lower 64 bits in two's complement. return ((long)left._upper < (long)right._upper) || ((left._upper == right._upper) && (left._lower < right._lower)); } @@ -1050,6 +1057,7 @@ public static Int128 Log2(Int128 value) /// public static bool operator <=(Int128 left, Int128 right) { + // See comment in < operator for how this works. return ((long)left._upper < (long)right._upper) || ((left._upper == right._upper) && (left._lower <= right._lower)); } @@ -1057,6 +1065,7 @@ public static Int128 Log2(Int128 value) /// public static bool operator >(Int128 left, Int128 right) { + // See comment in < operator for how this works. return ((long)left._upper > (long)right._upper) || ((left._upper == right._upper) && (left._lower > right._lower)); } @@ -1064,6 +1073,7 @@ public static Int128 Log2(Int128 value) /// public static bool operator >=(Int128 left, Int128 right) { + // See comment in < operator for how this works. return ((long)left._upper > (long)right._upper) || ((left._upper == right._upper) && (left._lower >= right._lower)); }