NSNumber使用舍入/截断的小数位数加倍 [英] NSNumber double with many decimal places being rounded/truncated
问题描述
我在 NSNumber
中有一个 double
。
double myDouble = 1363395572.6129999;
NSNumber *doubleNumber = @(myDouble);
// using [NSNumber numberWithDouble:myDouble] leads to the same result
这是哪里它有问题。
doubleNumber.doubleValue
似乎返回正确的值和完整值( 1363395572.6129999)
doubleNumber.doubleValue
seems to return the correct and full value (1363395572.6129999)
但是,在调试器中查看 doubleNumber
或执行 doubleNumber.description
给我(1363395572.613)
。
However, looking at doubleNumber
in the debugger or doing doubleNumber.description
gives me (1363395572.613)
.
我会理解如果这可能只是一些显示格式,但是当我将这个对象粘贴到JSON有效载荷中时,插入的乱码值将被插入而不是实际的数字。
I would understand if perhaps this was just some display formatting, but when I then stick this object into a JSON payload, the messed up rounded value gets inserted instead of the actual number.
我这样做的方式是这样的:
The way I'm doing this is something like this:
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:(Dictionary containing NSNumber)
options:0 error:nil];
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
此时查看字符串会显示截断的数字,其中包含3位小数,即使 NSNumber
我插入了7。
Looking at the string at this point shows me the truncated number with 3 decimal places even though the NSNumber
I inserted had 7.
我的问题是为什么会发生这种情况,更重要的是如何阻止它发生?
My question is why is this happening and more importantly how can I stop it from happening?
编辑结论:
对于任何偶然发现此问题的人,问题我从一开始就不清楚,但实际问题是 NSNumber
和 double
都无法持有数字我正在寻找的那种精确度。正如Martin的回答所示,我的问题是在我从JSON响应中反序列化初始数值时发生的。
For anyone who stumbles onto this, the problem was not clear to me from the beginning but the actual issue is that NSNumber
and double
are both incapable of holding a number with the sort of precision I am looking for. As Martin's answer shows, my problem occurred as soon as I deserialized the initial number values from a JSON response.
我最终通过将整个系统重新处理来解决我的问题取决于客户端上这些数字的精度级别(因为这些是时间戳,微秒),而是使用不同的标识符来传递API。
I ended up working around my problem by reworking the whole system to stop depending on this level of precision(since these are timestamps, microseconds) of these numbers on the client, and instead use a different identifier to pass around with the API.
正如Martin和Leo指出的那样,为了解决这个问题,需要使用一个自定义JSON解析器,它允许将JSON数解析为 NSDecimalNumber
而不是 NSNumber
。特别是我在上一段中概述的问题更好的解决方案,所以我没有采用这条路线。
As Martin and Leo pointed out, in order to get around this problem one would need to use a custom JSON parser that allows parsing of a JSON number into an NSDecimalNumber
rather than an NSNumber
. A better solution to my problem in particular was what I outlined in the previous paragraph, so I did not pursue this route.
推荐答案
正如上面的评论所述, double
的精度约为16位十进制
位数。 1363395572.612999
有17位数字,将此十进制数字
转换为 double
可获得与 1363395572.613
:
As already said in above comments, the precision of double
is about 16 decimal
digits. 1363395572.612999
has 17 digits, and converting this decimal number
to double
gives exactly the same results as for 1363395572.613
:
double myDouble = 1363395572.6129999;
double myDouble1 = 1363395572.613;
NSLog(@"%.20f", myDouble); // 1363395572.61299991607666015625
NSLog(@"%.20f", myDouble1); // 1363395572.61299991607666015625
NSLog(@"%s", myDouble == myDouble1 ? "equal" : "different"); // equal
因此,在精度范围内
,输出 1363395572.613
正确。
如果你的目标是准确发送数字1363395572.6129999然后你不能
首先将它存储在 double
中,因为它已经失去了精度。
一个可能的解决方案是使用 NSDecimalNumber
(其精度
为38位小数):
If your goal is to send precisely the number "1363395572.6129999" then you cannot
store it in a double
first because that already looses the precision.
A possible solution would be to use NSDecimalNumber
(which has a precision
of 38 decimal digits):
NSDecimalNumber *doubleNumber = [NSDecimalNumber decimalNumberWithString:@"1363395572.6129999"];
NSDictionary *dict = @{@"key": doubleNumber};
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict
options:0 error:nil];
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
// {"key":1363395572.6129999}
示例long double
和 NSDecimalNumber
:
long double ld1 = 1363395572.6129999L;
long double ld2 = 1363395572.613L;
NSDecimalNumber *num1 = [NSDecimalNumber decimalNumberWithString:[NSString stringWithFormat:@"%.7Lf", ld1]];
NSDecimalNumber *num2 = [NSDecimalNumber decimalNumberWithString:[NSString stringWithFormat:@"%.7Lf", ld2]];
NSDictionary *dict = @{@"key1": num1, @"key2": num2};
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict
options:0 error:nil];
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
// {"key1":1363395572.6129999,"key2":1363395572.613}
更新:正如在讨论中发现的那样,当从服务器发送的JSON对象中读取数据
时,问题就出现了。以下示例显示
NSJSONSerialization
无法从JSON数据中读取超过
double精度的浮点数:
Update: As it turned out in the discussion, the problem occurs already when the data
is read from a JSON object sent by a server. The following example shows that
NSJSONSerialization
is not able to read floating point numbers with more than
"double" precision from JSON data:
NSString *jsonString = @"{\"key1\":1363395572.6129999,\"key2\":1363395572.613}";
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *dict2 = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:NULL];
NSNumber *n1 = dict2[@"key1"];
NSNumber *n2 = dict2[@"key2"];
BOOL b = [n1 isEqualTo:n2]; // YES
这篇关于NSNumber使用舍入/截断的小数位数加倍的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!