浮動小数点データ形式は限定されたビット数のFractionでデータを表現するので、1/3のような循環小数や、πなどの無理数を正確に表現することは出来ない。このように誤差を含んだ数値で計算を行った場合、得られた結果がどの程度の誤差を含んでいるのか分からないという問題がある。
これに対して、全ての数値を、正確に表現できる上限と下限の数値のペアで表わし、足し算であれば、正確な加算結果は両方のオペランドの上限の和と、下限の和の間にあり、乗算であれば、両方のオペランドの上限と下限の全ての組み合わせの積のうちの最小のものと、最大のものの間にあるというように、常に、結果の上限と下限のペアを計算していくというやり方が有る。このように計算を行えば、正確な答えは、上限と下限の間にあることは保証される。このような計算法を区間演算(Interval Arithmetic)という。
一般の計算では、最下位ビットより下位の桁の数については四捨五入というような方法が用いられるが、区間演算の場合は、上限を計算する場合は切り上げ、下限を計算する場合は切り捨てというような計算が必要となる。IEEE 754規格では、このような区間演算などに対応するため、四捨五入以外に、切り上げ、切捨て、+∞、-∞方向への丸めが定義されている。
ガードビット、ラウンドビットとスティッキービット
無限精度での計算結果に対して、このような各種の丸めを適用した場合と同じ結果を得るためには、結果の有効ビットだけの計算では不足で、結果の最下位のビットの下に、ガードビット、更にその下にラウンドビットと呼ぶ、2ビット分の計算が必要である。そして、切り上げなどに正しく対応するためには、ラウンドビットより下位の位置に一つでも"1"があるかどうかを示すスティッキービットを計算する必要がある。
図4:正確に丸めを行うため、IEEE754ではガードビット、ラウンドビット、スティッキービットを計算する |
デノーマル数(非正規化数)
IEEE 754形式では、EXP部が0と最大値の場合は通常のデータ表現には使用せず、特別な用途にリザーブされている。指数部がゼロの場合は、次の図に示すデノーマル(Denormal)数という小さな数を表わす。
図5:デノーマル数と、最小EXPの正規の数。クリーム色のヒドンビット部分が、デノーマル数では"0"となる |
IBM Hexのような従来の表現形式では、最小の数値より小さくなる(アンダーフロー)が起こると、それより小さい数はゼロになってしまっていたが、IEEE 754では、デノーマル数という表現形式を用いて、有効ビット数は徐々に低下するものの、より小さい数値の表現が可能になっている。この機能をグラデュアルアンダーフロー(Gradual Underflow)と呼んでいる。
このようにデノーマル数は、 精度の点では有効な機能であるが、計算を開始するまえに正規化のためのシフトが必要であり、通常の浮動小数点数とは異なる処理が必要となる。このため、多くのプロセサでは、デノーマル数が演算のオペランドとして入力されるとトラップを発生して、ソフトウェアで処理を行うという方法がとられている。
IEEE 754規格では、全ての機能をハードウェアで実装することは求められておらず、ハード処理の困難な機能をソフトウェアで実装することはなんら問題ではない。それどころか、極端に言えば、規格準拠という点では、全ての浮動小数点演算処理をソフトウェアで行っても良いのである。
プログラムの計算結果としては、ソフトウェア処理でも結果がIEEE 754の規定に照らして正しければ良いのであるが、現実には、デノーマル数が比較的高い頻度で発生するようなプログラムでは性能がガタ落ちになる。となると、当然、精度は多少我慢しても良いから性能を落とすなというユーザが出てくるわけで、例えば、IA32プロセサではMXCSRレジスタにdenormals-are-zeroというフラグがあり、このビットをセットしておくと、演算結果がデノーマル数となってもトラップを発生せず、黙って、結果をゼロにしてしまう。SPARCにも同様にNon-Standardフラグがあり、結果がデノーマル数になると自動的にゼロにしてしまう機能がある。
しかし、POWER2.03仕様にはデノーマル数が出現した場合のトラップが定義されていないので、多分、全てハードウェアで処理しているのであろう。但し、ハードウェア処理と言っても、内部ではマイクロプログラムで処理されている可能性もあり、その場合は、やはり、実行時間はあまり速くない可能性がある。