问题描述
采用以下代码:
NSError *error;
NSString *myJSONString = @"{ \"foo\" : 0.1}";
NSData *jsonData = [myJSONString dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *results = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error];
我的问题是,results[@"foo"]
是NSDecimalNumber还是二进制或浮点数等有限二进制精度的东西?基本上,我的应用程序要求NSDecimalNumber
附带的无损精度,并且需要确保JSON反序列化不会由于double/floats等而导致舍入.
My question is, is results[@"foo"]
an NSDecimalNumber, or something with finite binary precision like a double or float? Basically, I have an application that requires the lossless accuracy that comes with an NSDecimalNumber
, and need to ensure that the JSON deserialization doesn't result in rounding because of doubles/floats etcetera.
例如如果将其解释为浮点数,那么我会遇到这样的问题:
E.g. if it was interpreted as a float, I'd run into problems like this with precision:
float baz = 0.1;
NSLog(@"baz: %.20f", baz);
// prints baz: 0.10000000149011611938
我尝试将foo
解释为NSDecimalNumber并打印结果:
I've tried interpreting foo
as an NSDecimalNumber and printing the result:
NSDecimalNumber *fooAsDecimal = results[@"foo"];
NSLog(@"fooAsDecimal: %@", [fooAsDecimal stringValue]);
// prints fooAsDecimal: 0.1
但是后来我发现在NSDecimalNumber
上调用stringValue
并不会打印所有有效数字,例如...
But then I found that calling stringValue
on an NSDecimalNumber
doesn't print all significant digits anyway, e.g...
NSDecimalNumber *barDecimal = [NSDecimalNumber decimalNumberWithString:@"0.1000000000000000000000000000000000000000000011"];
NSLog(@"barDecimal: %@", barDecimal);
// prints barDecimal: 0.1
...因此打印fooAsDecimal
不会告诉我results[@"foo"]
是否在某些时候被JSON解析器四舍五入到了有限精度.
...so printing fooAsDecimal
doesn't tell me whether results[@"foo"]
was at some point rounded to finite precision by the JSON parser or not.
要清楚,我意识到我可以在JSON表示中使用字符串而不是数字来存储foo的值,即"0.1"
而不是0.1
,然后使用[NSDecimalNumber decimalNumberWithString:results[@"foo"]
].但是,我感兴趣的是NSJSONSerialization类如何反序列化JSON数字,因此我知道这是否真的必要.
To be clear, I realise I could use a string rather than a number in the JSON representation to store the value of foo, i.e. "0.1"
instead of 0.1
, and then use [NSDecimalNumber decimalNumberWithString:results[@"foo"]
]. But, what I'm interested in is how the NSJSONSerialization class deserializes JSON numbers, so I know whether this is really necessary or not.
推荐答案
NSJSONSerialization
(在Swift中为JSONSerialization
)遵循以下常规模式:
NSJSONSerialization
(and JSONSerialization
in Swift) follow the general pattern:
- 如果数字只有整数部分(无小数或指数),请尝试将其解析为
long long
.如果没有溢出,请返回带有long long
的NSNumber
. - 尝试使用
strtod_l
解析双精度型.如果没有溢出,请返回带有double
的NSNumber
. - 在所有其他情况下,请尝试使用
NSDecimalNumber
来支持更大范围的值,特别是尾数最多为38位,指数在-128 ... 127之间.
- If a number has only an integer part (no decimal or exponent), attempt to parse it as a
long long
. If that doesn't overflow, return anNSNumber
withlong long
. - Attempt to parse a double with
strtod_l
. If it doesn't overflow, return anNSNumber
withdouble
. - In all other cases, attempt to use
NSDecimalNumber
which supports a much larger range of values, specifically a mantissa up to 38 digits and exponent between -128...127.
如果您查看其他人张贴的示例,您会看到,当值超出double
的范围或精度时,您会得到NSDecimalNumber
.
If you look at other examples people have posted you can see that when the value exceeds the range or precision of a double
you get an NSDecimalNumber
back.
这篇关于NSJSONSerialization是否将数字反序列化为NSDecimalNumber?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!