[stdlib/prototype] Multiprecision subtraction
diff --git a/test/Prototypes/Integers.swift.gyb b/test/Prototypes/Integers.swift.gyb
index cec23df..37c7791 100644
--- a/test/Prototypes/Integers.swift.gyb
+++ b/test/Prototypes/Integers.swift.gyb
@@ -589,6 +589,10 @@
}
extension UWord {
+ public typealias AdditiveOperator
+ = (UWord) -> (UWord, carryIn: Bool)
+ -> (result: UWord, carryFlag: Bool, overflowFlag: Bool)
+
% for name in 'add', 'subtract':
// @_transparent
public // transparent
@@ -932,18 +936,20 @@
//
extension IntegerType {
public mutating func unsignedAddInPlace<RHS: IntegerType>(
- rhs: RHS
+ rhs: RHS, uwordOperator: UWord.AdditiveOperator
) -> ArithmeticOverflow {
_log("* \(Self.self)(\(self.hex)).unsignedAddInPlace"
+ "(\(RHS.self)(\(rhs.hex)))")
let (carry, knownOverflow) = self.unsignedAddInPlace(
rhs,
- countWords: max(self.countRepresentedWords, rhs.countRepresentedWords))
+ countWords: max(self.countRepresentedWords, rhs.countRepresentedWords),
+ uwordOperator: uwordOperator
+ )
return knownOverflow ?? ArithmeticOverflow(carry)
}
public mutating func unsignedAddInPlace<RHS: IntegerType>(
- rhs: RHS, countWords: Word
+ rhs: RHS, countWords: Word, uwordOperator: UWord.AdditiveOperator
) -> (carry: Bool, knownOverflow: ArithmeticOverflow?) {
_log("** \(Self.self)(\(self.hex)).unsignedAddInPlace"
+ "(\(RHS.self)(\(rhs.hex)), countWords: \(countWords))")
@@ -954,7 +960,7 @@
while i < countWords {
let sum: UWord
- (sum, carry, _) = uword(i)._adding(rhs.uword(i), carryIn: carry)
+ (sum, carry, _) = uwordOperator(uword(i))(rhs.uword(i), carryIn: carry)
if !self.replaceUWord(i, with: sum) {
return (false, .Overflow)
@@ -975,7 +981,7 @@
}
public mutating func signedAddInPlace<RHS: IntegerType>(
- rhs: RHS
+ rhs: RHS, uwordOperator: UWord.AdditiveOperator
) -> ArithmeticOverflow {
_log("* \(Self.self)(\(self.hex)).signedAddInPlace"
+ "(\(RHS.self)(\(rhs.hex)))")
@@ -983,8 +989,11 @@
// word. We may overflow here or discover that there is no
// overflow.
let lowWordCount = self.signWordIndex
+
let (lowCarry, lowOverflowKnown)
- = self.unsignedAddInPlace(rhs, countWords: lowWordCount)
+ = self.unsignedAddInPlace(
+ rhs, countWords: lowWordCount, uwordOperator: uwordOperator)
+
if let finalOverflow = lowOverflowKnown { return finalOverflow }
// Save off the sign word so that we don't lose it if the highest
@@ -998,7 +1007,7 @@
repeat {
let bits: UWord
- (bits, carry, overflow) = oldSign._lowUWord._adding(
+ (bits, carry, overflow) = uwordOperator(oldSign._lowUWord)(
rhs.uword(wordIndex), carryIn: carry)
if !self.replaceUWord(wordIndex, with: bits) {
return .Overflow
@@ -1014,12 +1023,15 @@
}
extension IntegerType {
- public mutating func addInPlace<RHS: IntegerType>(
+ % for name in 'add', 'subtract':
+ public mutating func ${name}InPlace<RHS: IntegerType>(
rhs: RHS
) -> ArithmeticOverflow {
return Self.isSigned || RHS.isSigned
- ? signedAddInPlace(rhs) : unsignedAddInPlace(rhs)
+ ? signedAddInPlace(rhs, uwordOperator: UWord._${name}ing)
+ : unsignedAddInPlace(rhs, uwordOperator: UWord._${name}ing)
}
+ % end
}
% for x in binaryArithmetic:
@@ -1035,6 +1047,12 @@
_assertCond(overflow == .None, "overflow in multiprecision add.")
}
+@inline(__always)
+public func -=<T: IntegerType, U: IntegerType>(inout lhs: T, rhs: U) {
+ let overflow = lhs.subtractInPlace(rhs)
+ _assertCond(overflow == .None, "overflow in multiprecision subtract.")
+}
+
//===--- Tests ------------------------------------------------------------===//
extension IntegerType {
@@ -1538,6 +1556,104 @@
expectEqual(0, x)
}
+tests.test("Multiprecision/-/DWord") {
+ var x = DWord.max - 2
+ x -= (-1 as Int8)
+ expectEqual(DWord.max - 1, x)
+ x -= (1 as Int8)
+ expectEqual(DWord.max - 2, x)
+
+ x = DWord.min
+ x -= (-1 as Int8)
+ expectEqual(DWord.min + 1, x)
+
+ x -= (1 as Int8)
+ expectEqual(DWord.min, x)
+
+ x = DWord(UWord.max)
+ x -= (-1 as Int8)
+ expectEqual(DWord(UWord.max) + 1, x)
+ x -= (1 as Int8)
+ expectEqual(DWord(UWord.max), x)
+ x -= (-1 as DWord)
+ expectEqual(DWord(UWord.max) + 1, x)
+
+ x = DWord(Word.max)
+ var overflow: ArithmeticOverflow
+ overflow = x.subtractInPlace(UWord(~Word.min) + 1)
+ expectEqual(.None, overflow)
+ expectEqual(-1, x)
+
+ overflow = x.subtractInPlace(UDWord(~DWord.min) + 1)
+ expectEqual(.Overflow, overflow)
+ expectEqual(DWord.max, x)
+
+ overflow = x.subtractInPlace(-1 as Word)
+ expectEqual(.Overflow, overflow)
+ expectEqual(DWord.min, x)
+
+ x = 1
+ overflow = x.subtractInPlace(DWord.min + 1)
+ expectEqual(.Overflow, overflow)
+ expectEqual(DWord.min, x)
+}
+
+tests.test("Multiprecision/-/UDWord") {
+ var x = UDWord.max - 2
+ x -= (-1 as Int8)
+ expectEqual(UDWord.max - 1, x)
+ x -= (1 as UInt8)
+ expectEqual(UDWord.max - 2, x)
+
+ x = UDWord.min
+ x -= (-1 as Int8)
+ expectEqual(1, x)
+
+ x -= (1 as Int8)
+ expectEqual(UDWord.min, x)
+
+ x = UDWord(UWord.max)
+ x -= (-1 as Int8)
+ expectEqual(UDWord(UWord.max) + 1, x)
+ x -= (1 as Int8)
+ expectEqual(UDWord(UWord.max), x)
+ x -= (-1 as DWord)
+ expectEqual(UDWord(UWord.max) + 1, x)
+ x -= (1 as DWord)
+ expectEqual(UDWord(UWord.max), x)
+
+ x = UDWord(Word.max)
+ var overflow: ArithmeticOverflow
+ overflow = x.subtractInPlace(UWord(~Word.min) + 1)
+ expectEqual(.Overflow, overflow)
+ expectEqual(UDWord.max, x)
+
+ overflow = x.subtractInPlace(UDWord(DWord.max) + 1)
+ expectEqual(.None, overflow)
+ overflow = x.subtractInPlace(UDWord(DWord.max) + 1)
+ expectEqual(.Overflow, overflow)
+ expectEqual(UDWord.max, x)
+
+ overflow = x.subtractInPlace(DWord.max)
+ expectEqual(.None, overflow)
+ overflow = x.subtractInPlace(DWord.max)
+ expectEqual(.None, overflow)
+ expectEqual(1, x)
+
+ overflow = x.subtractInPlace(2 as UDWord)
+ expectEqual(.Overflow, overflow)
+ expectEqual(UDWord.max, x)
+
+ overflow = x.subtractInPlace(-1 as Int8)
+ expectEqual(.Overflow, overflow)
+ expectEqual(0, x)
+
+ x = 1
+ overflow = x.subtractInPlace(UDWord.max)
+ expectEqual(.Overflow, overflow)
+ expectEqual(2, x)
+}
+
tests.test("Multiprecision/+/Int16") {
var x = Int16.max - 2
x += (1 as UDWord)