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

时间:2021-05-26 12:00:52

I'm handling large 64 bit unsigned integers from a JSON source which are being parsed into NSDecimalNumbers, which is apparently to "faithfully represent arbitrary-precision numbers".

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

The problem I'm having is that I cant get the correct numbers out of this class. For example (using the largest value possible):

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

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

It would appear that I can't get anything larger than the maximum signed long long value out of an NSDecimalNumber. It's not liking values larger than 9223372036854775808. However it seems that the number is being stored in the full precision within an NSDecimalNumber, as:

看起来我无法获得大于NSDecimalNumber中最大签名long long值的任何值。它不喜欢大于9223372036854775808的值。但是,似乎该数字以NSDecimalNumber中的完整精度存储,如下所示:

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

I've noticed that NSNumber objects can handle these large numbers fine and unsignedLongLongValue works correctly. It's just NSDecimalNumbers (which I am stuck with) which aren't working.

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

How can I get correct unsigned long long values out of NSDecimalNumbers? Or at least convert them into NSNumber objects where unsignedLongLongValue does work.

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

2 个解决方案

#1


11  

I've had a response from Apple on this issue via the developer forums:

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

This is a standing issue with NSDecimalNumber where the simple accessors (such as [unsigned]longLongValue) go through the doubleValue accessor – this any value requiring more than 53 bits of precision will be inappropriately rounded. Feel free to Report a Bug about this issue and mention bug number 8220543.

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

That said, if you are just getting 64-bit numbers from JSON, you should be able to just use NSNumber instead of NSDecimalNumber.

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

So I'm solving it by changing parser from SBJson to JSONKit, which is not only much faster, it also maps numbers into NSNumber objects instead of NSDecimalNumber objects.

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

#2


6  

If you still want to extract an unsigned long long value from an NSDecimalNumber, you could use the approach suggested by johne here and do something like the following:

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

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

which produces the proper result of

这产生了正确的结果

Number:18446744073709551615

编号:18446744073709551615

I tried to do this using an NSScanner:

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

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

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

but unfortunately, it only reads the signed long long values, so the above gives the incorrect value of 9223372036854775807.

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

#1


11  

I've had a response from Apple on this issue via the developer forums:

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

This is a standing issue with NSDecimalNumber where the simple accessors (such as [unsigned]longLongValue) go through the doubleValue accessor – this any value requiring more than 53 bits of precision will be inappropriately rounded. Feel free to Report a Bug about this issue and mention bug number 8220543.

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

That said, if you are just getting 64-bit numbers from JSON, you should be able to just use NSNumber instead of NSDecimalNumber.

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

So I'm solving it by changing parser from SBJson to JSONKit, which is not only much faster, it also maps numbers into NSNumber objects instead of NSDecimalNumber objects.

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

#2


6  

If you still want to extract an unsigned long long value from an NSDecimalNumber, you could use the approach suggested by johne here and do something like the following:

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

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

which produces the proper result of

这产生了正确的结果

Number:18446744073709551615

编号:18446744073709551615

I tried to do this using an NSScanner:

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

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

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

but unfortunately, it only reads the signed long long values, so the above gives the incorrect value of 9223372036854775807.

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