Проблема преобразования NSDecimalNumber в UInt64 - PullRequest
0 голосов
/ 20 сентября 2018

У меня есть реализация функции:

func number(for cof: UInt8, limit: UInt64) -> UInt64 {
    let decimalResult = (1 + Decimal(cof)/255) * Decimal(limit) / 1000
    return NSDecimalNumber(decimal: decimalResult).uint64Value
}

После использования этой функции с 0 cof:

number(for: 0, gasLimit: 21000) // Result is 21

Но когда я вызываю функцию с другой cof value.

number(for: 128, gasLimit: 21000) // Result is 0 

После отладки для значения 128 cof.

Я обнаружил, что

 let decimalResult = (1 + Decimal(gasPriceCoef)/255) * Decimal(gasLimit) / 1000 // Result is 31.5411764705882352941176470588235294116

И проблема в том, что когда я преобразую десятичное значение вUInt64 я получаю 0

Ответы [ 2 ]

0 голосов
/ 20 сентября 2018

uint64Value является свойством NSNumber, и оно недостаточно документировано применительно к NSDecimalNumber.

Но, насколько я тестировал, когда часть мантиссы превышает диапазон UInt64 возвращает 0.Например, 31.5411764705882352941176470588235294116 представляется как 315411764705882352941176470588235294116 × 10 ^ (- 38) в NSDecimalNumber, а 315411764705882352941176470588235294116 больше UInt64.max.(* 1)

Чтобы избежать такого поведения (* 2), вы можете округлить десятичное значение перед преобразованием его в UInt64.

func number(for cof: UInt8, limit: UInt64) -> UInt64 {
    var decimalResult = (1 + Decimal(cof)/255) * Decimal(limit) / 1000
    var roundedResult = Decimal()
    NSDecimalRound(&roundedResult, &decimalResult, 0, NSDecimalNumber.RoundingMode.plain)
    return NSDecimalNumber(decimal:  roundedResult).uint64Value
}
print(number(for: 128, limit: 21000)) //->32

(* 1) Actualповедение кажется немного более сложным, см. более короткие примеры в комментарии Мартина Р.

(* 2) Это поведение определенно является ошибкой, однажды помеченной как RESOLVED.Смотрите также другой комментарий Мартина Р. выше.

0 голосов
/ 20 сентября 2018

Это потому, что десятичное значение не является целым числом, и unint64Value не будет работать с этим.Вы всегда можете просто использовать примитивы -

let result = (1 + Double(cof) / 255) * Double(limit) / 1000
return UInt64(result)

Это возвращает правильный результат (31) на детской площадке

...