マリー=アントワネット様の素晴らしいお言葉に勇気付けられながら,IA-32 + MSVC++でのlog1pの1実装.
以下の実装はIA-32 + MSVC++な環境でのみ有効なコードです.
// log(1.0 + x)を計算する.特に|x| << 1.0で高精度であることが期待できる. double log1p(double x) { if(-1.0 + 1.4142135623730950488016887242097 / 2.0 < x && x < 1.0 - 1.4142135623730950488016887242097 / 2.0) { __asm{ fldln2; fld qword ptr [x]; fyl2xp1; fstp qword ptr [x]; } } else{ x = std::log(1.0 + x); } return x; }
GCCでは
expm1もほぼ同様.とゆ〜か,昨日貼ったexp(x)のアセンブリで最後に1足している部分を削るだけ.また,|x| < 1.0が対象なのでfrndintで(-1.0, 1.0)に縮小して,後でfscaleで元の大きさに拡大する変形(な変形)も不要になる.
以下の実装はIA-32 + MSVC++な環境でのみ有効なコードです.
// exp(x) - 1.0 を計算する.特に|x| << 1.0において高精度であることが期待できる. double expm1(double x) { if(-1.0 < x && x < 1.0){ __asm{ fld qword ptr [x]; fldl2e; fmulp st(1), st; f2xm1; fstp qword ptr [x]; } } else{ x = std::exp(x) - 1.0; } return x; }
log1pと同様,これもGCCでは
参考資料
http://intel.com/jp/developer/download/#ia32
にある資料のうち,特に以下の2つ.
IA-32における浮動少数演算の基本資料.
IA-32における浮動少数演算の各命令セットのためのリファレンス.浮動少数演算系の命令セットはFで始まるので,浮動少数演算だけならだいたいこのAからMのリファレンスで事足りる.