NSDecimalNumber 到 UInt64 的转换问题

NSDecimalNumber to UInt64 conversion issue

我已经实现了以下功能:

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 值调用函数时。

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

为 128 cof 值进行调试。

我发现

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

问题是,当我将 Decimal 值转换为 UInt64 时,我收到 0

这是因为 Decimal 值不是整数,& unint64Value 无法使用它。你总是可以只使用原语 -

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

这个 returns 操场上的正确结果 (31)

uint64ValueNSNumber 的 属性,应用于 NSDecimalNumber.

时没有详细记录

但据我测试,当尾数部分超出UInt64的范围时,它returns 0。例如31.5411764705882352941176470588235294116NSDecimalNumber中表示为315411764705882352941176470588235294116×10^(-38),而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) 实际行为似乎有点复杂,请参阅上面 Martin R 评论中的较短的示例

(*2) 一旦标记为已解决,此行为绝对是一个错误。另见上面 Martin R 的另一条评论。