WordsAndBits.swift 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. //
  2. // WordsAndBits.swift
  3. // CS.BigInt
  4. //
  5. // Created by Károly Lőrentey on 2017-08-11.
  6. // Copyright © 2016-2017 Károly Lőrentey.
  7. //
  8. extension Array where Element == UInt {
  9. mutating func twosComplement() {
  10. var increment = true
  11. for i in 0 ..< self.count {
  12. if increment {
  13. (self[i], increment) = (~self[i]).addingReportingOverflow(1)
  14. }
  15. else {
  16. self[i] = ~self[i]
  17. }
  18. }
  19. }
  20. }
  21. extension CS.BigUInt {
  22. public subscript(bitAt index: Int) -> Bool {
  23. get {
  24. precondition(index >= 0)
  25. let (i, j) = index.quotientAndRemainder(dividingBy: Word.bitWidth)
  26. return self[i] & (1 << j) != 0
  27. }
  28. set {
  29. precondition(index >= 0)
  30. let (i, j) = index.quotientAndRemainder(dividingBy: Word.bitWidth)
  31. if newValue {
  32. self[i] |= 1 << j
  33. }
  34. else {
  35. self[i] &= ~(1 << j)
  36. }
  37. }
  38. }
  39. }
  40. extension CS.BigUInt {
  41. /// The minimum number of bits required to represent this integer in binary.
  42. ///
  43. /// - Returns: floor(log2(2 * self + 1))
  44. /// - Complexity: O(1)
  45. public var bitWidth: Int {
  46. guard count > 0 else { return 0 }
  47. return count * Word.bitWidth - self[count - 1].leadingZeroBitCount
  48. }
  49. /// The number of leading zero bits in the binary representation of this integer in base `2^(Word.bitWidth)`.
  50. /// This is useful when you need to normalize a `BigUInt` such that the top bit of its most significant word is 1.
  51. ///
  52. /// - Note: 0 is considered to have zero leading zero bits.
  53. /// - Returns: A value in `0...(Word.bitWidth - 1)`.
  54. /// - SeeAlso: width
  55. /// - Complexity: O(1)
  56. public var leadingZeroBitCount: Int {
  57. guard count > 0 else { return 0 }
  58. return self[count - 1].leadingZeroBitCount
  59. }
  60. /// The number of trailing zero bits in the binary representation of this integer.
  61. ///
  62. /// - Note: 0 is considered to have zero trailing zero bits.
  63. /// - Returns: A value in `0...width`.
  64. /// - Complexity: O(count)
  65. public var trailingZeroBitCount: Int {
  66. guard count > 0 else { return 0 }
  67. let i = self.words.firstIndex { $0 != 0 }!
  68. return i * Word.bitWidth + self[i].trailingZeroBitCount
  69. }
  70. }
  71. extension CS.BigInt {
  72. public var bitWidth: Int {
  73. guard !magnitude.isZero else { return 0 }
  74. return magnitude.bitWidth + 1
  75. }
  76. public var trailingZeroBitCount: Int {
  77. // Amazingly, this works fine for negative numbers
  78. return magnitude.trailingZeroBitCount
  79. }
  80. }
  81. extension CS.BigUInt {
  82. public struct Words: RandomAccessCollection {
  83. private let value: CS.BigUInt
  84. fileprivate init(_ value: CS.BigUInt) { self.value = value }
  85. public var startIndex: Int { return 0 }
  86. public var endIndex: Int { return value.count }
  87. public subscript(_ index: Int) -> Word {
  88. return value[index]
  89. }
  90. }
  91. public var words: Words { return Words(self) }
  92. public init<Words: Sequence>(words: Words) where Words.Element == Word {
  93. let uc = words.underestimatedCount
  94. if uc > 2 {
  95. self.init(words: Array(words))
  96. }
  97. else {
  98. var it = words.makeIterator()
  99. guard let w0 = it.next() else {
  100. self.init()
  101. return
  102. }
  103. guard let w1 = it.next() else {
  104. self.init(word: w0)
  105. return
  106. }
  107. if let w2 = it.next() {
  108. var words: [UInt] = []
  109. words.reserveCapacity(Swift.max(3, uc))
  110. words.append(w0)
  111. words.append(w1)
  112. words.append(w2)
  113. while let word = it.next() {
  114. words.append(word)
  115. }
  116. self.init(words: words)
  117. }
  118. else {
  119. self.init(low: w0, high: w1)
  120. }
  121. }
  122. }
  123. }
  124. extension CS.BigInt {
  125. public struct Words: RandomAccessCollection {
  126. public typealias Indices = CountableRange<Int>
  127. private let value: CS.BigInt
  128. private let decrementLimit: Int
  129. fileprivate init(_ value: CS.BigInt) {
  130. self.value = value
  131. switch value.sign {
  132. case .plus:
  133. self.decrementLimit = 0
  134. case .minus:
  135. assert(!value.magnitude.isZero)
  136. self.decrementLimit = value.magnitude.words.firstIndex(where: { $0 != 0 })!
  137. }
  138. }
  139. public var count: Int {
  140. switch value.sign {
  141. case .plus:
  142. if let high = value.magnitude.words.last, high >> (Word.bitWidth - 1) != 0 {
  143. return value.magnitude.count + 1
  144. }
  145. return value.magnitude.count
  146. case .minus:
  147. let high = value.magnitude.words.last!
  148. if high >> (Word.bitWidth - 1) != 0 {
  149. return value.magnitude.count + 1
  150. }
  151. return value.magnitude.count
  152. }
  153. }
  154. public var indices: Indices { return 0 ..< count }
  155. public var startIndex: Int { return 0 }
  156. public var endIndex: Int { return count }
  157. public subscript(_ index: Int) -> UInt {
  158. // Note that indices above `endIndex` are accepted.
  159. if value.sign == .plus {
  160. return value.magnitude[index]
  161. }
  162. if index <= decrementLimit {
  163. return ~(value.magnitude[index] &- 1)
  164. }
  165. return ~value.magnitude[index]
  166. }
  167. }
  168. public var words: Words {
  169. return Words(self)
  170. }
  171. public init<S: Sequence>(words: S) where S.Element == Word {
  172. var words = Array(words)
  173. if (words.last ?? 0) >> (Word.bitWidth - 1) == 0 {
  174. self.init(sign: .plus, magnitude: CS.BigUInt(words: words))
  175. }
  176. else {
  177. words.twosComplement()
  178. self.init(sign: .minus, magnitude: CS.BigUInt(words: words))
  179. }
  180. }
  181. }