2015/12/23(水)kv-0.4.28

kvライブラリを0.4.28にアップデートしました。

今回はライブラリ本体の変更はほとんどなく、highderiv.hpp(高階微分の計算)、test-rounding.cc(丸めモードの変更が正常に動いているか簡易チェック)を追加したくらいです。webのドキュメントは、psaやaffineにいくらか加筆しています。明日、応用数理セミナーの講演でこのライブラリの話をするのでその前に区切りとして全ての変更を放出しておきたかったという理由もあります。

test-rounding.ccの追加は、前回日記で触れたcygwinのsqrt問題があったので、とりあえず軽くチェックしようと思ったためです。いろいろな環境でテストしてみたところ、概ね以下のような感じです。
  • Linux, Macは64bit OSで64bitコンパイルしていれば問題なし
  • x86の32bitモードはFPUが使われてしまうためIEEE754に従っておらず、お勧め出来ない。
  • Windowsでは、cygwin, msys2で最適化をしないと、sqrtに丸めの向きが変わらない問題が発生。VC++の64bitなら問題なし。
sqrtはVC++の32bitモードでも問題が発生することが分かっており、VC++由来のライブラリを使っている環境ではsqrtの方向付き丸めをエミュレーションで何とかすることも考えてみます。

2015/12/16(水)cygwinのsqrtの丸めモード変更

普段は自分は使っていないのですが、学生の一人がcygwinを使っていて、奇妙な現象を見つけたのでメモ代わりに記録しておきます。

問題は、cygwinのsqrtで丸めの向きが最適化をかけないときに変わらないというものです。環境は64bitのwindows7で、cygwinも64bitの最新のものです。gccは4.9.3でした。
#include <stdio.h>
#include <math.h>
#include <fenv.h>

int main()
{
        volatile double x, y, z;

        x = 2.;
        fesetround(FE_DOWNWARD);
        y = sqrt(x);
        fesetround(FE_UPWARD);
        z = sqrt(x);
        fesetround(FE_TONEAREST);

        if (y == z) {
                printf("sqrt error\n");
        }
}
このようなプログラムで、
cc cygwin-sqrt.c
のように最適化オプションをつけないでコンパイルしたとき、丸めの向きが上向きでも下向きでも結果が同じになってしまいます。
cc -O3 cygwin-sqrt.c
のように最適化をかければ問題ありません。いろいろ試すと、-O0ではアウト、-O1, -O2, -O3はセーフでした。

volatileを使わない場合最適化をかけることで結果がおかしくなるのはさほど珍しくありませんが、このように最適化をかけない状態で結果が異常になるのはとても珍しいです。

cc -Sでアセンブリソースを表示させてみると、最適化無しでは単に外部のsqrt関数を
        call    sqrt
と呼んでいるのに対して、-O3だと
        sqrtsd  %xmm0, %xmm1
のようにSSE2で直接計算するコードが生成されているので、どうやら外部(libm?)のsqrtに問題がありそうです。

以前にVisual C++で似たようなことがあったので、それとも関係あるのでしょうか。どなたか詳しい方に教えて欲しいものです。

これで丸めの向きが変わらないのはIEEE754的にまずいので、そんな腐った環境は無視するというのも一つの考え方でしょうが、こういう事例が多くあるようならsqrtに関しては丸めモード変更に期待しないで何とかすることを検討するべきかも。kvライブラリでいえば-DKV_NOHWROUNDを付ければ問題なくなるので、それをデフォルトにするとか。
OK キャンセル 確認 その他