-
Notifications
You must be signed in to change notification settings - Fork 99
/
BigUInt Subtraction.swift
151 lines (138 loc) · 5.81 KB
/
BigUInt Subtraction.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
//
// BigUInt Subtraction.swift
// BigInt
//
// Created by Károly Lőrentey on 2016-01-03.
// Copyright © 2016-2017 Károly Lőrentey.
//
extension BigUInt {
//MARK: Subtraction
/// Subtract a digit `d` from this integer in place, returning a flag that is true if the operation
/// caused an arithmetic overflow. `d` is shifted `shift` digits to the left before being subtracted.
///
/// - Note: If the result is true, then `self` becomes the two's complement of the absolute difference.
/// - Complexity: O(count)
public mutating func subtractDigitWithOverflow(_ d: Digit, atPosition shift: Int = 0) -> Bool {
precondition(shift >= 0)
lift()
var carry: Digit = d
var i = shift
while carry > 0 && i < count {
let (d, c) = Digit.subtractWithOverflow(self[i], carry)
self[i] = d
carry = (c ? 1 : 0)
i += 1
}
return carry > 0
}
/// Subtract a digit `d` from this integer, returning the difference and a flag that is true if the operation
/// caused an arithmetic overflow. `d` is shifted `shift` digits to the left before being subtracted.
///
/// - Note: If `overflow` is true, then the returned value is the two's complement of the absolute difference.
/// - Complexity: O(count)
public func subtractingDigitWithOverflow(_ d: Digit, atPosition shift: Int = 0) -> (BigUInt, overflow: Bool) {
var result = self
let overflow = result.subtractDigitWithOverflow(d, atPosition: shift)
return (result, overflow)
}
/// Subtract a digit `d` from this integer in place.
/// `d` is shifted `shift` digits to the left before being subtracted.
///
/// - Requires: self >= d * 2^shift
/// - Complexity: O(count)
public mutating func subtractDigit(_ d: Digit, atPosition shift: Int = 0) {
let overflow = subtractDigitWithOverflow(d, atPosition: shift)
precondition(!overflow)
}
/// Subtract a digit `d` from this integer and return the result.
/// `d` is shifted `shift` digits to the left before being subtracted.
///
/// - Requires: self >= d * 2^shift
/// - Complexity: O(count)
public func subtractingDigit(_ d: Digit, atPosition shift: Int = 0) -> BigUInt {
var result = self
result.subtractDigit(d, atPosition: shift)
return result
}
/// Subtract `b` from this integer in place, and return true iff the operation caused an
/// arithmetic overflow. `b` is shifted `shift` digits to the left before being subtracted.
///
/// - Note: If the result is true, then `self` becomes the twos' complement of the absolute difference.
/// - Complexity: O(count)
public mutating func subtractWithOverflow(_ b: BigUInt, atPosition shift: Int = 0) -> Bool {
precondition(shift >= 0)
lift()
var carry = false
var bi = 0
while bi < b.count || (shift + bi < count && carry) {
let ai = shift + bi
let (d, c) = Digit.subtractWithOverflow(self[ai], b[bi])
if carry {
let (d2, c2) = Digit.subtractWithOverflow(d, 1)
self[ai] = d2
carry = c || c2
}
else {
self[ai] = d
carry = c
}
bi += 1
}
return carry
}
/// Subtract `b` from this integer, returning the difference and a flag that is true if the operation caused an
/// arithmetic overflow. `b` is shifted `shift` digits to the left before being subtracted.
///
/// - Note: If `overflow` is true, then the result value is the twos' complement of the absolute value of the difference.
/// - Complexity: O(count)
public func subtractingWithOverflow(_ b: BigUInt, atPosition shift: Int = 0) -> (BigUInt, overflow: Bool) {
var result = self
let overflow = result.subtractWithOverflow(b, atPosition: shift)
return (result, overflow)
}
/// Subtract `b` from this integer in place.
/// `b` is shifted `shift` digits to the left before being subtracted.
///
/// - Requires: self >= b * 2^shift
/// - Complexity: O(count)
public mutating func subtract(_ b: BigUInt, atPosition shift: Int = 0) {
let overflow = subtractWithOverflow(b, atPosition: shift)
precondition(!overflow)
}
/// Subtract `b` from this integer, and return the difference.
/// `b` is shifted `shift` digits to the left before being subtracted.
///
/// - Requires: self >= b * 2^shift
/// - Complexity: O(count)
public func subtracting(_ b: BigUInt, atPosition shift: Int = 0) -> BigUInt {
var result = self
result.subtract(b, atPosition: shift)
return result
}
/// Decrement this integer by one.
///
/// - Requires: !isZero
/// - Complexity: O(count)
public mutating func decrement(atPosition shift: Int = 0) {
self.subtract(1, atPosition: shift)
}
/// Subtract `b` from `a` and return the result.
///
/// - Requires: a >= b
/// - Complexity: O(a.count)
public static func -(a: BigUInt, b: BigUInt) -> BigUInt {
return a.subtracting(b)
}
/// Subtract `b` from `a` and store the result in `a`.
///
/// - Requires: a >= b
/// - Complexity: O(a.count)
public static func -=(a: inout BigUInt, b: BigUInt) {
a.subtract(b, atPosition: 0)
}
/// Subtracts rhs from `lhs`, returning the result and a `Bool` that is true iff the operation caused an arithmetic overflow.
/// Overflow is returned if and only if `lhs` is less than `rhs`, in which case the result is the twos' complement of the absolute difference.
public static func subtractWithOverflow(_ lhs: BigUInt, _ rhs: BigUInt) -> (BigUInt, overflow: Bool) {
return lhs.subtractingWithOverflow(rhs)
}
}