gpt4 book ai didi

ios - NSNumber double 有许多小数位被四舍五入/截断

转载 作者:可可西里 更新时间:2023-11-01 05:02:46 29 4
gpt4 key购买 nike

我在 NSNumber 中有一个 double

double myDouble = 1363395572.6129999;

NSNumber *doubleNumber = @(myDouble);
// using [NSNumber numberWithDouble:myDouble] leads to the same result

这就是问题所在。

doubleNumber.doubleValue 似乎返回正确且完整的值 (1363395572.6129999)

但是,在调试器中查看 doubleNumber 或执行 doubleNumber.description 会得到 (1363395572.613)

如果这可能只是某种显示格式,我会理解,但是当我将此对象粘贴到 JSON 负载中时,插入的是乱七八糟的舍入值而不是实际数字。

我这样做的方式是这样的:

NSData *jsonData = [NSJSONSerialization dataWithJSONObject:(Dictionary containing NSNumber)
options:0 error:nil];

NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];

即使我插入的 NSNumber 有 7,此时查看字符串会显示截断后的数字,小数点后 3 位。

我的问题是为什么会发生这种情况,更重要的是我怎样才能阻止它发生?

编辑结论:

对于任何偶然发现这个问题的人,从一开始我就不清楚这个问题,但实际问题是 NSNumberdouble 都不能保存数字以我正在寻找的那种精确度。正如 Martin 的回答所示,当我从 JSON 响应中反序列化初始数值时,我的问题就出现了。

我最终通过重新设计整个系统来解决我的问题,以根据客户端上这些数字的这种精度级别(因为这些是时间戳,微秒)停止,而是使用不同的标识符来传递 API .

正如 Martin 和 Leo 指出的那样,为了解决这个问题,需要使用自定义 JSON 解析器,它允许将 JSON 数字解析为 NSDecimalNumber 而不是 NSNumber 。我在上一段中概述了特别针对我的问题的更好解决方案,因此我没有采用这条路线。

最佳答案

正如上面评论中所说,double 的精度大约是小数点后 16 位数字。 1363395572.612999有17位数字,将这个十进制数转换double 给出与 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

因此,在double精度内,输出1363395572.613正确

如果您的目标是准确发送号码“1363395572.6129999”,那么您不能首先将它存储在 double 中,因为这已经失去了精度。一个可能的解决方案是使用 NSDecimalNumber(它有一个精度38 位十进制数):

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 doubleNSDecimalNumber 示例:

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 无法读取大于等于的 float 来自 JSON 数据的“ double ”:

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

关于ios - NSNumber double 有许多小数位被四舍五入/截断,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23019338/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com