是否可以对浮点算术错误中的 a 和 b 的值进行逆向工程,例如 (a -b) == 0.499,而它应该是 0.5?

问题描述 投票:0回答:1

在我的应用程序中,我正在计算经过的时间(a-b),我得到了

0.4999978542327881
(由python打印),我想如果它没有被python四舍五入打印的话,它真的是
0.4999978542327880859375

我确实相信

a-b
应该是
0.5
如果我用笔和纸来做的话。我的猜测是,由于
0.4999978542327880859375
a
和结果值的浮点数表示形式的限制,我得到
b

我对这个错误很满意,并且我考虑了公差。

我的问题确实是:有没有一个程序可以得到

a
b
我的意思是我想得到两个十进制数
a
b
,当使用笔和纸相减时给出
0.5
和然后使用浮点运算(IEEE 754)会给我
0.4999978542327880859375
。我可以打印
a
b
但我无法真正重现错误,因为它取决于经过的时间。

例如,假设我有

(a-b) = 0.19999999999999998
,并且我知道如果我使用
简单的“人类”算术
而不是浮点算术,它应该是 0.2。我想将
a
b
的值逆向工程为
0.3
0.1
因为我知道常规算术中的
0.3-0.1==0.2
但浮点算术中的
0.3-0.1==0.19999999999999998
因为
0.1
最接近的表示是
0.1000000000000000055511151231257827021181583404541015625

该过程不需要为

a
b
生成唯一值。所有可能的
(a,b)
对的列表会更有用,这样我就可以搜索最合适的示例,因为我知道发生这种情况的大致时间,并且
a
b
是自纪元以来的时间戳(以秒为单位):漂浮。例如,在这个特定的实例中,我知道
a
b
都必须在
1704964314.0
('2024-01-11T09:11:54.000+00:00') 和
1704964316.0
('2024-01) 之间-11T09:11:56.000+00:00')

我对

0.4999978542327881
的特殊情况感兴趣,但也对获取特定结果示例的一般程序感兴趣。为什么?因为我想提供我在应用程序日志中找到的每个浮点“错误”的输入值示例(针对 github 问题)。

floating-point precision
1个回答
0
投票

第一步是使用非十进制表示法进行分析:

下面打印

0x1.ffff7p-2 0x1.ffff7p-2
,暗示问题可能仅限于
float
值,而不是
double

int main() {
  double d = 0.4999978542327880859375;
  printf("%a\n%a\n", d, (float) d);
  return 0;
}

添加以下代码,我们看到

0x1.ffff7p-2
距离 0.5 为 72
float
。这个简单数学减法的距离意味着
a - b
距离是由于值 about 大于 0.5 72 倍而产生的。 (在这里挥手数学。)

  unsigned count = 0;
  while (d < 0.5) {
    d = nextafterf(d, 0.5);
    count++;
  }
  printf("%X\n", count);

除此之外,我们正在进入更多 ifs,并且确实需要更多信息才能进行更多工作。

© www.soinside.com 2019 - 2024. All rights reserved.