本ライブラリ(dd.hpp) は、
FPUの内部精度は 全長80bit, 仮数部64bitで、IEEE754の全長64bit, 仮数部53bitと 異なることはよく知られている。 これと本ライブラリで使っている擬似多倍長法とは極めて相性が悪く、様々な 異常現象を引き起こす。例えばtwosumではいったん足して再度引くことによって エラーの計測を行っているが、なまじ中間変数の精度が高いために、正しくエラーが 測定できないというようなことが起こる。
SSE2の方はIEEE754に完全に従っている。
IntelのCPUでも、64bit環境だと基本的にSSE2のみを用いもはやFPUは使わないので、 このような異常現象は起きない。が、わざと-mfpmath=387とかすればその限りではない。 また、32bitCPUでも、-msse2 -mfpmath=sseとか付ければ安全になる。
小さな親切大きなお世話でFPUには困ったものだが、幸いなことにFPU Control Registerに FPUの計算精度を設定するフラグがあり、これを64bitから53bitに変更すれば この問題は避けられる。本ライブラリでは、fpu53.hをincludeして、 これを実行している。 コンパイラによってはこれがうまく動作しないなど考えられるので、何か問題があれば 報告して欲しい。
(version 0.4.54で仕様を変更) ddの演算が正しく動くためにははIEEE754に完全に従っている必要があり、 例えばIntel CPUの32bit環境はIEEE754に従わないことがあるので、 本ライブラリはコンパイルできないようになっている。 具体的には、#include <cfloat>した後マクロFLT_EVAL_METHODを調べ、 それが0でないならばエラーでコンパイルできないようにした。 Intel CPUの32bit環境でどうしてもkvを使いたい場合は、 コンパイルオプションとして -msse2 -mfpmath=sse を付けるなどして SSE2を使わせるようにすると、上記マクロが0になってコンパイルできるようになる。 このマクロが定義されないコンパイラ、あるいはSSE2を持たないCPUは、 古すぎるためサポートしないことにした。
double x, y; int i; y = frexp(x, &i);のように呼び出すと、xを入力として 0.5 ≤ |y| < 1、x=y×2iを満たすような yとiを計算してくれる関数である。 (IEEE754の指数部とは1ずれるが) 指数部を取り出してくれる関数としてよく用いられる。 ddに対しても、
kv::dd x, y; int i; y = frexp(x, &i);のように同様な関数を実装してある。
しかし、例えばx=1+2-1074のように ddの上位と下位の大きさが大きく離れている場合を考えると、 frexpの出力はy=0.5+2-1075、i=1となるべきであるが、 2-1075がdoubleで表現できないためそういう出力は不可能であるという 問題点がある。すなわち、doubleではfrexpは誤差の発生しない関数であるが、 ddでは誤差が発生する場合があることに注意が必要である。 なお、指数部iの方は常に信用できる。
conv-dd.hppに含まれているstringtodd, ddtostringは、dd型と10進数文字列の 相互変換を行うもので、実装は面倒だった。 単体でも使えるので、ddの入出力に困ってる人はぜひ使ってみて欲しい。
IEEE 754のdoubleと同様な無限大が実装されている。 内部表現は、(±∞, 0)である。