为什么fmax(a,b)返回较小的(负)零以及如何干净地解决它?

kan*_*aka 4 c math floating-point

#include <stdio.h>
#include <math.h>

int main () {
    float a = 0.0, b = -0.0;
    printf("fmax(%f, %f) = %f\n", a, b, fmax(a, b));
}
Run Code Online (Sandbox Code Playgroud)

我得到以下结果:

gcc f.c -o f -lm
./f
fmax(0.000000, -0.000000) = -0.000000
Run Code Online (Sandbox Code Playgroud)

fmax手册页中未记录此(错误)行为.对它有合理的解释吗?是否有一个干净(简洁)的解决方法?另外,如果两者都是-0.0,我想得到-0.0作为最大值.

Jea*_*bre 7

"问题"就是这样a == b.标志无关紧要,因为尾数(标志放在一边)纯粹是0.我得到了0x80000000vs0

所以fmax只是检查是否a < bb < a(取决于实现),都是假的,所以无论答案是潜在的匹配.

在我的gcc版本,我得到fmax(0.0,-0.0)0.0,不过fmax(-0.0,0.0)-0.0.

我尝试了一个完整的解决方法,memcmp用于在0结果的情况下比较二进制数据.

如建议的那样更好,使用signbit哪个测试,如果数字设置为负位(无论值如何):

#include <stdio.h>
#include <math.h>
#include <string.h>

float my_fmax(float a,float b)
{
   float result = fmax(a,b);
   if ((result==0) && (a==b))
   {
       /* equal values and both zero
          the only case of potential wrong selection of the negative 
          value. Only in that case, we tamper with the result of fmax,
          and just return a unless a has negative bit set */

       result = signbit(a) ? b : a;
   }
   return result;
}

int main () {
    float a = -0.0, b = 0.0;

    printf("fmax(%f, %f) = %f\n", a,b, my_fmax(a, b));
    a = 0.0;
    printf("fmax(%f, %f) = %f\n", a,b, my_fmax(a, b));
    a = b = -0.0;
    printf("fmax(%f, %f) = %f\n", a,b, my_fmax(a, b));
    a = 1.0;
    printf("fmax(%f, %f) = %f\n", a,b, my_fmax(a, b));
    a = -1.0;
    printf("fmax(%f, %f) = %f\n", a,b, my_fmax(a, b));
    b = 0.0;
    printf("fmax(%f, %f) = %f\n", a,b, my_fmax(a, b));
}
Run Code Online (Sandbox Code Playgroud)

结果(我想我涵盖了所有案例):

fmax(-0.000000, 0.000000) = 0.000000
fmax(0.000000, 0.000000) = 0.000000
fmax(-0.000000, -0.000000) = -0.000000
fmax(1.000000, -0.000000) = 1.000000
fmax(-1.000000, -0.000000) = -0.000000
fmax(-1.000000, 0.000000) = 0.000000
Run Code Online (Sandbox Code Playgroud)