9
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

fenv.h を使うときは、FENV_ACCESSも指定する

Posted at

概要

fenv.h を使うときは、FENV_ACCESSの指定も忘れないようにしましょう。

fenv.h

浮動小数演算の丸めモードには、4つあって、

  • -∞ 方向への丸め(FE_DOWNWARD)
  • +∞ 方向への丸め(FE_UPWARD)
  • 0 方向への丸め(FE_TOWARDZERO)
  • 近い値への丸め(FE_TONEAREST)

fesetround()で設定できます。

しかし、fesetroundだけでは、完全にこの挙動を指定できるわけではないです。

というのは、コンパイラは、コンパイル時に定数の演算を終わらせてしまう最適化をする可能性があるためです。

#include <fenv.h>
#include <stdio.h>

double get1() {
    return 1.0;
}

double get3() {
    return 3.0;
}

double f(void) {
    return get1() / get3();
}
int main() {
    fesetround(FE_UPWARD);
    printf("%a\n", f());

    fesetround(FE_DOWNWARD);
    printf("%a\n", f());

    fesetround(FE_TOWARDZERO);
    printf("%a\n", f());

    fesetround(FE_TONEAREST);
    printf("%a\n", f());
}

というようなコードを考えると、f()関数中の、1/3 という演算は本来なら丸めモードを参照しないといけないわけですが、コンパイル時に、1/3 の演算を済ませてしまうと、丸めモードを指定した場合の結果と変わってしまいます。

上のプログラムだと、-O0 と -O2 で結果が変わるのが確認できると思います。

$ clang -std=c11 -O0 fenv.c -Wall -lm  
$ ./a.out 
0x1.5555555555556p-2
0x1.5555555555555p-2
0x1.5555555555555p-2
0x1.5555555555555p-2
$ clang -std=c11 -O2 fenv.c -Wall -lm  
$ ./a.out 
0x1.5555555555555p-2
0x1.5555555555555p-2
0x1.5555555555555p-2
0x1.5555555555555p-2
$ gcc -std=c11 -O0 fenv.c -Wall -lm
$ ./a.out 
0x1.5555555555556p-2
0x1.5555555555555p-2
0x1.5555555555555p-2
0x1.5555555555555p-2
$ gcc -std=c11 -O2 fenv.c -Wall -lm
$ ./a.out 
0x1.5555555555555p-2
0x1.5555555555555p-2
0x1.5555555555555p-2
0x1.5555555555555p-2

というわけで、fesetroundを使った丸めモード指定を正しく使うなら、コンパイラによる最適化を抑制する必要があります。これを指定するのが、

#pragma STDC FENV_ACCESS ON

というプラグマです。

上のプログラムをこのFENV_ACCESSを使うように書きかえると、

double f(void) {
#pragma STDC FENV_ACCESS ON
    return get1() / get3();
}
$ gcc -std=c11 -O2 fenv.c -Wall -lm
fenv.c: In function ‘f’:
fenv.c:13:0: warning: ignoring #pragma STDC FENV_ACCESS [-Wunknown-pragmas]
#pragma STDC FENV_ACCESS ON
^

$ clang -std=c11 -O2 fenv.c -Wall -lm
fenv.c:13:14: warning: pragma STDC FENV_ACCESS ON is not supported, ignoring pragma [-Wunknown-pragmas]
#pragma STDC FENV_ACCESS ON
             ^
1 warning generated.

GCC, clangではまだサポートされていないことが確認できますね。(完)

9
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?