+0.0和-0.0上的哪些操作和功能会产生不同的算术结果?

chu*_*ica 20 c floating-point

在C中,当±0.0支持-0.0+0.0分配给a时double通常不会产生算术差异.尽管它们具有不同的位模式,但它们在算术上比较相同.

double zp = +0.0;
double zn = -0.0;
printf("0 == memcmp %d\n", 0 == memcmp(&zn, &zp, sizeof zp));// --> 0 == memcmp 0
printf("==          %d\n", zn == zp);                        // --> ==          1
Run Code Online (Sandbox Code Playgroud)

受到@Pascal Cuoq评论的启发,我正在寻找标准C中的一些功能,这些功能提供了算术上不同的结果.

注意:许多功能,如sin(),返回+0.0f(+0.0)-0.0f(-0.0).但这些并不能提供不同的算术结果.这两个结果也不应该同时存在NaN.

chu*_*ica 17

有一些标准操作和功能在f(+0.0)和之间形成数字上不同的答案f(-0.0).

不同的舍入模式或其他浮点实现可以给出不同的结果.

#include <math.h>

double inverse(double x) { return 1/x; }

double atan2m1(double y) { return atan2(y, -1.0); }

double sprintf_d(double x) {
  char buf[20];
  // sprintf(buf, "%+f", x);   Changed to e
  sprintf(buf, "%+e", x);
  return buf[0];  // returns `+` or `-`
}

double copysign_1(double x) { return copysign(1.0, x); }

double signbit_d(double x) {
  int sign = signbit(x);  // my compile returns 0 or INT_MIN
  return sign;
}

double pow_m1(double x) { return pow(x, -1.0); }

void zero_test(const char *name, double (*f)(double)) {
  double fzp = (f)(+0.0);
  double fzn = (f)(-0.0);
  int differ = fzp != fzn;
  if (fzp != fzp && fzn != fzn) differ = 0;  // if both NAN
  printf("%-15s  f(+0):%-+15e %s  f(-0):%-+15e\n", 
      name, fzp, differ ? "!=" : "==", fzn);
}

void zero_tests(void) {
  zero_test("1/x",             inverse);
  zero_test("atan2(x,-1)",     atan2m1);
  zero_test("printf(\"%+e\")", sprintf_d);
  zero_test("copysign(x,1)",   copysign_1);
  zero_test("signbit()",       signbit_d);
  zero_test("pow(x,-odd)",     pow_m1);;  // @Pascal Cuoq
  zero_test("tgamma(x)",       tgamma);  // @vinc17 @Pascal Cuoq
}
Run Code Online (Sandbox Code Playgroud)
Output:
1/x              f(+0):+inf             !=  f(-0):-inf           
atan2(x,-1)      f(+0):+3.141593e+00    !=  f(-0):-3.141593e+00  
printf("%+e")    f(+0):+4.300000e+01    !=  f(-0):+4.500000e+01   
copysign(x,1)    f(+0):+1.000000e+00    !=  f(-0):-1.000000e+00  
signbit()        f(+0):+0.000000e+00    !=  f(-0):-2.147484e+09 
pow(x,-odd)      f(+0):+inf             !=  f(-0):-inf           
tgamma(x)        f(+0):+inf             !=  f(-0):+inf  
Run Code Online (Sandbox Code Playgroud)

注意:
tgamma(x)出现==在我的gcc 4.8.2机器上,但正确地 !=在其他机器上.

rsqrt(),AKA 1/sqrt()可能是未来的C标准功能.可能/可能也不行.

double zero = +0.0; memcpy(&zero, &x, sizeof x)可以显示的x是一个不同的位模式,+0.0x仍然可以是一个+0.0.我觉得有些FP格式有很多位模式+0.0-0.0.TBD.

这是https://stackoverflow.com/help/self-answer提供的自我回答.

  • 当你提出`atan2`时我印象非常深刻,当你添加`sprintf`时甚至更多.从那时起,我还没有想到任何进一步区分+0和-0的功能. (3认同)

vin*_*c17 5

IEEE 754-2008功能rsqrt(将在未来的ISO C标准中)在±0上返回±∞,这是非常令人惊讶的.并且tgamma还在±0上返回±∞.对于MPFR,mpfr_digamma在±0处返回±∞的相反值.

  • @chux关于rSqrt,遗憾的是在修改旧的IEEE 754-1985标准期间没有跟进我的请求:http://grouper.ieee.org/groups/754/email/msg03855.html (2认同)