「この場合、2 つの double を使用して値を格納します。そのため、一度に 2 つの操作を行う必要があります。」</p>
これは double-double 算術がどのように機能するかではありません。実装される実際の演算、融合乗算加算演算の可用性、一方のオペランドが他方よりも大きいという仮定に応じて、1 つの double-double 演算が 6 ~ 20 回の double 演算で実装されることを期待する必要があります。 </p>
たとえば、CRlibmから取得した、FMA 命令が使用できない場合の double-double 乗算の実装の 1 つを次に示します。
#define Mul22(zh,zl,xh,xl,yh,yl) \
{ \
double mh, ml; \
\
const double c = 134217729.; \
double up, u1, u2, vp, v1, v2; \
\
up = (xh)*c; vp = (yh)*c; \
u1 = ((xh)-up)+up; v1 = ((yh)-vp)+vp; \
u2 = (xh)-u1; v2 = (yh)-v1; \
\
mh = (xh)*(yh); \
ml = (((u1*v1-mh)+(u1*v2))+(u2*v1))+(u2*v2); \
\
ml += (xh)*(yl) + (xl)*(yh); \
*zh = mh+ml; \
*zl = mh - (*zh) + ml; \
}
最初の 8 つの操作だけで、オペランドの各 double を 2 つの半分に正確に分割するためのものです。これにより、各側の半分を反対側の半分で乗算し、結果を a として正確に取得できdouble
ます。計算u1*v1
、u1*v2
、 … はまさにそれを行います。
mh
とで取得された値ml
は重複する可能性があるため、最後の 3 つの演算は、結果を 2 つの浮動小数点数の合計に再正規化するためにあります。
この場合、各 double に丸め誤差が発生する可能性がありますか、それともこれを回避するメカニズムですか?
コメントが言うように:
/*
* computes double-double multiplication: zh+zl = (xh+xl) * (yh+yl)
* relative error is smaller than 2^-102
*/
これらの結果を達成するために使用されるすべてのメカニズムについては、Handbook of Floating-Point Arithmetic を参照してください。