| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202 |
- //
- // WordsAndBits.swift
- // CS.BigInt
- //
- // Created by Károly Lőrentey on 2017-08-11.
- // Copyright © 2016-2017 Károly Lőrentey.
- //
- extension Array where Element == UInt {
- mutating func twosComplement() {
- var increment = true
- for i in 0 ..< self.count {
- if increment {
- (self[i], increment) = (~self[i]).addingReportingOverflow(1)
- }
- else {
- self[i] = ~self[i]
- }
- }
- }
- }
- extension CS.BigUInt {
- public subscript(bitAt index: Int) -> Bool {
- get {
- precondition(index >= 0)
- let (i, j) = index.quotientAndRemainder(dividingBy: Word.bitWidth)
- return self[i] & (1 << j) != 0
- }
- set {
- precondition(index >= 0)
- let (i, j) = index.quotientAndRemainder(dividingBy: Word.bitWidth)
- if newValue {
- self[i] |= 1 << j
- }
- else {
- self[i] &= ~(1 << j)
- }
- }
- }
- }
- extension CS.BigUInt {
- /// The minimum number of bits required to represent this integer in binary.
- ///
- /// - Returns: floor(log2(2 * self + 1))
- /// - Complexity: O(1)
- public var bitWidth: Int {
- guard count > 0 else { return 0 }
- return count * Word.bitWidth - self[count - 1].leadingZeroBitCount
- }
- /// The number of leading zero bits in the binary representation of this integer in base `2^(Word.bitWidth)`.
- /// This is useful when you need to normalize a `BigUInt` such that the top bit of its most significant word is 1.
- ///
- /// - Note: 0 is considered to have zero leading zero bits.
- /// - Returns: A value in `0...(Word.bitWidth - 1)`.
- /// - SeeAlso: width
- /// - Complexity: O(1)
- public var leadingZeroBitCount: Int {
- guard count > 0 else { return 0 }
- return self[count - 1].leadingZeroBitCount
- }
- /// The number of trailing zero bits in the binary representation of this integer.
- ///
- /// - Note: 0 is considered to have zero trailing zero bits.
- /// - Returns: A value in `0...width`.
- /// - Complexity: O(count)
- public var trailingZeroBitCount: Int {
- guard count > 0 else { return 0 }
- let i = self.words.firstIndex { $0 != 0 }!
- return i * Word.bitWidth + self[i].trailingZeroBitCount
- }
- }
- extension CS.BigInt {
- public var bitWidth: Int {
- guard !magnitude.isZero else { return 0 }
- return magnitude.bitWidth + 1
- }
- public var trailingZeroBitCount: Int {
- // Amazingly, this works fine for negative numbers
- return magnitude.trailingZeroBitCount
- }
- }
- extension CS.BigUInt {
- public struct Words: RandomAccessCollection {
- private let value: CS.BigUInt
- fileprivate init(_ value: CS.BigUInt) { self.value = value }
- public var startIndex: Int { return 0 }
- public var endIndex: Int { return value.count }
- public subscript(_ index: Int) -> Word {
- return value[index]
- }
- }
- public var words: Words { return Words(self) }
- public init<Words: Sequence>(words: Words) where Words.Element == Word {
- let uc = words.underestimatedCount
- if uc > 2 {
- self.init(words: Array(words))
- }
- else {
- var it = words.makeIterator()
- guard let w0 = it.next() else {
- self.init()
- return
- }
- guard let w1 = it.next() else {
- self.init(word: w0)
- return
- }
- if let w2 = it.next() {
- var words: [UInt] = []
- words.reserveCapacity(Swift.max(3, uc))
- words.append(w0)
- words.append(w1)
- words.append(w2)
- while let word = it.next() {
- words.append(word)
- }
- self.init(words: words)
- }
- else {
- self.init(low: w0, high: w1)
- }
- }
- }
- }
- extension CS.BigInt {
- public struct Words: RandomAccessCollection {
- public typealias Indices = CountableRange<Int>
- private let value: CS.BigInt
- private let decrementLimit: Int
- fileprivate init(_ value: CS.BigInt) {
- self.value = value
- switch value.sign {
- case .plus:
- self.decrementLimit = 0
- case .minus:
- assert(!value.magnitude.isZero)
- self.decrementLimit = value.magnitude.words.firstIndex(where: { $0 != 0 })!
- }
- }
- public var count: Int {
- switch value.sign {
- case .plus:
- if let high = value.magnitude.words.last, high >> (Word.bitWidth - 1) != 0 {
- return value.magnitude.count + 1
- }
- return value.magnitude.count
- case .minus:
- let high = value.magnitude.words.last!
- if high >> (Word.bitWidth - 1) != 0 {
- return value.magnitude.count + 1
- }
- return value.magnitude.count
- }
- }
- public var indices: Indices { return 0 ..< count }
- public var startIndex: Int { return 0 }
- public var endIndex: Int { return count }
- public subscript(_ index: Int) -> UInt {
- // Note that indices above `endIndex` are accepted.
- if value.sign == .plus {
- return value.magnitude[index]
- }
- if index <= decrementLimit {
- return ~(value.magnitude[index] &- 1)
- }
- return ~value.magnitude[index]
- }
- }
- public var words: Words {
- return Words(self)
- }
- public init<S: Sequence>(words: S) where S.Element == Word {
- var words = Array(words)
- if (words.last ?? 0) >> (Word.bitWidth - 1) == 0 {
- self.init(sign: .plus, magnitude: CS.BigUInt(words: words))
- }
- else {
- words.twosComplement()
- self.init(sign: .minus, magnitude: CS.BigUInt(words: words))
- }
- }
- }
|