我有一个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
对象正确。
NSDictionary
中的值是NSDecimalNumber
是什么东西在幕后被转换为浮动?
答案 0 :(得分:2)
NSDecimalValue
不存储为double
,它是64位无符号整数尾数,基数为10的8位有符号整数指数,以及符号位。
问题是NSDecimalValue
的确切值只能表示为...... NSDecimalValue
。
您可以使用方法doubleValue
获得大约64位IEE754值。
当您尝试使用longLongValue
时,您可以有效地将长度为int的结果转换为IEE754的近似值。
您可能会或可能不会将其视为NSDecimalValue
实施中的错误(并最终提交雷达并要求Apple使用其他转换例程)。但严格来说,这不是一个错误:它是一个设计决定。
您应该将NSDecimalValue
视为一种浮点小数。事实上,它与IEEE754称之为扩展精度浮点十进制数的软件实现非常相似,只是它不符合该定义(因为它没有指数)至少支持-6143和+6144之间的值,因为它不支持NANs和infinites。)
换句话说,它不是整数的扩展实现,它是double的扩展(但缺少NAN和infinites)实现。事实上,Apple本身只提供了对double
的近似转换(暗示转换为long long int可能对于任何超过53位精度的值都是精确的),这不是错误。
您可能希望也可能不希望自己实施不同的转换(使用类别)。
另一种可能的观点是将问题视为您使用的JSon实现中的错误。但这也是值得商榷的:它给了你一个NSDecimalValue
,这可以说是一个正确的表述。您使用NSDecimalValue
或操作负责对其进行任何转换。
答案 1 :(得分: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"]]
可能更可靠,因为您的应用支持多个区域设置。
答案 2 :(得分:0)
对于有兴趣快速解决问题的人,按照模拟文件正确答案:
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:
82040646385235770982014-04-16 14:22:02.998 Tutorial4 [97950:303]某些数字NSNumber:
82040646385235770982014-04-16 14:22:02.998 Tutorial4 [97950:303] Dict:{someValue = 8204064638523577098; }
2014-04-16 14:22:02.998 Tutorial4 [97950:303] dict中的一些数字:
82040646385235770982014-04-16 14:22:02.999 Tutorial4 [97950:303] dict中的一些数字 lld:8204064638523577344
2014-04-16 14:22:02.999 Tutorial4 [97950:303]正确解析lld:
8204064638523577098