C99 - 保证浮点舍入模式的排序

时间:2015-06-29 14:56:15

标签: c floating-point language-lawyer c99 floating-accuracy

是否有任何保证(在C99标准和/或IEEE-754中)使用不同舍入模式时获得的结果应以特定方式进行排序?

例如,让f(rm, x)成为rm为舍入模式且x为其参数的函数。我是否可以认为无错误的实现应该确保以下不等式?

f(FE_DOWNWARD,x) <= f(FE_TONEAREST,x) <= f(FE_UPWARD,x)

作为一个例子,我机器上的以下代码与这个假设相矛盾(即使使用最近的glibc,版本2.21),我想知道它是否是一个错误(值得报告),或者只是舍入错误的一个不幸后果,这意味着永远不要依赖这种行为。

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <fenv.h>
#include <gnu/libc-version.h>

void set_round(int rm) {
  // checks that the rounding mode has been successfully set
  if (fesetround(rm)) { perror("setround"); exit(1); }
}

int main() {
  printf("GNU libc version: %s\n", gnu_get_libc_version());
  float x = 3;
  set_round(FE_TONEAREST);
  float r = log10f(x);
  printf("nearest:     r = %g (%a)\n", r, r);

  set_round(FE_DOWNWARD);
  r = log10f(x);
  printf("downward:    r = %g (%a)\n", r, r);

  set_round(FE_UPWARD);
  r = log10f(x);
  printf("upward:      r = %g (%a)\n", r, r);

  set_round(FE_TOWARDZERO);
  r = log10f(x);
  printf("toward zero: r = %g (%a)\n", r, r);
  return 0;
}

输出:

GNU libc version: 2.21
nearest:     r = 0.477121 (0x1.e89278p-2)
downward:    r = 0.477121 (0x1.e8927ap-2)
upward:      r = 0.477122 (0x1.e8927cp-2)
toward zero: r = 0.477121 (0x1.e8927ap-2)

编辑:事实证明这个具体的例子是GCC“功能” 1 :使用Clang,或激活GCC的优化标志,或使用文字常量而不是调用log10f时的变量,所有这些都会导致值一致。然而,问题仍然在一般情况下。

1 这不被GCC视为错误,而是由于GCC直接执行优化而不涉及不精确的glibc而产生的令人惊讶的结果。

1 个答案:

答案 0 :(得分:4)

没有这样的保证。

某些数学库试图仅为数学库函数来满足此约束,但任何标准都不需要这种行为,而且很少见(甚至大多数尝试提供它的库都有妥协)和错误)。

对于不在数学库中的函数,尝试符合该属性几乎是不可能的,无论如何都是无用的,因此基本上是闻所未闻的。

IEEE-754(2008)建议,但不要求数学库函数的特定子集正确舍入(或正确舍入的版本可用),这意味着您正在寻找的财产。但是,这项建议目前尚未得到广泛实施。