Как преобразовать NSDecimalNumber в байтовый массив, если NSDecimalNumber больше, чем Uint64? - PullRequest
0 голосов
/ 07 декабря 2018

Я хочу преобразовать NSDecimalNumber в байтовый массив.Кроме того, я не хочу использовать какую-либо библиотеку для этого, как BigInt, BInt и т. Д.

Я попробовал это:

static func toByteArray<T>(_ value: T) -> [UInt8] {
    var value = value
    return withUnsafeBytes(of: &value) { Array($0) }
}
let value =  NSDecimalNumber(string: "...")
let bytes = toByteArray(value.uint64Value)

Если число не больше Uint64, оно работаетотличный.Но что, если это так, как мы можем преобразовать это?

Ответы [ 2 ]

0 голосов
/ 07 декабря 2018

Проблема, очевидно, заключается в использовании uint64Value, которое, очевидно, не может представлять любое значение больше UInt64.max, и ваш пример, 59 785 897 542 892 656 787 456, больше этого.

Если вы хотите захватить байтпредставления 128-битной мантиссы, вы можете использовать _mantissa кортеж из UInt16 слов Decimal и конвертировать их в байты, если хотите.Например,

extension Decimal {
    var byteArray: [UInt8] {
        return [_mantissa.0,
                _mantissa.1,
                _mantissa.2,
                _mantissa.3,
                _mantissa.4,
                _mantissa.5,
                _mantissa.6,
                _mantissa.7]
            .flatMap { [UInt8($0 & 0xff), UInt8($0 >> 8)] }
    }
}

И

if let foo = Decimal(string: "59785897542892656787456") {
    print(foo.byteArray)
}

Возвращение:

[0, 0, 0, 0, 0, 0, 0, 0, 169,12, 0, 0, 0, 0, 0, 0]

Это, по общему признанию, только откладывает проблему, преодолев 64-битный предел вашего подхода uint64Value, но все еще ограничено128-битный предел NSDecimalNumber / Decimal.Для захвата чисел, превышающих 128 бит, вам нужно совершенно другое представление.


Примечание: это также предполагает, что показатель степени равен 0.Однако, если у вас было какое-то большое число, например, 4.2e101 (4.2 * 10 101 ), показатель степени будет 100, а мантисса будет просто 42, что, я держу пари, вероятно, не то, чтоВы хотите в своем байтовом массиве.Опять же, это пример числа, которое слишком велико, чтобы представлять его как одно целое 128-битное целое число:

if let foo = Decimal(string: "4.2e101") {
    print(foo.byteArray)
    print(foo.exponent)
}

Выход:

[42, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]100

0 голосов
/ 07 декабря 2018

Вы проходите value.uint64Value, а не value.Таким образом, число будет обернуто вокруг нуля, чтобы соответствовать NSDecimal в формате UInt64.

Передача "18446744073709551616" (которая является строкой, соответствующей UInt64.max + 1) эквивалентна передаче "0".Передача "18446744073709551617" (это строка, соответствующая UInt64.max + 2) эквивалентна передаче "1".

...