提问者:小点点

严格比较浮动是否安全,因为我们没有对它们进行操作?


通常,当我们想要测试小数是否相等时,由于IEEE754的近似性质,我们会有一定的不确定性。

if (fabs(one_float - other_float) < SUFFICIENTLY_SMALL) {
    consider them equal;
}

另一种方法可能是将浮点数转换为特定大小的整数,并比较生成的整数。

if ((uint)one_float == (uint)other_float) {
    consider them equal;
}

但是考虑一下这样的情况,我们的浮子从来没有经过任何算术,我们对它们唯一做的就是赋值。

//  Might be called at any moment
void resize(float new_width, float new_height)
{
    if (current_width == new_width && current_height == new_height) {
        return;
    }

    accomodate framebuffers;
    update uniforms;
    do stuff;

    current_width = new_width;
    current_height = new_height;
}

在上面的例子中,我们有一个可以自发启动的事件处理程序,我们希望仅在真正发生调整大小时重新分配资源。我们可能会采用近似比较的常规路径,但这似乎是一种浪费,因为该处理程序会经常启动。据我所知,浮点数与其他所有内容一样,使用内存移动来分配;等号操作符只执行内存比较。所以看起来我们在一个安全港。当在x86和ARM上检查时,这个假设成立,但我只是想确定一下。也许它有一些规范支持?

那么,当只分配浮点数时,是否有什么东西可能会改变它们?所描述的方法可行吗?


共3个答案

匿名用户

一大堆“应该”随之而来。

我不认为有任何东西说从浮点数到浮点数的赋值(current_width=new_width)不能改变值,但如果存在这样的东西,我会感到惊讶。除了直接复制之外,没有理由在同一类型的变量之间进行赋值。

如果传入的new_widthnew_height保持它们的值直到它们改变,那么这种比较应该没有任何问题。但是如果它们在每次调用之前都被计算,它们可能会改变它们的值,这取决于计算是如何完成的。所以需要检查的不仅仅是这个函数。

C 2011标准说计算可能使用比你分配的格式更大的精度,但没有具体说明将一个变量分配给另一个变量。所以唯一的不精确应该在计算阶段。“简单赋值”部分(6.5.16.1)说:

在简单赋值(=)中,右操作数的值被转换为赋值表达式的类型,并替换存储在左操作数指定的对象中的值。

因此,如果类型已经匹配,则不需要转换。

所以,简单地说:如果您不重新计算每次调用的传入值,则相等的比较应该成立。但是真的存在帧缓冲区大小为浮点数而不是整数的情况吗?

匿名用户

在您提到的情况下,使用==进行比较是安全的,因为函数末尾有以下行:

current_width = new_width;
current_height = new_height;

new_widthnew_height的任何更改都将使if语句失败,并且您将获得所需的行为。

abs()函数通常用于在程序中动态分配一个变量浮点数和一个要用作引用的常量浮点数。类似于:

bool isEqual(float first, float second)
{
   if(fabs(first-second)<0.0001)
      return true;
   return false;
}

int main()
{
   float x = (float) 1 / 3;
   if(isEqual(x,0.3333))
      printf("It is equal\n");
   else
      printf("It is not equal\n");
}

匿名用户

在这里查看如何比较两个浮点数。

https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/

用“ULP”找到测试,他紧张地说。你可以将浮点数作为int进行比较,但看看文章中是如何完成的,即(我希望我没有违反任何许可,如果是这样,请删除后面的代码,它不是我的)

bool AlmostEqualUlps(float A, float B, int maxUlpsDiff){
    Float_t uA(A);
    Float_t uB(B);
    // Different signs means they do not match.
    if (uA.Negative() != uB.Negative()) {
        // Check for equality to make sure +0==-0
        if (A == B) {
            return true;
        }
        return false;
    }

    // Find the difference in ULPs.
    int ulpsDiff = abs(uA.i - uB.i);
    if (ulpsDiff <= maxUlpsDiff) {
        return true;
    }
    return false;
}

请阅读那篇文章的其余部分,它真的很好。