+0.0 和 -0.0 上的哪些运算和函数给出不同的算术结果? [英] What operations and functions on +0.0 and -0.0 give different arithmetic results?

查看:12
本文介绍了+0.0 和 -0.0 上的哪些运算和函数给出不同的算术结果?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 C 中,当支持 ±0.0 时,通常将 -0.0+0.0 分配给 double没有算术的区别.虽然它们有不同的位模式,但它们在算术上是相等的.

In C, when ±0.0 is supported, -0.0 or +0.0 assigned to a double typically makes no arithmetic difference. Although they have different bit patterns, they arithmetically compare as equal.

double zp = +0.0;
double zn = -0.0;
printf("0 == memcmp %d
", 0 == memcmp(&zn, &zp, sizeof zp));// --> 0 == memcmp 0
printf("==          %d
", zn == zp);                        // --> ==          1

灵感来自 @Pascal Cuoq 评论,我正在寻找标准 C 中的其他几个函数提供了算术上不同的结果.

Inspire by a @Pascal Cuoq comment, I am looking for a few more functions in standard C that provide arithmetically different results.

注意:许多函数,如 sin(),从 f(+0.0)-0.0<返回 +0.0/code> 来自 f(-0.0).但是这些并没有提供不同的算术结果.两个结果也不应该都是 NaN.

Note: Many functions, like sin(), return +0.0 from f(+0.0) and -0.0 from f(-0.0). But these do not provide different arithmetic results. Also the 2 results should not both be NaN.

推荐答案

f(+0.0)f(-0.0).

不同的舍入模式或其他浮点实现可能会产生不同的结果.

Different rounding modes or other floating point implementations may give different results.

#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
", 
      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
}

<小时>

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  

<小时>

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


Notes:
tgamma(x) came up == on my gcc 4.8.2 machine, but correctly != on others.

rsqrt(),又名 1/sqrt() 可能是未来的 C 标准函数.可能/可能不工作.

rsqrt(), AKA 1/sqrt() is a maybe future C standard function. May/may not also work.

双零 = +0.0;memcpy(&zero, &x, sizeof x) 可以显示 x 是与 +0.0 不同的位模式,但 x 仍然可以是 +0.0.我认为某些 FP 格式有许多位模式,即 +0.0-0.0.待定.

double zero = +0.0; memcpy(&zero, &x, sizeof x) can show x is a different bit pattern than +0.0 but x could still be a +0.0. I think some FP formats have many bit patterns that are +0.0 and -0.0. TBD.

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

This is a self-answer as provided by https://stackoverflow.com/help/self-answer.

这篇关于+0.0 和 -0.0 上的哪些运算和函数给出不同的算术结果?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆