NSNumber使用舍入/截断的小数位数加倍 [英] NSNumber double with many decimal places being rounded/truncated

查看:127
本文介绍了NSNumber使用舍入/截断的小数位数加倍的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆