浮動小数点数演算における保護桁について

浮動小数点数同士を足したり引いたりする場合、その数学的な結果は浮動小数点数で表せるとは限りません。 そのため、結果を適当に浮動小数点数に戻す、丸めが行われます。 丸めを行うためには、最終的な結果に使われる桁数より少し多く情報を保持しておく必要があります。 そのような部分のことを、保護桁と言います。

正確に丸める最も簡単な方法は、丸める前の結果を正確に求める、というものです。 しかしそうするには、かなり大きなビット幅の加算器が必要になります。 幸運なことに、これを回避する方法があります。 最終的な結果に使われる桁数よりもずっと離れた桁の計算はしないというものです。 具体的には、最終的な結果に使われる桁数に加えて3bit余分にあれば、IEEE754で規定された丸めを行うことができます。

この記事では、なぜ余分に3bit必要なのかを説明します。 この3bitには名前がついていて、それぞれ上の桁から「ガードビット」「ラウンドビット」「スティッキービット」となっています。 ガードビットは保護桁の最上位のビット、ラウンドビットはその次のビットを意味しています。 スティッキービットは特殊で、その次以降が全て0ではない(1がいくつか立っている)ことを意味するビットです。

以下では、説明が冗長になることを防ぐため、以下の太字用語を定義して使います。

結論から書くと、以下のようになります。

  • 加算の結果を偶数丸めする場合、ラウンドビットは不要で、ガードビットとスティッキービットのみが必要
  • 減算の結果を偶数丸めする場合、ガードビットとスティッキービットだけでなくラウンドビットも必要
    • 加算と違ってラウンドビットが必要なのは、繰り下がりが発生してガードビット部分が最終結果に使われる場合があるため

加算する場合

浮動小数点数では符号+指数部+絶対値表現なので、以下では符号のことは考えずに絶対値部分のみを考えます。

加算する場合、以下のように桁合わせをしてから加算器に入力することになります。 ここで、桁合わせしてはみ出た部分は、最終結果には直接的には使われません。 したがって、この部分が保護桁であるということになります。 なお、最上位桁に繰上りが発生した場合は、最終結果に使われない部分が1bit増えますが、保護桁が不足するのではなく余るだけなので、問題にはなりません。

図1: 加算する場合の様子

桁合わせしてはみ出た部分については、片側のオペランドが0なので、特に計算せずガードビット(G)とスティッキービット(S)が求まります。

ガードビットが必要なのは、最近接丸めを実現するためです。 0.5より少ないか多いかを判断するために必要になります。 スティッキービットが必要なのは、偶数丸めを実現するためです。 0.5ちょうどなのか0.5より多いのかを判断するために必要になります。 つまり、四捨五入丸め(round nearest, ties to away)をサポートすればよい場合、スティッキービットは不要です。 また、ゼロへの丸めをサポートすればよい場合、ガードビットもスティッキービットも不要です。 他にも丸めモードは多数ありますが、ガードビットとスティッキービットさえあればいずれにも対応できます。

丸めモードごとの各ビットの要不要は以下のようになります。 ここで、「ガードビット不要・スティッキービット必要」とは、はみ出した部分に1があるかを判定するスティッキービットのみが必要であるという意味です。

丸めモード G S
ゼロへの丸め 不要 不要
正の無限大への丸め 不要 必要
負の無限大への丸め 不要 必要
偶数丸め 必要 必要
奇数丸め 不要 必要
四捨五入丸め 必要 不要

偶数丸めを行う場合、ガードビットとスティッキービットの使い方は以下のようになります。

G S 動作
0 0 そのまま
0 1 そのまま
1 0 結果の仮数部の最下位が1ならば1を加える
1 1 結果の仮数部に1を加える

減算する場合

減算する場合も、以下のように桁合わせをしてから加算器に入力することになります。 ここで、桁合わせしてはみ出た部分が保護桁なのですが、注意するべき点があります。 それは、最上位桁で繰り下がりが発生した場合、最終結果に使われないとは言い切れない点です。 ここでは、以下の二通りに分類して考えてみます。

指数部が近く、多数桁の桁落ちが発生しうる場合

オペランドの指数部の差が0か1である場合が相当します。 この場合、桁落ちが発生しますが、結果は浮動小数点数で正確に表せます。 したがって、桁合わせしてはみ出た部分(高々1bit)を含めて加算器に入力し、出力を桁合わせすれば計算完了です。

指数部が近くないので、多数桁の桁落ちが発生しない場合

オペランドの指数部の差が2以上である場合が相当します。 多数桁の桁落ちが発生しないとは言っても、最上位桁の繰り下がりが発生する場合はあります。 その場合、最終結果の有効数字が1bit足りなくなるので、保護桁から捻出する必要が発生します。 よって、加算の時と比べてもう1bit必要で、ガードビット(G)・ラウンドビット(R)・スティッキービット(R)の3bitが必要です。

図2: 減算する場合の様子

足し算の時はあふれたビットがそのまま保護桁となりましたが、引き算の場合はあふれたビットも含めて引き算をして保護桁の値を決定します。 スティッキービットを決めるためには完全な引き算は必要なく、関係するビットを全てORしたものを減算器に入力すれば十分です。 つまり、3bit分だけ幅広だけの減算器が必要ということになります。

減算の場合、四捨五入すればいい場合でもスティッキービットまで必要です(五捨五超入なら不要です)。

偶数丸めを行う場合、保護桁の使い方は以下のようになります。

最上位桁の繰り下がり G R S 動作
なし 0 x x そのまま
なし 1 0 0 結果の仮数部の最下位が1ならば1を加える
なし 1 0 1 結果の仮数部に1を加える
なし 1 1 x 結果の仮数部に1を加える
あり - 0 x そのまま(Gが仮数部の最下位ビットとなる)
あり - 1 0 Gが1ならば結果の仮数部に1を加える
あり - 1 1 結果の仮数部に1を加える

なお、加算の時と回路を共有することを考えると、桁合わせの際に1bitずらして配置することで以下を共通化できるので、そういった構成法がよいかもしれません。

  • 桁合わせに必要な1bit右シフト回路
    • 1bitずらさないと、1bit左シフト回路も必要になる
  • ラウンドビットが不要
  • 丸める際の補正が0か+1しか出てこない

参考文献