3

我有一个 NSDictionary,其中包含一个值为 4937446359977427944 的键。我尝试将它的值作为 long long 并得到 4937446359977427968 回来?

NSLog(@"value1 = %@", [dict objectForKey"MyKey"]); // prints 4937446359977427944 

long long lv = [dict objectForKey:@"MyKey"] longLongValue];

NSLog(@"value2 = %lld", lv); // prints 4937446359977427968

正在做:

NSLog(@"%lld", [@"4937446359977427944" longLongValue]); // prints 4937446359977427944

我假设这是某种舍入问题,因为低位似乎已被清除,我只是不知道如何阻止它(或为什么会发生)。

正在使用创建字典,NSJSONSerialization并且 JSON 对象确实(正确地)包含一个"MyKey": 4937446359977427944条目并且该dict对象是正确的。

中保存的值NSDictionaryNSDecimalNumber

有什么东西在幕后被转换成花车吗?

4

3 回答 3

2

NSDecimalValue不存储为double,它是一个 64 位无符号整数尾数、一个以 10 为底的 8 位有符号整数指数和一个符号位。

问题是 an 的精确值NSDecimalValue只能表示为 ... an NSDecimalValue

您可以使用 method 获得大约 64 位的 IEE754 值doubleValue

当您尝试使用时,longLongValue您可以有效地获得转换为 long long int 的近似 IEE754 值的结果。

您可能会或可能不会认为它是实现中的错误NSDecimalValue(并最终提交雷达并要求 Apple 使用不同的转换例程)。但严格来说,这不是一个错误:这是一个设计决策。

您应该将其NSDecimalValue视为一种浮点小数。事实上,它与 IEEE754 称为扩展精度浮点十进制数的软件实现非常相似,只是它不符合该定义(因为它没有支持至少介于 -6143 和 +6144 之间的值的指数和因为它不支持 NAN 和无限)。

换句话说,它不是整数的扩展实现,它是双精度的扩展(但缺少 NAN 和无限)实现。Apple 本机仅提供近似转换double(意味着对于超过 53 位精度的任何值,到 long long int 的转换可能准确也可能不准确)这一事实不是错误。

您可能希望也可能不希望自己(使用类别)实施不同的转换。

另一种可能的观点是认为问题是您使用的 JSon 实现中的错误。但这也是值得商榷的:它给了你一个NSDecimalValue可以说是正确的表示。要么您使用 the 进行操作,要么您NSDecimalValue对它任何转换负责。

于 2012-09-14T09:14:10.327 回答
1

我不确定您是否对简单的解决方案感兴趣,或者只是研究导致精度损失的原因的细节。

如果您对一个简单的答案感兴趣:-[NSDecimalNumber description]将字符串与值相乘,-[NSString longLongValue]并将字符串转换为long long

NSDecimalNumber *decimalNumber = [NSDecimalNumber decimalNumberWithString:@"4937446359977427944"];
long long longLongNumber = [[decimalNumber description] longLongValue];
NSLog(@"decimalNumber %@ -- longLongNumber %lld", decimalNumber, longLongNumber);

输出

2014-04-16 08:51:21.221 APP_NAME[30458:60b] decimalNumber 4937446359977427944 -- longLongNumber 4937446359977427944

最后说明

[decimalNumber descriptionWithLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]]可能更可靠的是您的应用程序支持多个语言环境。

于 2014-04-16T12:56:39.633 回答
0

对于任何有兴趣快速解决问题的人,根据 Analog File 正确答案:

long long someNumber = 8204064638523577098;
NSLog(@"some number lld:               %lld", someNumber);
NSNumber *snNSNumber = [NSNumber numberWithLongLong:someNumber];
NSLog(@"some number NSNumber:          %@", snNSNumber);
NSString *someJson = @"{\"someValue\":8204064638523577098}";
NSDictionary* dict = [NSJSONSerialization
 JSONObjectWithData:[someJson dataUsingEncoding:NSUTF8StringEncoding]
 options:0
 error:nil];
NSLog(@"Dict: %@", dict);
NSLog(@"Some digit out of dict:        %@", [dict objectForKey:@"someValue"]);
NSLog(@"Some digit out of dict as lld: %lld", [[dict objectForKey:@"someValue"] longLongValue]);
long long someNumberParsed;
sscanf([[[dict objectForKey:@"someValue"] stringValue] UTF8String], "%lld", &someNumberParsed);
NSLog(@"Properly parsed lld:           %lld", someNumberParsed);

结果是:

2014-04-16 14:22:02.997 Tutorial4[97950:303] 一些号码 lld:
8204064638523577098

2014-04-16 14:22:02.998 Tutorial4[97950:303] 一些数字 NSNumber:
8204064638523577098

2014-04-16 14:22:02.998 Tutorial4[97950:303] 字典:{ someValue = 8204064638523577098; }

2014-04-16 14:22:02.998 Tutorial4[97950:303] 一些数字超出字典:
8204064638523577098

2014-04-16 14:22:02.999 Tutorial4[97950:303] 一些数字超出 dict 作为 lld:8204064638523577344

2014-04-16 14:22:02.999 Tutorial4[97950:303] 正确解析 lld:
8204064638523577098

于 2014-04-16T12:34:03.530 回答