2025/03/18(火)数学ソフトウェアとフリードキュメント

昨日は、数学ソフトウェアとフリードキュメント 37という集まりで、kvライブラリについて50分間、話をしてきました。数値計算の誤差がどのくらい怖いか、という「脅し」のパートが受けてたみたいです。kvライブラリのホームページに置いてあるスライドにちょっと追加しただけではありますが、スライドが欲しいという話があったのでここに置いておきます。

2025/03/15(土)kv-0.4.58

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

今回も大した変更はありません。
  • ODE Solverで、精度保証に失敗した場合ごく稀にstep sizeを小さくしてのretryをせずにエラーで止まってしまうことがあったのを修正。
  • PSAのpow(x, y)で、yが整数でない定数だがpsa型でない場合の動作を改善。
  • vleq.hppの精度を改善 (高安先生の要請による)
くらいです。

数学ソフトウェアとフリードキュメント 37でkvについてしゃべるので、いい機会なのでここまで溜まっていたアップデートを吐き出したかったという理由もありました。

2024/08/27(火)kv-0.4.57

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

今回は、
  • 以前にるふぁさんにご指摘頂いた、defint_autostepで使用する級数の次数を1にしたときに正しく計算できていなかったバグの修正。
  • ode_maffineに自動微分型を指定し、なおかつcallback関数を指定したとき、 callback関数が初期値に関する微分の情報をも渡してくれるように変更。
の2点です。後者はとある研究で必要になって機能追加しました。

大したアップデートではないですが、一応2つ溜まったので。

2024/02/07(水)g++-13と_Float64xとkv-0.4.56

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

今回は問題発生への対処です。ある人から、g++ version 13でkvがまったくコンパイルできない、clang++では問題ないと連絡が来ました。実際、ubuntu 23.10を入れて試してみると、test-rounding.ccとかtest-interval.ccみたいな基本的なプログラムすらコンパイルエラーになってしまいました。

調べてみると、_Float64x (IntelのFPUが持っている80bit拡張浮動小数点数) の関係する部分がエラーになっています。kvどころか、
#include <iostream>

int main()
{
        _Float64x a;

        std::cin >> a;
}
みたいな単純なプログラムがコンパイルエラーになってしまいます。また、
#include <iostream>
#include <limits>

int main()
{
        std::cout << std::numeric_limits<_Float64x>::epsilon() << std::endl;
        std::cout << std::numeric_limits<_Float64x>::max() << std::endl;
        std::cout << std::numeric_limits<_Float64x>::min() << std::endl;
        std::cout << std::numeric_limits<_Float64x>::infinity() << std::endl;

        std::cout << std::numeric_limits<__float80>::epsilon() << std::endl;
        std::cout << std::numeric_limits<__float80>::max() << std::endl;
        std::cout << std::numeric_limits<__float80>::min() << std::endl;
        std::cout << std::numeric_limits<__float80>::infinity() << std::endl;

        std::cout << std::numeric_limits<long double>::epsilon() << std::endl;
        std::cout << std::numeric_limits<long double>::max() << std::endl;
        std::cout << std::numeric_limits<long double>::min() << std::endl;
        std::cout << std::numeric_limits<long double>::infinity() << std::endl;
}
は、
0
0
0
0
1.0842e-19
1.18973e+4932
3.3621e-4932
inf
1.0842e-19
1.18973e+4932
3.3621e-4932
inf
のように、numeric_limits<_Float64x>はすべて0を返してきます。

調べてみると、「_Float64xをサポートしているのはgccのみで、もともとg++では_Float64xをまったくサポートしていなかった。しかしversion 12までは単なるlong doubleのtypedefだったので、たまたまg++でも動いてしまっていた。最新のg++ version 13では_Float64xを部分的にサポートするようになったがlibstdc++はサポートしていない状態になり、結果的にまったく使えなくなってしまった」ということのようです。やりとりはこの辺

gccのドキュメントの6.12 Additional Floating Typesでは、「As an extension, GNU C and GNU C++ support additional floating types, (中略) _float80 is available on the i386, x86_64, and IA-64 targets, and supports the 80-bit (XFmode) floating type. It is an alias for the type name _Float64x on these targets. 」とはっきり書いているので、g++でも_Float64xはサポートされているように見えるのですが。

IntelのCPUではlong double、__float80も_Float64xと同じ80bit拡張浮動小数点数です。こっちの2つはg++-13でも生き残っています。どちらかで全部書き換えることも考えたのですが、long doubleは異なるアーキテクチャだと異なる浮動小数点数フォーマットに対応していることが多く、トラブルを招く可能性が高い、__float80はgccのみのオリジナル拡張でclangで使えない、とそれぞれ問題があります。

もっともメジャーで、4月にはみんながubuntu 24.04を使い始めることを考えると、g++-13で動かないなんてのは使い物にならないも同然なので、緊急にkv-0.4.56をリリースしました。とりあえず最低限の変更で、g++-13では_Float64x関連の機能が全部働かないようにしました。g++-12以下ではすべて問題なく、g++-13では_Float64xを使う機能を除いてすべてコンパイルできるようになりました。他の変更は、ついでにoptimize.hppにちょっとした追加機能が入ったくらいです。

g++-14以降でちゃんと戻ることを祈るのみですが、こんなIntel CPUにしかない盲腸のような機能を使おうとするほうが悪い、という話でもあるのかな。

2022/09/16(金)kv-0.4.55

久しぶりに、kvを0.4.55にアップデートしました。

今年の1月に、M1 macの区間演算は遅い?という記事を書きました。このときに、ARM CPUでのinline assemblerによる丸めの向きの変更のコードを追加していたのですが、大して面白い変更では無かったので放置していました。気づいたら8ヶ月も経ってしまい、細かい修正も溜まってきたのでここでいったん公開することにしました。

というわけで、今回の変更はARM CPUで-DKV_FASTROUNDを付けるとinline assemblerによる丸めの向きの変更が使えるようになる、というものです。ARM 64bitだけでなく、一応ARM 32bitでも動くようにしたつもりですが、あまりテストされていません。

詳細は丸めモードの変え方とコンパイルオプションまとめの「6. ベンチマーク」に書きましたが、一般的にARM CPUでは丸めのモードを変更すると実行時間で大きなペナルティがあるようで、Intel CPUに比べてかなり遅いです。ARM CPUではハードウェアによる丸め変更を一切行わずにソフトウェアで方向付き丸めをエミュレートするのが一番速いという、残念な状況になっています。これを、精度保証に向かないCPUが普及しつつあって残念と見るか、エミュレーションのアルゴリズムを開発しておいて良かった、と見るか。

以下、とある区間演算を多用したプログラムを、端点がdouble精度の区間演算と、端点がdd精度の区間演算の場合について、オプションを変えながら実行したときの実行時間を上のページから抜き出しておきます。爆速のはずのM1 chipの計算速度が遅く、-DNOHWROUND (ソフトウェアエミュレートによる丸め変更) が一番まともになっているのが分かります。

core i5 11400

計算精度(端点の型) コンパイルオプション
(-O3 -DNDEBUGに加えて)
計算時間
-DKV_USE_TPFMAなし -DKV_USE_TPFMAあり
double なし 6.65 sec
-DKV_FASTROUND 3.74 sec
-DKV_NOHWROUND 7.88 sec 6.05 sec
-DKV_USE_AVX512 -mavx512f 2.74 sec
dd なし 37.20 sec 33.58 sec
-DKV_FASTROUND 25.08 sec 21.52 sec
-DKV_NOHWROUND 92.24 sec 71.81 sec
-DKV_USE_AVX512 -mavx512f 16.47 sec

M1 MacBook Air

計算精度(端点の型) コンパイルオプション
(-O3 -DNDEBUGに加えて)
計算時間
-DKV_USE_TPFMAなし -DKV_USE_TPFMAあり
double なし 24.45 sec
-DKV_FASTROUND 22.36 sec
-DKV_NOHWROUND 9.08 sec 6.03 sec
dd なし 108.8 sec 100.6 sec
-DKV_FASTROUND 102.4 sec 94.64 sec
-DKV_NOHWROUND 84.60 sec 53.76 sec
OK キャンセル 確認 その他