@@ -311,17 +311,11 @@ extension DoubleWidth : FixedWidthInteger {
311
311
by rhs: DoubleWidth
312
312
) -> (partialValue: DoubleWidth, overflow: Bool) {
313
313
let (carry, product) = multipliedFullWidth(by: rhs)
314
- let result = DoubleWidth(truncatingIfNeeded: product)
315
-
316
- let isNegative = DoubleWidth.isSigned &&
317
- (self < (0 as DoubleWidth)) != (rhs < (0 as DoubleWidth))
318
- let didCarry = isNegative
319
- ? carry != ~(0 as DoubleWidth)
320
- : carry != (0 as DoubleWidth)
321
- let hadPositiveOverflow =
322
- DoubleWidth.isSigned && !isNegative && product.leadingZeroBitCount == 0
323
-
324
- return (result, didCarry || hadPositiveOverflow)
314
+ let partialValue = DoubleWidth(truncatingIfNeeded: product)
315
+ // Overflow has occured if carry is not just the sign-extension of
316
+ // partialValue (which is zero when Base is unsigned).
317
+ let overflow = carry != (partialValue >> DoubleWidth.bitWidth)
318
+ return (partialValue, overflow)
325
319
}
326
320
327
321
public func quotientAndRemainder(
@@ -473,18 +467,21 @@ extension DoubleWidth : FixedWidthInteger {
473
467
474
468
/// Returns this value "masked" by its bit width.
475
469
///
476
- /// "Masking" notionally involves repeatedly incrementing or decrementing this
477
- /// value by `self.bitWidth` until the result is contained in the range
478
- /// `0..<self.bitWidth`.
470
+ /// "Masking" notionally involves repeatedly incrementing or decrementing
471
+ /// this value by `self.bitWidth` until the result is contained in the
472
+ /// range `0..<self.bitWidth`.
479
473
internal func _masked() -> DoubleWidth {
480
- // FIXME(integers): test types with bit widths that aren't powers of 2
474
+ let bits = DoubleWidth(DoubleWidth.bitWidth)
481
475
if DoubleWidth.bitWidth.nonzeroBitCount == 1 {
482
- return self & DoubleWidth(DoubleWidth.bitWidth &- 1)
483
- }
484
- if DoubleWidth.isSigned && self._storage.high < (0 as High) {
485
- return self % DoubleWidth(DoubleWidth.bitWidth) + self
476
+ return self & (bits &- 1)
486
477
}
487
- return self % DoubleWidth(DoubleWidth.bitWidth)
478
+ let reduced = self % bits
479
+ // bitWidth is always positive, but the value being reduced might have
480
+ // been negative, in which case reduced will also be negative. We need
481
+ // the representative in [0, bitWidth), so conditionally add the count
482
+ // to get the positive residue.
483
+ if Base.isSigned && reduced < 0 { return reduced &+ bits }
484
+ return reduced
488
485
}
489
486
490
487
public static func &<<=(lhs: inout DoubleWidth, rhs: DoubleWidth) {
@@ -555,6 +552,31 @@ binaryOperators = [
555
552
}
556
553
% end
557
554
555
+ public static func &+(
556
+ lhs: DoubleWidth, rhs: DoubleWidth
557
+ ) -> DoubleWidth {
558
+ let (low, carry) = lhs.low.addingReportingOverflow(rhs.low)
559
+ let high = lhs.high &+ rhs.high &+ (carry ? 1 : 0)
560
+ return DoubleWidth(high, low)
561
+ }
562
+
563
+ public static func &-(
564
+ lhs: DoubleWidth, rhs: DoubleWidth
565
+ ) -> DoubleWidth {
566
+ let (low, borrow) = lhs.low.subtractingReportingOverflow(rhs.low)
567
+ let high = lhs.high &- rhs.high &- (borrow ? 1 : 0)
568
+ return DoubleWidth(high, low)
569
+ }
570
+
571
+ public static func &*(
572
+ lhs: DoubleWidth, rhs: DoubleWidth
573
+ ) -> DoubleWidth {
574
+ let p00 = lhs.low.multipliedFullWidth(by: rhs.low)
575
+ let p10 = lhs.high &* Base(truncatingIfNeeded: rhs.low)
576
+ let p01 = Base(truncatingIfNeeded: lhs.low) &* rhs.high
577
+ return DoubleWidth(p10 &+ p01 &+ Base(truncatingIfNeeded: p00.high), p00.low)
578
+ }
579
+
558
580
public init(_truncatingBits bits: UInt) {
559
581
_storage.low = Low(_truncatingBits: bits)
560
582
_storage.high = High(_truncatingBits: bits >> UInt(Low.bitWidth))
0 commit comments