比较IEEE浮点数和双精度是否相等

时间:2020-03-05 18:41:48  来源:igfitidea点击:

比较IEEE浮点数和双精度数是否相等的最佳方法是什么?我听说过几种方法,但是我想看看社区的想法。

解决方案

回答

我认为最好的方法是比较ULP。

bool is_nan(float f)
{
    return (*reinterpret_cast<unsigned __int32*>(&f) & 0x7f800000) == 0x7f800000 && (*reinterpret_cast<unsigned __int32*>(&f) & 0x007fffff) != 0;
}

bool is_finite(float f)
{
    return (*reinterpret_cast<unsigned __int32*>(&f) & 0x7f800000) != 0x7f800000;
}

// if this symbol is defined, NaNs are never equal to anything (as is normal in IEEE floating point)
// if this symbol is not defined, NaNs are hugely different from regular numbers, but might be equal to each other
#define UNEQUAL_NANS 1
// if this symbol is defined, infinites are never equal to finite numbers (as they're unimaginably greater)
// if this symbol is not defined, infinities are 1 ULP away from +/- FLT_MAX
#define INFINITE_INFINITIES 1

// test whether two IEEE floats are within a specified number of representable values of each other
// This depends on the fact that IEEE floats are properly ordered when treated as signed magnitude integers
bool equal_float(float lhs, float rhs, unsigned __int32 max_ulp_difference)
{
#ifdef UNEQUAL_NANS
    if(is_nan(lhs) || is_nan(rhs))
    {
        return false;
    }
#endif
#ifdef INFINITE_INFINITIES
    if((is_finite(lhs) && !is_finite(rhs)) || (!is_finite(lhs) && is_finite(rhs)))
    {
        return false;
    }
#endif
    signed __int32 left(*reinterpret_cast<signed __int32*>(&lhs));
    // transform signed magnitude ints into 2s complement signed ints
    if(left < 0)
    {
        left = 0x80000000 - left;
    }
    signed __int32 right(*reinterpret_cast<signed __int32*>(&rhs));
    // transform signed magnitude ints into 2s complement signed ints
    if(right < 0)
    {
        right = 0x80000000 - right;
    }
    if(static_cast<unsigned __int32>(std::abs(left - right)) <= max_ulp_difference)
    {
        return true;
    }
    return false;
}

类似的技术可以用于双打。技巧是转换浮点数,以便对它们进行排序(就像整数一样),然后看看它们之间有何不同。

我不知道为什么这该死的东西搞砸了我的下划线。编辑:哦,也许这只是预览的人工产物。那没关系

回答

噢,亲爱的上帝,除非我们在P6或者更早的版本上运行,否则请勿将浮点位解释为整数。

回答

Oh dear lord please don't interpret the float bits as ints unless you're running on a P6 or earlier.

即使它导致它通过内存从向量寄存器复制到整数寄存器,甚至使流水线停滞,它也是我遇到的最好的方法,因为即使面对表面它也提供了最可靠的比较浮点错误。

也就是说,这是值得付出的代价。

回答

我正在使用的当前版本是这个

bool is_equals(float A, float B,
               float maxRelativeError, float maxAbsoluteError)
{

  if (fabs(A - B) < maxAbsoluteError)
    return true;

  float relativeError;
  if (fabs(B) > fabs(A))
    relativeError = fabs((A - B) / B);
  else
    relativeError = fabs((A - B) / A);

  if (relativeError <= maxRelativeError)
    return true;

  return false;
}

通过结合相对和绝对错误容忍度,这似乎可以解决大多数问题。 ULP方法更好吗?如果是这样,为什么?

回答

it's the best way to do it that I've come across, insofar as it provides the most robust comparisons even in the face of floating point errors.

如果我们有浮点错误,那么我们将遇到的问题甚至更多。虽然我认为这取决于个人观点。

回答

This seems to take care of most problems by combining relative and absolute error tolerance. Is the ULP approach better? If so, why?

ULP是两个浮点数之间"距离"的直接度量。这意味着它们不需要我们想出相对和绝对误差值,也不必确保获得"大约正确"的值。使用ULP,我们可以直接表示希望数字接近多少,并且相同的阈值适用于较小的值和适用于较大的值。

回答

If you have floating point errors you have even more problems than this. Although I guess that is up to personal perspective.

即使我们进行数值分析以最大程度地减少误差的累积,我们也无法消除它,而剩下的结果应该是相同的(如果我们使用实数进行计算),但应该有所不同(因为我们无法使用实数进行计算)。

回答

如果我们希望两个浮点数相等,那么我认为它们应该相等。如果我们遇到浮点取整问题,则定点表示法可能会更适合问题。

回答

If you are looking for two floats to be equal, then they should be identically equal in my opinion. If you are facing a floating point rounding problem, perhaps a fixed point representation would suit your problem better.

也许我们无法承受这种方法会造成的范围或者性能损失。

回答

If you are looking for two floats to be equal, then they should be identically equal in my opinion. If you are facing a floating point rounding problem, perhaps a fixed point representation would suit your problem better.

也许我应该更好地解释这个问题。在C ++中,以下代码:

#include <iostream>

using namespace std;

int main()
{
  float a = 1.0;
  float b = 0.0;

  for(int i=0;i<10;++i)
  {
    b+=0.1;
  }

  if(a != b)
  {
    cout << "Something is wrong" << endl;
  }

  return 1;
}

打印短语"出了点问题"。我们是说应该吗?

回答

@DrPizza:我不是性能专家,但我希望定点运算比浮点运算更快(在大多数情况下)。

@克雷格H:好的。我完全可以打印它。如果a或者b存钱,则应以定点表示。我正在努力思考一个真实的例子,在这种例子中,这种逻辑应该与浮点数相关联。适用于彩车的东西:

  • 重量
  • 等级
  • 距离
  • 实际值(例如来自ADC的值)

对于所有这些事情,我们或者编号然后简单地将结果呈现给用户以供人工解释,或者做出比较性的陈述(即使这样的陈述是"该事物与另一事物之差在0.001之内")。像mine这样的比较语句仅在算法上下文中有用:" 0.001之内"部分取决于我们要问的是什么物理问题。那我0.02. 还是我应该说2/100分?

回答

@DrPizza: I am no performance guru but I would expect fixed point operations to be quicker than floating point operations (in most cases).

而是取决于我们对他们的处理方式。与IEEE浮点数具有相同范围的定点类型将慢很多倍(并且很多倍)。

Things suitable for floats:

3D图形,物理/工程,模拟,气候模拟。...

回答

It rather depends on what you are
  doing with them. A fixed-point type
  with the same range as an IEEE float
  would be many many times slower (and
  many times larger).

好的,但是如果我想要一个无限小的位分辨率,那么它又回到了我的原始观点:==和!=在这种问题的背景下毫无意义。

一个int让我表达〜10 ^ 9个值(无论范围如何),对于任何我关心其中两个相等的情况,这似乎足够了。如果这还不够,请使用64位操作系统,我们将获得大约10 ^ 19个不同的值。

我可以用int表示0到10 ^ 200范围内的值,这只是位分辨率的问题(分辨率将大于1,但同样,没有应用程序也具有这种范围)那样的分辨率)。

总而言之,我认为在所有情况下,或者代表一个连续的值,在这种情况下!=和==不相关,或者代表一个固定的值集,可以将其映射为一个int(或者另一个固定值)。 -精度类型)。

回答

An int lets me express ~10^9 values
  (regardless of the range) which seems
  like enough for any situation where I
  would care about two of them being
  equal. And if that's not enough, use a
  64-bit OS and you've got about 10^19
  distinct values.

我实际上已经达到了这个极限...我试图在模拟中以ps为单位的时间和以时钟周期为单位的时间来进行调整,在这种情况下,我们很容易达到10 ^ 10周期。不管我做了什么,我很快都溢出了64位整数的微不足道的范围... 10 ^ 19并不像我们想的那样多,现在gimme 128位正在计算!

浮点数使我能够解决数学问题,因为低端的值溢出了很多零。因此,我们基本上可以在数字上保留小数点后的整数,而不会损失精度(我想与64位int相比,在float的尾数中允许使用更有限的不同数量的值,但是非常需要这个范围! )。

然后事物转换回整数以进行比较等。

令人烦恼的是,最后我放弃了整个尝试,只是依靠float和<和>来完成工作。不是完美的,但可以用于预想的用例。