代码之家  ›  专栏  ›  技术社区  ›  JaredPar

比较ieee float和double是否相等

  •  9
  • JaredPar  · 技术社区  · 16 年前

    比较ieee float和double是否相等的最佳方法是什么?我听说过几种方法,但我想看看社区的想法。

    15 回复  |  直到 12 年前
        1
  •  7
  •   DrPizza    16 年前

    我认为最好的方法是比较 ULPs .

    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;
    }
    

    双打也可以使用类似的技术。诀窍是转换浮点数,使其有序(就像整数一样),然后看看它们有多不同。

    我不知道为什么这该死的东西把我的下划线弄乱了。编辑:哦,也许这只是一个预演的假象。那就行了。

        2
  •  3
  •   JaredPar    16 年前

    我使用的当前版本是

    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方法更好吗?如果是,为什么?

        3
  •  1
  •   DrPizza    16 年前

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

    这取决于你对他们做了什么。与IEEEfloat具有相同范围的定点类型将慢很多倍(并且大很多倍)。

    适用于漂浮物的物品:

    三维图形、物理/工程、模拟、气候模拟……

        4
  •  1
  •   Michael Lehn    12 年前

    在数字软件中,你经常想测试两个浮点数是否 确切地 相等。拉帕克有很多这样的例子。当然,最常见的情况是要测试浮点数是否等于“零”、“一”、“二”、“半”。如果有人感兴趣,我可以选择一些算法并进行更详细的介绍。

    同样,在BLAS中,您经常希望检查浮点数到底是零还是一。例如,例程dgemv可以计算表单的操作

    • y=β*y+α*a*x
    • y=β*y+α*a^t*x
    • y=β*y+α*a^h*x

    所以如果beta等于1,你有一个“加赋值”,对于beta等于0,你有一个“简单赋值”。因此,如果您对这些(常见的)案例进行特殊处理,当然可以降低计算成本。

    当然,您可以这样设计BLAS例程,以避免进行精确的比较(例如使用一些标志)。然而,在不可能的地方,LAPACK充满了例子。

    附笔。:

    • 在很多情况下,你肯定不想检查“是否完全相等”。对于许多人来说,这甚至可能是他们唯一必须面对的情况。我想指出的是,还有其他情况。

    • 虽然lapack是用fortran编写的,但是如果您使用其他编程语言来编写数字软件,则逻辑是相同的。

        5
  •  0
  •   DrPizza    16 年前

    哦,亲爱的上帝,请不要把浮点数解释为整数,除非你是在p6或更早的版本上运行。

    即使它使它通过内存从向量寄存器复制到整数寄存器,即使它中断了管道,这也是我遇到的最好的方法,因为它提供了最强大的比较,即使面对浮点错误也是如此。

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

        6
  •  0
  •   DrPizza    16 年前

    这似乎通过结合相对误差和绝对误差公差来解决大多数问题。ULP方法更好吗?如果是,为什么?

    ULP是两个浮点数之间“距离”的直接度量。这意味着它们不需要你求出相对和绝对误差值,也不需要你确保这些值是“关于正确的”。使用ulps,您可以直接表示希望数字的接近程度,对于较小的值和较大的值,相同的阈值同样适用。

        7
  •  0
  •   DrPizza    16 年前

    如果你有浮点错误,你会遇到更多的问题。尽管我想这取决于个人的观点。

    即使我们做了数值分析来最小化误差的累积,我们也不能消除它,我们可以得到相同的结果(如果我们用reals计算),但是不同的结果(因为我们不能用reals计算)。

        8
  •  0
  •   Nick    16 年前

    如果你在寻找两个相等的浮点数,那么在我看来它们应该是相等的。如果您面临浮点舍入问题,固定点表示可能更适合您的问题。

        9
  •  0
  •   DrPizza    16 年前

    如果你在寻找两个相等的浮点数,那么在我看来它们应该是相等的。如果您面临浮点舍入问题,固定点表示可能更适合您的问题。

    也许我们负担不起这种方法会造成的范围或性能损失。

        10
  •  0
  •   Nick    16 年前

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

    @克雷格:当然。我完全同意打印这个。如果A或B存储货币,那么它们应该用固定点表示。我正在努力想一个现实世界中的例子,在这个例子中,这种逻辑应该与浮动联系在一起。适用于漂浮物的物品:

    • 砝码
    • 等级
    • 距离
    • 实际值(如来自ADC的值)

    对于所有这些事情,要么你数数然后简单地把结果呈现给用户进行人工解释,要么你做一个比较陈述(即使这样的陈述是,“这个东西在另一个东西的0.001之内”)。像mine这样的比较语句只在算法上下文中有用:“within 0.001”部分取决于 身体的 你问的问题。那是我的0.02个。还是说2/100?

        11
  •  0
  •   Nick    16 年前

    这要看你是什么人 和他们一起做。定点类型 与IEEE浮动范围相同 会慢很多倍 比原来大很多倍)。

    好吧,但是如果我想要一个无限小的分辨率,那么它就回到我原来的点:==和!在这种问题的上下文中没有意义。

    int允许我表示~10^9个值(不考虑范围),这对于我希望其中两个值相等的任何情况都足够了。如果这还不够的话,使用64位操作系统,你可以得到10^19个不同的值。

    我可以在一个int中表示0到10^200的范围(例如),它只是受到影响的位分辨率(分辨率将大于1,但是,同样,没有任何应用程序具有这种范围以及这种分辨率)。

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

        12
  •  0
  •   jakobengblom2    16 年前

    int可以表示~10^9个值 (不考虑范围)这似乎 在任何情况下 会关心他们中的两个 相等。如果还不够,就用 64位操作系统,大约10^19 不同的值。

    我真的达到了极限…我试图在一个模拟中改变ps中的时间和时钟周期中的时间,在这个模拟中你很容易达到10^10个周期。不管我做了什么,我很快就溢出了64位整数的小范围…10^19并不像你想象的那么多,现在给我128位计算!

    浮动允许我得到数学问题的解决方案,因为值在低端溢出了很多零。所以你基本上在数字中有一个小数点浮动aronud,并且没有精度损失(我喜欢在浮点尾数中允许的值的唯一数目比64位int更有限,但是非常需要th范围!).

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

    很烦人,最后我放弃了整个尝试,只依靠浮动和lt;和gt;来完成工作。不完美,但适用于预期的用例。

        13
  •  0
  •   BCS    16 年前

    如果你在寻找两个相等的浮点数,那么在我看来它们应该是相等的。如果您面临浮点舍入问题,固定点表示可能更适合您的问题。

    也许我应该更好地解释这个问题。在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;
    }
    

    打印出“有问题”这句话。你是说应该这样吗?

        14
  •  0
  •   Tim Cooper    12 年前

    哦,亲爱的上帝,请不要把浮点数解释为整数,除非你是在p6或更早的版本上运行。

        15
  •  0
  •   Tim Cooper    12 年前

    这是我遇到的最好的方法,因为它提供了最强大的比较,即使面对浮点错误也是如此。

    如果你有浮点错误,你会遇到更多的问题。尽管我想这取决于个人的观点。