NSDecimalNumber 和大的无符号长长(64 位)整数

Posted

技术标签:

【中文标题】NSDecimalNumber 和大的无符号长长(64 位)整数【英文标题】:NSDecimalNumber and large unsigned long long (64-bit) integers 【发布时间】:2011-07-15 16:49:33 【问题描述】:

我正在处理来自 JSON 源的大型 64 位无符号整数,这些整数被解析为 NSDecimalNumbers,这显然是为了“忠实地表示任意精度的数字”。

我遇到的问题是我无法从这门课中得到正确的数字。例如(使用可能的最大值):

print (unsigned long long) [[NSDecimalNumber decimalNumberWithString:@"18446744073709551615"] unsignedLongLongValue]
= 0 // Incorrect
print (unsigned long long) [[NSDecimalNumber decimalNumberWithString:@"9223372036854775808"] unsignedLongLongValue]
= 9223372036854775808 // Correct
print (unsigned long long) [[NSDecimalNumber decimalNumberWithString:@"9223372036854775810"] unsignedLongLongValue]
= 9223372036854775808 // Incorrect

看起来我无法从 NSDecimalNumber 中得到大于最大有符号 long long 值的值。它不喜欢大于 9223372036854775808 的值。但是,该数字似乎以全精度存储在 NSDecimalNumber 中,如下所示:

po [[NSDecimalNumber decimalNumberWithString:@"18446744073709551615"] stringValue]
= 18446744073709551615

我注意到 NSNumber 对象可以很好地处理这些大数字,并且 unsignedLongLongValue 可以正常工作。只是 NSDecimalNumbers(我坚持使用)不起作用。

如何从 NSDecimalNumbers 中获取正确的 unsigned long long 值?或者至少将它们转换为 unsignedLongLongValue 工作的 NSNumber 对象。

【问题讨论】:

【参考方案1】:

我通过开发者论坛收到了 Apple 对此问题的回复:

这是 NSDecimalNumber 的一个长期存在的问题,其中简单的 访问器(例如 [unsigned]longLongValue)通过 doubleValue 访问器——任何需要超过 53 位精度的值 将被不恰当地四舍五入。随时报告有关此的错误 发布并提及错误号 8220543。

也就是说,如果你只是 从 JSON 获取 64 位数字,您应该可以使用 NSNumber 而不是 NSDecimalNumber。

所以我通过将解析器从 SBJson 更改为 JSONKit 来解决这个问题,这不仅更快,而且还将数字映射到 NSNumber 对象而不是 NSDecimalNumber 对象。

【讨论】:

不知道ios 5 的 NSJSONSerialization 类是否仍然存在这个问题? 它确实完全保留在 iOS 5 的 NSJSONSerialization 中! o_O 似乎 Apple 仍然没有修复 OSX 10.9.2 中的这个错误 :(【参考方案2】:

如果您仍想从 NSDecimalNumber 中提取 unsigned long long 值,您可以使用 johne here 建议的方法并执行以下操作:

NSDecimalNumber *testNumber = [NSDecimalNumber decimalNumberWithString:@"18446744073709551615"];
unsigned long long ullvalue = strtoull([[testNumber stringValue] UTF8String], NULL, 0);
NSLog(@"Number:%llu", ullvalue);

产生正确的结果

编号:18446744073709551615

我尝试使用 NSScanner 来做到这一点:

NSScanner *theScanner = [[NSScanner alloc] initWithString:[testNumber stringValue]];
unsigned long long outputValue;

[theScanner scanLongLong:(long long *)&outputValue];
[theScanner release];

但不幸的是,它只读取有符号的 long long 值,所以上面给出了错误的值 9223372036854775807。

【讨论】:

感谢您的建议,如果您遇到 NSDecimalNumbers 问题,这是个好主意!

以上是关于NSDecimalNumber 和大的无符号长长(64 位)整数的主要内容,如果未能解决你的问题,请参考以下文章

C中的无符号整数在java中的处理

整数的无符号编码和有符号编码

从蓝牙低功耗 GATT 特性中检索大的 32 位无符号整数

NSDecimalNumber 和从末尾弹出数字

为啥有符号负数转换为无符号数?

数据库,主键为何不宜太长长长长长长长长?