Skip to content

Commit 1883189

Browse files
Merge pull request #273 from xwu/toil-and-trouble
[_TestSupport] Fix DoubleWidth think-o that trips an assert
2 parents 182c9b2 + a7e27e1 commit 1883189

File tree

2 files changed

+39
-3
lines changed

2 files changed

+39
-3
lines changed

Sources/_TestSupport/DoubleWidth.swift

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -363,8 +363,10 @@ extension DoubleWidth : FixedWidthInteger {
363363

364364
let low =
365365
DoubleWidth<Low>(mid1.partial, a.partial)
366+
let (sum_, overflow_) =
367+
mid1.carry.addingReportingOverflow(mid2.partial)
366368
let high =
367-
DoubleWidth(High(mid2.carry + d.carry), mid1.carry + mid2.partial)
369+
DoubleWidth(High(mid2.carry + d.carry + (overflow_ ? 1 : 0)), sum_)
368370

369371
if isNegative {
370372
let (lowComplement, overflow) = (~low).addingReportingOverflow(1)
@@ -631,10 +633,14 @@ extension DoubleWidth : UnsignedInteger where Base : UnsignedInteger {
631633
) -> (quotient: Low, remainder: Magnitude) {
632634
// The following invariants are guaranteed to hold by dividingFullWidth or
633635
// quotientAndRemainder before this method is invoked:
634-
assert(lhs.high != (0 as Low))
635636
assert(rhs.leadingZeroBitCount == 0)
636637
assert(Magnitude(lhs.high, lhs.mid) < rhs)
637638

639+
guard lhs.high != (0 as Low) else {
640+
let lhs_ = Magnitude(lhs.mid, lhs.low)
641+
return lhs_ < rhs ? (0, lhs_) : (1, lhs_ &- rhs)
642+
}
643+
638644
// Estimate the quotient.
639645
var quotient = lhs.high == rhs.high
640646
? Low.max
@@ -735,8 +741,10 @@ extension DoubleWidth : UnsignedInteger where Base : UnsignedInteger {
735741

736742
// Left shift both rhs and lhs, then divide and right shift the remainder.
737743
let shift = rhs.leadingZeroBitCount
744+
// Note the use of `>>` instead of `&>>` below,
745+
// as `high` should be zero if `shift` is zero.
746+
let high = (lhs >> (Magnitude.bitWidth &- shift)).low
738747
let rhs = rhs &<< shift
739-
let high = (lhs &>> (Magnitude.bitWidth &- shift)).low
740748
let lhs = lhs &<< shift
741749
let (quotient, remainder) =
742750
Magnitude._divide((high, lhs.high, lhs.low), by: rhs)

Tests/IntegerUtilitiesTests/DoubleWidthTests.swift

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,34 @@ final class DoubleWidthTests: XCTestCase {
129129

130130
XCTAssertEqual(x % 3, 1)
131131
XCTAssertEqual(x % y, x)
132+
133+
do {
134+
let lhs = _UInt16((high: 0b0011_0000, low: 0))
135+
let rhs = _UInt16((high: 0b0010_0000, low: 0))
136+
XCTAssertEqual(lhs % rhs, 4096)
137+
}
138+
do {
139+
let lhs = _UInt128((high: 0xa0c7d7165cf01386, low: 0xbf3f66a93056143f))
140+
let rhs = _UInt128((high: 0x9ac3a19b1e7d6b83, low: 0x513929792d588736))
141+
XCTAssertEqual(String(lhs % rhs), "7997221894243298914179865336050715913")
142+
}
143+
do {
144+
let lhs = _UInt128((high: 0xea8a9116b7af33b7, low: 0x3d9d6779ddd22ca3))
145+
let rhs = _UInt128((high: 0xc3673efc7f1f37cc, low: 0x312f661057d0ba94))
146+
XCTAssertEqual(String(lhs % rhs), "52023287460685389410162512181093036559")
147+
}
148+
do {
149+
let lhs = _UInt256("2369676578372158364766242369061213561181961479062237766620")!
150+
let rhs = _UInt256("102797312405202436815976773795958969482")!
151+
XCTAssertEqual(String(lhs / rhs), "23051931251193218442")
152+
}
153+
do {
154+
let lhs = _UInt256("96467201117289166187766181030232879447148862859323917044548749804018359008044")!
155+
let rhs = _UInt256("4646260627574879223760172113656436161581617773435991717024")!
156+
XCTAssertEqual(String(lhs / rhs), "20762331011904583253")
157+
}
158+
159+
XCTAssertTrue((0xff01 as _UInt16).multipliedFullWidth(by: 0x101) == (high: 256, low: 1))
132160
}
133161

134162
func testArithmetic_Signed() {

0 commit comments

Comments
 (0)