比较浮点数的正确方法

Correct Way to Compare Floating-point Numbers

本文关键字:方法 浮点数 比较      更新时间:2023-10-16

我正在计算一个N + fraction形式的实数值。比如说,比如N + fraction = 7.10987623,然后N = 7 fraction = 0.10987623接下来,我需要检查一下fraction是否大于或等于23269/25920的比率。

在 C/C++ 中,以下内容似乎给出了正确的结果;但是,我不确定这是否是进行比较的正确方法:

// EPSILON is defined to be the error tolerance
// and `ratio' is defined as 23269.0/25920.0 
if(fabs(fraction - ratio) > EPSILON)
 // `fraction' is greater or equal to `ratio'

我也尝试了另一种方式,但它似乎给出了不正确的结果。

if(fabs(fraction - ratio) < EPSILON)

你有正确的方法来比较相等性:

fabs(fraction - ratio) < EPSILON

在宽度EPSILONratio周围建立一个等式带。任何高于该波段的东西,都是严格意义上的更大。因此,>检查是:

fraction > ratio + EPSILON

由于我们想要>=,我们只取这两个部分的并集:

fraction > ratio - EPSILON

与其指定一个EPSILON,它需要根据N的大小而变化,另一种方法是将N添加到ratio,因为这样它和fraction将产生相同的舍入:

x <= floor(x) + ratio

通过 modf() 将数字分解为整数和小数部分。
使用良好的 FP 库,预计不会损失精度。

#include <math.h>
int foo(double N_plus_fraction) {
  double ipart;
  double fraction = modf(N_plus_fraction, &ipart);
  fraction = fabs(fraction);  // lets use the absolution fraction.

将阈值分解为分子/分母部分并缩放分数。

  double f = fraction*25920.0;
  return f >= 23269.0;
}

由于乘积f可能不是fraction25920.0的精确数学乘积,而是最接近的四舍五入的乘积,代码可以使用稍大(或更小)的fnextafter()取决于人们想要偏向结果的方式。

  double f = fraction*25920.0;
  f = nextafter(f, 2*f);  // make f the next greater FP value.
  return f >= 23269.0;
}

唯一预期的不精确性发生在fraction*25920.0步骤中。