如果 NSDecimalNumber 大于 Uint64,如何将 NSDecimalNumber 转换为字节数组?
Posted
技术标签:
【中文标题】如果 NSDecimalNumber 大于 Uint64,如何将 NSDecimalNumber 转换为字节数组?【英文标题】:How to convert NSDecimalNumber to byte array if NSDecimalNumber is bigger than Uint64? 【发布时间】:2018-12-06 23:38:40 【问题描述】:我想将 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,则效果很好。但是,如果是的话,我们如何转换它呢?
【问题讨论】:
问题是什么,“如何将 NSDecimalNumber 转换为字节数组?”或“如果数字大于 Uint64 会发生什么?”? 我刚刚改变了问题。很抱歉造成误导。 你能举一个value
和expexted bytes
的例子吗? value
总是整数吗?
例如,如果值为“59785897542892656787456”,则该值必须为 [12, 169, 0, 0, 0, 0, 0, 0,0 ,0]。像 java 中的 new BigInteger("59785897542892656787456").toByteArray。
看看value.decimalValue
和它的_mantissa
。
【参考方案1】:
问题显然是uint64Value
的使用,它显然不能代表任何大于UInt64.max
的值,而你的例子59,785,897,542,892,656,787,456大于那个。
如果要获取 128 位尾数的字节表示,可以使用 UInt16
的 Decimal
的字组的 _mantissa
元组,并根据需要将它们转换为字节。例如
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]
诚然,这只是推迟了问题,打破了 uint64Value
方法的 64 位限制,但仍受限于 NSDecimalNumber
/Decimal
固有的 128 位限制。要捕获大于 128 位的数字,您需要完全不同的表示形式。
注意:这也假设指数是0
。但是,如果您有一些较大的数字,例如4.2e101 (4.2 * 10101),指数为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] 100
【讨论】:
【参考方案2】:您传递的是value.uint64Value
,而不是value
。因此,数字将 环绕 零,以使 NSDecimal 适合 UInt64 格式。
传递"18446744073709551616"
(也就是UInt64.max
+1对应的字符串)等价于传递"0"
。传递"18446744073709551617"
(也就是UInt64.max
+2对应的字符串)相当于传递"1"
。
【讨论】:
传递 NSDecimalNumber 不会给出正确的结果。 这回答了您的原始问题,解释了当数字大于 UInt64 时会发生什么。 抱歉误导。MemoryLayout<NSDecimalNumber>.size
是指针的大小吗? NSDecimalNumber
对象的大小无关紧要。它是一个围绕NSDecimal
(Swift 中的Decimal
)的面向对象的包装器。 NSDecimalNumber
和 NSDecimal
可以处理字符串 "18446744073709551616"
和 "18446744073709551617"
。方法uint64Value
无法将这些值转换为UInt64
。以上是关于如果 NSDecimalNumber 大于 Uint64,如何将 NSDecimalNumber 转换为字节数组?的主要内容,如果未能解决你的问题,请参考以下文章
核心数据和 iPhone 的 NSDecimalNumber 问题
从 NSDecimalNumber 中删除负号 (-) 给我一个错误