Преобразование очень больших десятичных чисел в шестнадцатеричное в быстрой - PullRequest
0 голосов
/ 25 мая 2018

Мы можем использовать спецификатор String Format для преобразования целочисленного значения или длинного значения в шестнадцатеричное представление.

Int Example:
print(String(format:"%x", 1111))
//result:457

Long Example:        
print(String(format:"%lx", 11111111111111))
//result:a1b01d4b1c7

Но что если мы попытаемся преобразовать очень большое десятичное число, которое больше, чем uint64.max?// 18446744073709551615

Как правильно конвертировать в этом случае?

1 Ответ

0 голосов
/ 25 мая 2018

Одним из возможных решений является использование NSDecimalNumber для хранения большого значения.Но он не имеет встроенного способа преобразования числа в строку, отличную от базы 10.

Ниже приведено расширение к NSDecimalNumber, которое преобразует число в любое основание от 2 до 16.И это также включает удобство init, которое принимает строку в заданной базе.

extension NSDecimalNumber {
    convenience init(string: String, base: Int) {
        guard base >= 2 && base <= 16 else { fatalError("Invalid base") }

        let digits = "0123456789ABCDEF"
        let baseNum = NSDecimalNumber(value: base)

        var res = NSDecimalNumber(value: 0)
        for ch in string {
            let index = digits.index(of: ch)!
            let digit = digits.distance(from: digits.startIndex, to: index)
            res = res.multiplying(by: baseNum).adding(NSDecimalNumber(value: digit))
        }

        self.init(decimal: res.decimalValue)
    }

    func toBase(_ base: Int) -> String {
        guard base >= 2 && base <= 16 else { fatalError("Invalid base") }

        // Support higher bases by added more digits
        let digits = "0123456789ABCDEF"
        let rounding = NSDecimalNumberHandler(roundingMode: .down, scale: 0, raiseOnExactness: false, raiseOnOverflow: false, raiseOnUnderflow: false, raiseOnDivideByZero: false)
        let baseNum = NSDecimalNumber(value: base)

        var res = ""
        var val = self
        while val.compare(0) == .orderedDescending {
            let next = val.dividing(by: baseNum, withBehavior: rounding)
            let round = next.multiplying(by: baseNum)
            let diff = val.subtracting(round)
            let digit = diff.intValue
            let index = digits.index(digits.startIndex, offsetBy: digit)
            res.insert(digits[index], at: res.startIndex)

            val = next
        }

        return res
    }
}

Тест:

let bigNum = NSDecimalNumber(string: "18446744073709551615")
print(bigNum.toBase(16))
print(bigNum.toBase(10)) // or just print(bigNum)
print(NSDecimalNumber(string: "B7", base: 16))
print(NSDecimalNumber(string: NSDecimalNumber(string: "18446744073709551615").toBase(16), base: 16))

Вывод:

FFFFFFFFFFFFFFFFF
18446744073709551615
183
18446744073709551615

...