【问题标题】:iOS: Limit precision of datatype "double" without converting to NSStringiOS:限制数据类型“double”的精度而不转换为 NSString
【发布时间】:2015-04-21 05:57:43
【问题描述】:

在这里,我想问一下 double 如何使用它们的精度。

我创建了一个示例,其中我输入了如下的双精度值:

double d = 2.0126161;
double d1 = 2.0126162;
double d2 = 2.0126163;
double d3 = 2.0126164;
double d4 = 2.0126165;

电流输出:

如果我通过在 lldb 中运行“po”命令设置断点并检查,则值显示如下:

(lldb) po d
2.0126160999999998

(lldb) po d1
2.0126162000000001

(lldb) po d2
2.0126162999999999

(lldb) po d3
2.0126164000000002

(lldb) po d4
2.0126165

我将这些双精度值分配给具有数据类型“双精度”的 CLLocation 对象的纬度和经度。

在这里,您可以看到输出,显示 d4 的“po”命令打印值“2.0126165”,这与我们明确提供给 d4 的值相同,这完全没问题,也是我想要的。

问题:

但是与我们显式传递的值相比,d、d1、d2、d3 的“po”命令的值发生了变化。

d, d1, d2, d3 值的这种变化会在涉及双倍 d, d1, d2, d3 的计算中产生差异。如果我们检查累积效应表明与我们预期的输出相比存在显着差异。

我不想将值四舍五入到特定的小数位数,因为值因值而异。

如何让 d、d1、d2、d3 具有与显式初始化时相同的值,而不使用数据类型 double 更改精度(检查下面的预期输出)?

预期输出:

(lldb) po d
2.0126161

(lldb) po d1
2.0126162

(lldb) po d2
2.0126163

(lldb) po d3
2.0126164

(lldb) po d4
2.0126165

注意:请注意我不想在屏幕上显示这个值,我使用这些双精度值进行数学计算,所以没有必要通过传递“转换为 NSString” %.7f" 作为 NSString 的格式说明符。

【问题讨论】:

  • 差异有多大?假设 double 是 IEEE 754 64 位二进制浮点,在简单的转换中,舍入误差将不超过 2^53 的一部分。在纬度和经度的背景下,基本的舍入误差约为百万分之一英寸。你确定你不能容忍差异,而只是为了展示而四舍五入?
  • @PatriciaShanahan:是的,这种计算的累积效应导致我们发现地图上点的投影存在显着差异。
  • 精确到小数位数还是双倍计算哪个更准确?
  • @PatriciaShanahan:在我的情况下,计算到小数点后会得到更准确的结果。

标签: ios objective-c double precision double-precision


【解决方案1】:

你所经历的是正常的,有无限数量的数字必须映射到一定数量的字节。因此,您通常不会得到您输入的确切数字,而是可以以所选数字格式表示的下一个最接近的数字。

对于数学计算,请使用NSDecimalNumber

【讨论】:

  • 感谢您的回复。如何使用 NSDecimalNumber?另外,我使用了 CLLocation 对象,它们的纬度和经度是双倍的。我涉及 CLLocation 对象进行许多计算。
  • 您可以根据您拥有的纬度/经度创建 NSDecimalNumbers。您报告的双精度“不精确”对您的纬度/经度计算有任何损害吗?
  • 使用 NSDecimalNumber 的另一个问题是,当将这些值分配给 CLLocation 的纬度和经度时,我们将再次使用 double latitude = [objDecimalNumber doubleValue]; 之类的东西将其更改为双精度值。所以问题再次保持不变。
  • 考虑一下您的想法-问题必须首先存在,因为 CLLocations 使用双打。所以要么保留双打并接受它们的精度,要么切换到 NSDecimalNumber。从您的问题来看,尚不清楚数据来自何处以及在何处使用。因此,一直使用双精度可能没问题,而且误差可能很小。
  • 是的,你的问题是对的。关于我们从哪里分配和派生这些双重值的问题尚不清楚。我已经编辑了这个问题。谢谢。
【解决方案2】:

您正在使用具有 double 类型属性(纬度和经度)的 CLLocation

double 类型默认使用小数点后 16 位。要获得您分配的确切值,请执行以下操作:

double d = 2.0126161000000000; 

剩下的数字用0,长度调整为16。

希望这会有所帮助。

【讨论】:

  • 这不起作用。传递double d = 2.0126161000000000; 并通过“po”命令检查输出显示(lldb) po d 2.0126160999999998
  • 尝试将最后一位数字 0 更改为 1。
猜你喜欢
  • 2010-10-29
  • 2014-04-28
  • 1970-01-01
  • 2016-06-01
  • 2023-03-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多