sinf()の結果がVCとclang/gccで違う件について


VCとclang/gccで単精度浮動小数点数での三角関数の結果が微妙に違う。

まず以下のコード。

main.c

#define my_sinf(x) (float)sin((double)(x))

int main() {
    int tmp;
    float val;
    float ret_sin, ret_sinf, ret_my_sinf;

    tmp = 0x3e75565e;
    memcpy(&val, &tmp, 4);
    
    ret_sin = sin((double)val);//倍精度用
    ret_sinf = sinf(val);//単精度
    ret_my_sinf = my_sinf(val);//自作単精度

    printf("ret_sin : 0x%08x\n", *((int*)&ret_sin));
    printf("ret_sinf : 0x%08x\n", *((int*)&ret_sinf));
    printf("ret_my_sinf : 0x%08x\n", *((int*)&ret_my_sinf));

    return 0;
}

VCの結果

> cl.exe main.c
ret_sin : 0x3e72ff38
ret_sinf : 0x3e72ff38 <--- 最下位桁が8
ret_my_sinf : 0x3e72ff38

clang/gccの結果

$ clang --std=c99 -o test main.c
ret_sin : 0x3e72ff38
ret_sinf : 0x3e72ff39 <--- 最下位桁が9
ret_my_sinf : 0x3e72ff38


この結果の違いから、
VCにおいては sinf() は my_sinf() と同様に
内部で倍精度浮動小数点数で計算したあとで単精度にして返しているのに対し、
clang/gccでは、内部も単精度浮動小数点数で計算しているであろうというのがわかる。
(手元にある別のlibcのソースを見たら内部が単精度だったし(適当))


C言語の仕様としては計算の精度までは指定していないためこれは仕方が無いのですが、
同じ計算なのにビルド環境によって結果が違うというのは
まじめな計算をしている時には厄介なバグになるので注意ですね。実際死んだ。

こういうとき、いつもなら気晴らしにVCを叩くところだけど
さすがに精度がいいほうを叩くのはなんか気が引けるっすね