|
2 | 2 | //
|
3 | 3 | // This source file is part of the Swift Numerics open source project
|
4 | 4 | //
|
5 |
| -// Copyright (c) 2017-2021 Apple Inc. and the Swift Numerics project authors |
| 5 | +// Copyright (c) 2017-2024 Apple Inc. and the Swift Numerics project authors |
6 | 6 | // Licensed under Apache License v2.0 with Runtime Library Exception
|
7 | 7 | //
|
8 | 8 | // See https://swift.org/LICENSE.txt for license information
|
@@ -281,17 +281,11 @@ extension DoubleWidth : FixedWidthInteger {
|
281 | 281 | by rhs: DoubleWidth
|
282 | 282 | ) -> (partialValue: DoubleWidth, overflow: Bool) {
|
283 | 283 | let (carry, product) = multipliedFullWidth(by: rhs)
|
284 |
| - let result = DoubleWidth(truncatingIfNeeded: product) |
285 |
| - |
286 |
| - let isNegative = DoubleWidth.isSigned && |
287 |
| - (self < (0 as DoubleWidth)) != (rhs < (0 as DoubleWidth)) |
288 |
| - let didCarry = isNegative |
289 |
| - ? carry != ~(0 as DoubleWidth) |
290 |
| - : carry != (0 as DoubleWidth) |
291 |
| - let hadPositiveOverflow = |
292 |
| - DoubleWidth.isSigned && !isNegative && product.leadingZeroBitCount == 0 |
293 |
| - |
294 |
| - return (result, didCarry || hadPositiveOverflow) |
| 284 | + let partialValue = DoubleWidth(truncatingIfNeeded: product) |
| 285 | + // Overflow has occured if carry is not just the sign-extension of |
| 286 | + // partialValue (which is zero when Base is unsigned). |
| 287 | + let overflow = carry != (partialValue >> DoubleWidth.bitWidth) |
| 288 | + return (partialValue, overflow) |
295 | 289 | }
|
296 | 290 |
|
297 | 291 | public func quotientAndRemainder(
|
@@ -331,7 +325,11 @@ extension DoubleWidth : FixedWidthInteger {
|
331 | 325 | if DoubleWidth.isSigned && other == -1 && self == .min { return (0, true) }
|
332 | 326 | return (quotientAndRemainder(dividingBy: other).remainder, false)
|
333 | 327 | }
|
334 |
| - |
| 328 | + |
| 329 | + // When using a pre-Swift 6.0 runtime, `&*` is not a protocol requirement of |
| 330 | + // FixedWidthInteger, which results in the default implementation of this |
| 331 | + // operation ending up recursively calling itself forever. In order to avoid |
| 332 | + // this, we keep the concrete implementation around. |
335 | 333 | public func multipliedFullWidth(
|
336 | 334 | by other: DoubleWidth
|
337 | 335 | ) -> (high: DoubleWidth, low: DoubleWidth.Magnitude) {
|
@@ -453,18 +451,21 @@ extension DoubleWidth : FixedWidthInteger {
|
453 | 451 |
|
454 | 452 | /// Returns this value "masked" by its bit width.
|
455 | 453 | ///
|
456 |
| - /// "Masking" notionally involves repeatedly incrementing or decrementing this |
457 |
| - /// value by `self.bitWidth` until the result is contained in the range |
458 |
| - /// `0..<self.bitWidth`. |
| 454 | + /// "Masking" notionally involves repeatedly incrementing or decrementing |
| 455 | + /// this value by `self.bitWidth` until the result is contained in the |
| 456 | + /// range `0..<self.bitWidth`. |
459 | 457 | internal func _masked() -> DoubleWidth {
|
460 |
| - // FIXME(integers): test types with bit widths that aren't powers of 2 |
| 458 | + let bits = DoubleWidth(DoubleWidth.bitWidth) |
461 | 459 | if DoubleWidth.bitWidth.nonzeroBitCount == 1 {
|
462 |
| - return self & DoubleWidth(DoubleWidth.bitWidth &- 1) |
| 460 | + return self & (bits &- 1) |
463 | 461 | }
|
464 |
| - if DoubleWidth.isSigned && self._storage.high < (0 as High) { |
465 |
| - return self % DoubleWidth(DoubleWidth.bitWidth) + self |
466 |
| - } |
467 |
| - return self % DoubleWidth(DoubleWidth.bitWidth) |
| 462 | + let reduced = self % bits |
| 463 | + // bitWidth is always positive, but the value being reduced might have |
| 464 | + // been negative, in which case reduced will also be negative. We need |
| 465 | + // the representative in [0, bitWidth), so conditionally add the count |
| 466 | + // to get the positive residue. |
| 467 | + if Base.isSigned && reduced < 0 { return reduced &+ bits } |
| 468 | + return reduced |
468 | 469 | }
|
469 | 470 |
|
470 | 471 | public static func &<<=(lhs: inout DoubleWidth, rhs: DoubleWidth) {
|
@@ -590,6 +591,31 @@ extension DoubleWidth : FixedWidthInteger {
|
590 | 591 | precondition(!overflow, "Overflow in %=")
|
591 | 592 | lhs = result
|
592 | 593 | }
|
| 594 | + |
| 595 | + public static func &+( |
| 596 | + lhs: DoubleWidth, rhs: DoubleWidth |
| 597 | + ) -> DoubleWidth { |
| 598 | + let (low, carry) = lhs.low.addingReportingOverflow(rhs.low) |
| 599 | + let high = lhs.high &+ rhs.high &+ (carry ? 1 : 0) |
| 600 | + return DoubleWidth(high, low) |
| 601 | + } |
| 602 | + |
| 603 | + public static func &-( |
| 604 | + lhs: DoubleWidth, rhs: DoubleWidth |
| 605 | + ) -> DoubleWidth { |
| 606 | + let (low, borrow) = lhs.low.subtractingReportingOverflow(rhs.low) |
| 607 | + let high = lhs.high &- rhs.high &- (borrow ? 1 : 0) |
| 608 | + return DoubleWidth(high, low) |
| 609 | + } |
| 610 | + |
| 611 | + public static func &*( |
| 612 | + lhs: DoubleWidth, rhs: DoubleWidth |
| 613 | + ) -> DoubleWidth { |
| 614 | + let p00 = lhs.low.multipliedFullWidth(by: rhs.low) |
| 615 | + let p10 = lhs.high &* Base(truncatingIfNeeded: rhs.low) |
| 616 | + let p01 = Base(truncatingIfNeeded: lhs.low) &* rhs.high |
| 617 | + return DoubleWidth(p10 &+ p01 &+ Base(truncatingIfNeeded: p00.high), p00.low) |
| 618 | + } |
593 | 619 |
|
594 | 620 | public init(_truncatingBits bits: UInt) {
|
595 | 621 | _storage.low = Low(_truncatingBits: bits)
|
|
0 commit comments