-
Notifications
You must be signed in to change notification settings - Fork 99
/
BigUInt Shifts.swift
145 lines (124 loc) · 4.21 KB
/
BigUInt Shifts.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
//
// BigUInt Shifts.swift
// BigInt
//
// Created by Károly Lőrentey on 2016-01-03.
// Copyright © 2016-2017 Károly Lőrentey.
//
extension BigUInt {
//MARK: Shift Operators
/// Shift a big integer to the right by `amount` bits and store the result in place.
///
/// - Complexity: O(count)
public static func <<= (b: inout BigUInt, amount: Int) {
typealias Digit = BigUInt.Digit
precondition(amount >= 0)
guard amount > 0 else { return }
let ext = amount / Digit.width // External shift amount (new digits)
let up = Digit(amount % Digit.width) // Internal shift amount (subdigit shift)
let down = Digit(Digit.width) - up
b.lift()
if up > 0 {
var i = 0
var lowbits: Digit = 0
while i < b.count || lowbits > 0 {
let digit = b[i]
b[i] = digit << up | lowbits
lowbits = digit >> down
i += 1
}
}
if ext > 0 && b.count > 0 {
b._digits.insert(contentsOf: Array<Digit>(repeating: 0, count: ext), at: 0)
b._end = b._digits.count
}
}
/// Shift a big integer to the left by `amount` bits and return the result.
///
/// - Returns: b * 2^amount
/// - Complexity: O(count)
public static func << (b: BigUInt, amount: Int) -> BigUInt {
typealias Digit = BigUInt.Digit
precondition(amount >= 0)
guard amount > 0 else { return b }
let ext = amount / Digit.width // External shift amount (new digits)
let up = Digit(amount % Digit.width) // Internal shift amount (subdigit shift)
let down = Digit(Digit.width) - up
var result = BigUInt()
if up > 0 {
var i = 0
var lowbits: Digit = 0
while i < b.count || lowbits > 0 {
let digit = b[i]
result[i + ext] = digit << up | lowbits
lowbits = digit >> down
i += 1
}
}
else {
for i in 0..<b.count {
result[i + ext] = b[i]
}
}
return result
}
/// Shift a big integer to the right by `amount` bits and store the result in place.
///
/// - Complexity: O(count)
public static func >>= (b: inout BigUInt, amount: Int) {
typealias Digit = BigUInt.Digit
precondition(amount >= 0)
guard amount > 0 else { return }
let ext = amount / Digit.width // External shift amount (new digits)
let down = Digit(amount % Digit.width) // Internal shift amount (subdigit shift)
let up = Digit(Digit.width) - down
if ext >= b.count {
b = BigUInt()
return
}
b.lift()
if ext > 0 {
b._digits.removeSubrange(0 ..< ext)
b._end = b._digits.count
}
if down > 0 {
var i = b.count - 1
var highbits: Digit = 0
while i >= 0 {
let digit = b[i]
b[i] = highbits | digit >> down
highbits = digit << up
i -= 1
}
b.shrink()
}
}
/// Shift a big integer to the right by `amount` bits and return the result.
///
/// - Returns: b / 2^amount
/// - Complexity: O(count)
public static func >> (b: BigUInt, amount: Int) -> BigUInt {
typealias Digit = BigUInt.Digit
precondition(amount >= 0)
guard amount > 0 else { return b }
let ext = amount / Digit.width // External shift amount (new digits)
let down = Digit(amount % Digit.width) // Internal shift amount (subdigit shift)
let up = Digit(Digit.width) - down
if ext >= b.count { return BigUInt() }
var result = BigUInt()
if down > 0 {
var highbits: Digit = 0
for i in (ext..<b.count).reversed() {
let digit = b[i]
result[i - ext] = highbits | digit >> down
highbits = digit << up
}
}
else {
for i in (ext..<b.count).reversed() {
result[i - ext] = b[i]
}
}
return result
}
}