非正規化数

非正規化数（ひせいきかすう、"Denormalized Number"）または非正規数（ひせいきすう、"Denormal Number"）は、浮動小数点方式において「正規化」して表現できないような、0にごく近い、絶対値が極端に小さい数の表現法により表現された数である。英語では "Subnormal Number" とも。たとえばC言語の倍精度 (double) の場合、float.h により codice_1 という名前に定義される最小の正規化数よりも絶対値が小さい（つまりゼロに近い）。
概要.
一般に浮動小数点方式では、仮数部の上位桁にゼロが出現しないよう表現を調整する。たとえば、0.0123 は と表現される。これを「正規化」と言う。非正規化数は、正規化すると、表現に使用しようとしている表現方式で、指数が表現可能な範囲より小さくなってしまう数である（一般に浮動小数点では、仮数部・指数部のどちらも桁数は固定である）。たとえばIEEE 754の倍精度（binary64）では、指数が2−1022までしか表現できない。これより小さな数は、指数部のビットを全ゼロ（これは 0.0 と同じ）としたうえで2−1022を表しているものとし、仮数部は正規化されていない2進表現とする。
もう少し具体的に説明する。一般に浮動小数点数方式における仮数部は、位取り記数法による、重み付けの最も大きい方の桁の数字の並びである。ここで、ある桁数"p"の正の正規化数の仮数部を"m"0."m"1"m"2"m"3..."m""p"−2"m""p"−1とする。「正規化」の定義から、最上位桁 ("m"0) はゼロ以外である。二進法の場合、0でなければ常に1であるため、コンピュータのレジスタやメモリにおけるビット列などの具体的な表現では、常に1であることがわかっている最上位ビット (MSB) は省略してしまうことも可能である（いわゆるケチ表現）。この省略法を採用している場合、正規化数とは、この「省略された暗黙の1」がある数である、とも言える。
これに対し非正規化数は指数部の制限のために、ケチ表現とすることはできず、上位桁にゼロが埋められた数により (0."m"1"m"2"m"3..."m""p"−2"m""p"−1)、最小の正規化数よりも絶対値が小さい数を表現する。表現可能な桁数（すなわち相対精度）も低下する。
IEEE 754-2008 では、非正規化数は "subnormal number" と改名され、二進だけでなく十進の形式も規定されている。十進には前述の二進の場合のケチ表現のようなものは無いため、形式としても二進の場合のような違いはない。
gradual underflow.
演算の結果の絶対値が、厳密なゼロではないが表現可能な最小の正規化数のそれよりも小さい値になった場合を「アンダーフロー」とする。アンダーフローの際にゼロに丸めてしまう（しばしば「フラッシュ」 (flush) と表現される）こともあるが、非正規化数で表現することにより、徐々に精度は失われるが、ある程度は結果が救われることになる。そのようなアンダーフローのさせかたをgradual underflowと言う（漸近的、などと訳されるが定訳は（まだ）ない）。
背景.
非正規化数によって、浮動小数点数の加減算は決して「アンダーフローによるゼロ」にならないことが保証される（乗除算ではそれでも発生し得る）。2つの近い値の浮動小数点数には必ずゼロでない表現可能な差が存在する。漸近的アンダーフローを認めない場合、"a"−"b" という減算で2つの値に小さな差があったとしても、アンダーフローと判断して差をゼロにしてしまうことになる。すると、漸近的アンダーフローを採用していれば発生しないはずのゼロ除算が発生する原因にもなる。
IEEE 754 標準が作成されている間に、非正規化数は Intel 8087 で実装された。IEEE 754 として最終的に採用されたカハンらの提案の中で、この非正規化数の部分が最も議論を呼んだが、この実装が非正規化数が実際に使えることを証明した。FPUの実装によっては非正規化数をハードウェアで直接サポートしておらず、ソフトウェアで実現している。これはユーザーからは透過的だが、非正規化数を使った計算は正規化数による同じ計算よりも性能が悪くなる。
性能問題.
システムによっては、非正規化数を正規化数と同じ形でハードウェアで扱っている。実装によってはシステムソフトウェアに非正規化数の扱いを任せており、ハードウェアでは正規化数とゼロのみを処理する。非正規化数をソフトウェアで扱うと、性能が大きく低下する。しかし、非正規化数を完全にハードウェアで処理したとしても、現代の多くのプロセッサではやはり計算性能が大幅に低下する。アーキテクチャによっては、正規化数の100倍も時間がかかることがある。
精度を保ち、性能低下も防ぐ目的で、非正規化数を生じないようなコードにしてあるアプリケーションもある。例えば音声処理アプリケーションでは、非正規化数は信号が人間の耳に聞こえないほど小さい場合に出現する。そのため非正規化数となった信号部分はゼロにカットしてしまうという対策をとるのが一般的である。
インテル製のメインストリームのマイクロプロセッサの場合、IA-64とSSEにおいて、演算結果でgradual underflowを行わずゼロに丸めるFlush-to-Zero (FZ, FTZ) というハードウェア機能がある。SSEの後の拡張には、演算のオペランドにおいて非正規化数をゼロに丸めるDenormals-Are-Zero (DAZ) というハードウェア機能もある。どちらもcontrol/status register (CSR) のマスクで指定できる。。
参考文献.
ウィリアム・カハンのウェブサイト には非正規化数を使うことで計算結果を改善する例を示した論文などがある。