Closed oscbyspro closed 1 year ago
1. Test Case '-[ANKFullWidthKitBenchmarks. Int256BenchmarksOnMultiplication testMultipliedReportingOverflow]' passed (0.023 seconds).
1. Test Case '-[ANKFullWidthKitBenchmarks.UInt256BenchmarksOnMultiplication testMultipliedReportingOverflow]' passed (0.014 seconds).
2. Test Case '-[ANKFullWidthKitBenchmarks. Int256BenchmarksOnMultiplication testMultipliedReportingOverflow]' passed (0.017 seconds).
2. Test Case '-[ANKFullWidthKitBenchmarks.UInt256BenchmarksOnMultiplication testMultipliedReportingOverflow]' passed (0.014 seconds).
The following assertions test all overflowing signed paths:
ANKAssertMultiplication(T.max, T( 1), T.max, T( 0), false)
ANKAssertMultiplication(T.max, T(-1), T.min + T(1), T(-1), false)
ANKAssertMultiplication(T.min, T( 1), T.min, T(-1), false)
ANKAssertMultiplication(T.min, T(-1), T.min, T( 0), true )
ANKAssertMultiplication(T.max, T( 2), T(-2), T( 0), true )
ANKAssertMultiplication(T.max, T(-2), T( 2), T(-1), true )
ANKAssertMultiplication(T.min, T( 2), T( 0), T(-1), true )
ANKAssertMultiplication(T.min, T(-2), T( 0), T( 1), true )
I find this rewrite, which leverages matches(repeating:)
(#104), amazingly straight forward:
if !Self.isSigned {
overflow = !(product.high.matches(repeating: false)) // π
} else if self.isLessThanZero == amount.isLessThanZero {
// overflow = product > Self.max, but more efficient
overflow = !(product.high.matches(repeating: false) && !product.low.mostSignificantBit) // ποΈ
} else {
// overflow = product < Self.min, but more efficient
overflow = !(product.high.matches(repeating: true ) && product.low.mostSignificantBit) && product.high.mostSignificantBit // ποΈ
}
Alternatively:
if !Self.isSigned {
overflow = !(product.high.isZero) // π
} else if self.isLessThanZero == amount.isLessThanZero {
// overflow = product > Self.max, but more efficient
overflow = !(product.high.isZero && !product.low.mostSignificantBit) // ποΈ
} else {
// overflow = product < Self.min, but more efficient
overflow = !(product.high.isFull && product.low.mostSignificantBit) && product.high.mostSignificantBit // ποΈ
}
Signed multiplication is currently much slower than unsigned, mostly because the signed overflow check is snail-paced.
I believe the following is a faster, allocationless, version of the same comparsion. Although, I may have to add tests for it.
The idea is to only check bits that are significant for detecting overflow.