Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios NSNumber双精度数字,小数位数被舍入/截断_Ios_Objective C_Nsnumber - Fatal编程技术网

Ios NSNumber双精度数字,小数位数被舍入/截断

Ios NSNumber双精度数字,小数位数被舍入/截断,ios,objective-c,nsnumber,Ios,Objective C,Nsnumber,我有一个NSNumber中的double double myDouble = 1363395572.6129999; NSNumber *doubleNumber = @(myDouble); // using [NSNumber numberWithDouble:myDouble] leads to the same result 这就是问题所在 doubleNumber.doubleValue似乎返回正确的完整值(1363395572.6129999) 但是,在调试器中查看double

我有一个
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];
在这一点上查看字符串,可以看到带3位小数的截断数字,即使插入的
NSNumber
有7位小数

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

带结论编辑:

对于任何一个偶然发现这个问题的人来说,我从一开始就不清楚这个问题,但实际问题是
NSNumber
double
都无法以我所期望的精度保存一个数字。正如Martin的回答所示,当我从JSON响应中反序列化初始数字值时,问题就出现了

我最终解决了我的问题,重新设计了整个系统,使其不再依赖于客户机上这些数字的精度级别(因为这些是时间戳,微秒),而是使用不同的标识符与API一起传递


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

我只是尝试了一下,但似乎精度在序列化过程中丢失了,而不是在数字初始化过程中。也许JSON序列化是构建一个精确的字符串,丢失数字格式,然后从中构建数据


一种解决方案是将整数值和分数值保存在它们自己的8字节字段中。。。可能使用两个LP64长。精度部分可以乘以较大的值,然后在检索时进行除法。

我测试了以下代码:

double myDouble = 1363395572.6129999;
NSString *s = [NSString stringWithFormat:@"%.7f", myDouble];
NSLog(@"%@", s);
输出为:

1363395572.6129999

所以,在放入JSON对象之前,只需自己格式化字符串,就可以了

编辑: 如果您想要更高的精度,而不仅仅是更多地控制JSON中的内容,那么
长双精度
将存储它。因此:

long double myDouble = 1363395572.6129999;
NSString *s = [NSString stringWithFormat:@"%.7L", myDouble];
NSLog(@"%@", s);

如上所述,
double
的精度约为16位小数 数字<代码>1363395572.612999有17位数字,并转换此十进制数 to
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
的示例:

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}
NSDecimalNumber* dc = [NSDecimalNumber decimalNumberWithString:[NSString stringWithFormat:@"%.7f", myDouble]];
更新:正如在讨论中所发现的,当数据 从服务器发送的JSON对象读取。下面的示例显示
NSJSONSerialization
无法读取大于 JSON数据的“双精度”:

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

使用
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}
NSDecimalNumber* dc = [NSDecimalNumber decimalNumberWithString:[NSString stringWithFormat:@"%.7f", myDouble]];
在字典里使用这个十进制数字



如果您有一个精确的所需数字的字符串值,请直接将其输入到
NSDecimalNumber
构造函数以获得精确的十进制数。不要使用中间
double
阶段,这样会降低精度。

1363395572.612999IS是1363395572.613A
double
只能存储大约13个有效数字。
description
仅用于调试,不应使用(少数对象类型除外)要准确地反映对象的内容,需要做的一件事是制作一个[NSString stringWithFormat:@“%.7f”,myDouble],看看它是什么样子。如果您可以在将其放入JSON之前强制执行您想要的内容,那么应该可以解决问题。{EDIT:posted as answer,tested and works]@RobP-除了在JSON中输入字符串而不是数字。对于
double myDouble=1363395572.613
您会得到相同的输出
1363395572.6129999
。因此这不会“增加”精度。是的,这一点很好,但至少在这一点上,您不会受到NSJSONSerialization功能的神秘影响。我只是验证了,即使使用type
long double
(至少在64位体系结构上)这
1363395572.613==1363395572.6129999
的计算结果为真。所以这只是一个“你希望它以什么格式出现在游戏中”的问题,因为基本值是相同的……我刚刚投了赞成票。如果你对你想要的JSON有具体的想法,我仍然认为在一个代码中格式化字符串不是一个坏主意。但是如果这个问题是否为基础精度?然后是的,需要更改值的存储类型!请注意,这是一个NSString,而不是NSNumber。这是一个显著的差异。确实存在差异,但取决于JSON的位置,它不一定是坏的。是的。如果目标是发送存储在
double myDouble
中的值,则结果t“1363395572.613”是“正确的”。如果目标是发送号码“1363395572.6129999”,则不能先将其存储在
double
中。@Dima”JSON num