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

Mic*_*all 14 cocoa objective-c

我正在处理来自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
Run Code Online (Sandbox Code Playgroud)

看起来我无法获得大于NSDecimalNumber中最大签名long long值的任何值.它不喜欢大于9223372036854775808的值.但是看起来这个数字是以NSDecimalNumber中的完整精度存储的,如:

po [[NSDecimalNumber decimalNumberWithString:@"18446744073709551615"] stringValue]
= 18446744073709551615
Run Code Online (Sandbox Code Playgroud)

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

如何从NSDecimalNumbers中获取正确的无符号long long值?或者至少将它们转换为unsignedLongLongValue可以工作的NSNumber对象.

Mic*_*all 11

我通过开发人员论坛得到了Apple对此问题的回复:

这是NSDecimalNumber的常见问题,其中简单访问器(例如[unsigned] longLongValue)通过doubleValue访问器 - 这个需要超过53位精度的任何值都将被不适当地舍入.请随时报告有关此问题的错误,并提及错误号8220543.

也就是说,如果您只是从JSON获取64位数字,您应该能够使用NSNumber而不是NSDecimalNumber.

所以我通过将解析器从SBJson更改为JSONKit来解决它,这不仅快得多,它还将数字映射到NSNumber对象而不是NSDecimalNumber对象.


Bra*_*son 6

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

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

这产生了正确的结果

编号:18446744073709551615

我尝试使用NSScanner执行此操作:

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

[theScanner scanLongLong:(long long *)&outputValue];
[theScanner release];
Run Code Online (Sandbox Code Playgroud)

但不幸的是,它只读取有符号的长long值,因此上面给出的值不正确9223372036854775807.