gccの4倍精度の使い方と性能 [gcc quadruple precision]

2011年,5月のリリースでgcc4.6から4倍精度が入った. 昔のブログで軽く使い方を書いたが他のサイトに情報があまり増えてなかったし,私の記事もできが悪かったのでこっちに移転したので改めてまとめてみた.

使い方

簡単な使い方としては, libquadmathを使うことになる.

__float128 型を宣言して使う.倍精度を代入して使うこともできる. 4倍精度数を表現したい場合には後ろに q をつけて使う.

四則演算子や代入なども使えるが,printfだけはchar型の配列に変換してから使う必要がある. 適当なサンプルは以下のとおり:

#include<quadmath.h>
#include<stdio.h>
int main(){
char str[128];

__float128 a = 1.2345678901234567890q;
__float128 b = 1.234;
a = a + b;

quadmath_snprintf(str,128,"%.40Qf",a);
printf("%s",str);

return (0);
}
$ g++ -lquadmath -m128bit-long-double test.c

こんな感じに作れる.I/Oがなければ同じプログラムでtemplate使って共通化できるが, I/Oだけは色々調べたがどうしようもなさそうだった.

性能評価

試しに内積を実装して時間を測ってみた.
コードはここにおいた (リポジトリを移動しました, 2020/05/18).

出力を外に出せば,普通に倍精度と共通化してtemplateで作れた.

gcpで16コアのHaswellマシンを借りて実行してみた.
あんまり参考にはならないが Intel(R) Xeon(R) CPU @ 2.30GHzとのこと.

gccはgcc version 8.2.1 20180905 (Red Hat 8.2.1-3)
OSはCentOS Linux release 8.0.1905 (Core)\

表 各ベクトルサイズにおける倍精度と4倍精度の実行時間 [ms] (-O0, 最適化オプションなし,16 threads)

double quad
10^3 0.028 0.48
10^6 0.98 7.11
10^9 907 6487

まぁ7~8倍くらい時間がかかるが,並列化も簡単でコードも倍精度から移行するのはあまり難しくはない.

加筆

最適化オプションを付けていなかったのと,スレッド数を変えたりしていなかった. 内積だし大して考えなくてもいいだろうとタカをくくっていたが,実験してみたら色々と想像より変化があったので加筆する.
オプションは上記のものに加えて -O3 -fopenmp をつけた.

表 各ベクトルサイズにおける倍精度と4倍精度の実行時間 [ms] (1 thread)

double quad
10^3 0.013 0.051
10^6 2.14 51.6
10^9 1987 53611

表 各ベクトルサイズにおける倍精度と4倍精度の実行時間 [ms] (16 threads)

double quad
10^3 0.003 0.025
10^6 1.28 6.25
10^9 218 6112

マルチスレッド化の効果はサイズ10^9でdoubleが9.1倍,quadは8/77倍でそれなりに出ている. 16倍出ない理由はわからない.どちらもメモリでサチっているということだろうか?(quadもサチるか??要調査)

ただ16 threads同士の最適化オプションあり/なしがちょっと問題で, doubleはかなり最適化が効いてO3とO0で4.1倍も速くなったが, quadだとほとんど効果がない.libquadmathを呼んでいるだけだから確かにこうなるだろうが, オプションあり同士だと30倍の性能差がある. やはりquadmathは遅い..

今後の課題

  • こういうの内積でやるのが正しいか?(コメントありましたらIssueかTwitterで)
  • libquadmathの4倍精度の実装についてまとめたい
  • QDライブラリについてまとめたい