コンピュータにおいて、浮動小数点演算(FP)とは、仮数(ある基数における固定桁数の符号付き数列)にその基数の整数乗を乗じることによって形成される実数の部分集合に対する演算である。この形式の数は浮動小数点数と呼ばれる。[ 1 ] : 3 [ 2 ] : 10
例えば、2469/200という数値は、10進数で表した5桁の浮動小数点数です。 しかし、7716/625 = 12.3456 は、5 桁の 10 進浮動小数点数ではありません。6桁が必要です。5 桁のみで最も近い浮動小数点数は 12.346 です。また、1/3 = 0.3333… は、有限桁数の 10 進浮動小数点数ではありません。実際には、ほとんどの浮動小数点システムは2 進数を使用しますが、10 進数 ( 10 進浮動小数点数) も一般的です。
加算や除算などの浮動小数点演算は、対応する実数演算を近似し、浮動小数点数でない結果を近くの浮動小数点数に丸めます。 [ 1 ] : 22 [ 2 ] : 10 例えば、10進数5桁の浮動小数点演算では、合計12.345 + 1.0001 = 13.3451は13.345に丸められる可能性があります。
浮動小数点という用語は、数値の小数点が、数値の有効数字の左、右、または数字の間など、任意の位置に「移動する」可能性があることを指します。この位置は指数によって示されるため、浮動小数点数は科学的記数法の一種と考えることができます。
浮動小数点システムは、固定桁数で、銀河間の距離や原子内の陽子間の距離など、桁の異なる非常に大きな数値を表現するために使用できます。このため、浮動小数点演算は、高速な処理時間を必要とする非常に小さい実数と非常に大きい実数を扱うためによく使用されます。このダイナミックレンジの結果、表現できる数値は均等に間隔が置かれておらず、連続する2つの表現可能な数値の差は指数によって変化します。[ 3 ]


長年にわたり、コンピュータではさまざまな浮動小数点表現が使用されてきました。1985年には、浮動小数点演算に関するIEEE 754規格が制定され、1990年代以降、最も一般的に使用されている表現はIEEEによって定義されたものです。
浮動小数点演算の速度は、一般的にFLOPSという単位で測定され、特に高度な数学的計算を伴うアプリケーションにおいては、コンピュータシステムの重要な特性となる。
浮動小数点数は、ソフトウェア実装(ソフトフロート)またはハードウェア実装(ハードフロート)を使用して計算できます。浮動小数点演算ユニット(FPU、通称:数学コプロセッサ)は、浮動小数点数の演算を実行するために特別に設計されており、ほとんどのコンピュータシステムに搭載されています。FPUが利用できない場合は、代わりにソフトウェア実装を使用できます。
数値表現とは、数値を符号化する方法を指定するもので、通常は数字列として表現される。
数字列で数値を表現する方法はいくつかあります。標準的な数学表記では、数字列の長さは任意で、小数点の位置は明示的な「点」文字(ドットまたはコンマ)を配置することで示されます。小数点が指定されていない場合、その数字列は暗黙的に整数を表し、指定されていない小数点は、最下位桁の隣、つまり数字列の右端に位置します。固定小数点システムでは、小数点の位置が数字列内で指定されます。したがって、固定小数点方式では、小数点が中央にある8桁の10進数列を使用することができ、その場合、「00012345」は0001.2345を表します。
科学的記数法では、与えられた数値は10のべき乗でスケーリングされ、特定の範囲(通常は1から10の間)に収まるように調整されます。小数点(基数)は最初の桁の直後に現れます。10のべき乗として、スケーリング係数は数値の末尾に別々に示されます。たとえば、木星の衛星イオの公転周期は152,853.5047秒、標準形式の科学的記数法では次のように表されます。1.528535047 × 10⁵秒。
浮動小数点表現は、概念的には科学的記数法に似ています。論理的には、浮動小数点数は以下で構成されます。
浮動小数点数の値を求めるには、仮数を指数で累乗した基数を乗算します。これは、基数を暗黙の位置から指数の値に等しい桁数だけずらすことに相当します。指数が正の場合は右に、指数が負の場合は左に移動します。
10進法(おなじみの十進表記)を例にとると、152,853.5047は、10 桁の精度を持つ有効数字として表されます。1528535047に指数として 5 を付けます。実際の値を求めるには、仮数の最初の桁の後に小数点を付け、その結果に10を掛けます。5つ与える1.528535047 × 10 5または152,853.5047。このような数値を保存する場合、基数(10)は保存する必要はありません。なぜなら、基数はサポートされている数値の範囲全体で同じであり、推測できるからです。
象徴的に言えば、この最終値は次のようになります。
ここで、 sは仮数(暗黙の小数点を無視)、pは精度(仮数の桁数)、bは底(この例では 10 )、eは指数です。
歴史的に、浮動小数点数を表現するためにいくつかの基数が使用されてきましたが、最も一般的だったのは基数2(バイナリ)で、次に基数10( 10進浮動小数点)が続き、その他にもあまり一般的ではない種類として、基数16(16進浮動小数点[ 4 ] [ 5 ] [ nb 3 ])、基数8(8進浮動小数点[ 1 ] [ 5 ] [ 6 ] [ 4 ] [ nb 4 ])、基数4(4進浮動小数点[ 7 ] [ 5 ] [ nb 5 ])、基数3(バランス型3進浮動小数点[ 1 ])、さらには基数256 [ 5 ] [ nb 6 ]などがあります。65,536 . [ 8 ] [ nb 7 ]
浮動小数点数は有理数です。なぜなら、ある整数を別の整数で割ったものとして表現できるからです。例えば、1.45 × 10 3は (145/100)×1000 または145,000 / 100。基数は表現できる分数を決定します。たとえば、1/5 はバイナリ基数では浮動小数点数として正確に表現できませんが、1/5 は 10 基数 (0.2、または2 × 10 −1 )。ただし、1/3 はバイナリ (0.010101...) または 10 進数 (0.333...) のどちらでも正確には表せませんが、基数 3では自明です (0.1 または 1×3 −1 )。無限展開が発生する場合、基数とその素因数に依存します。
仮数部(符号を含む)と指数部がコンピュータに格納される方法は、実装に依存します。一般的な IEEE フォーマットについては後述および他の場所で詳しく説明しますが、例として、バイナリ単精度 (32 ビット) 浮動小数点表現では、したがって、仮数は24ビットの文字列になります。例えば、数πの最初の33ビットは次のようになります。
このバイナリ展開では、位置を0(最左端のビット、または最上位ビット)から32(最右端のビット)までとします。24ビットの仮数は、 下線で示されている位置23で停止します。上記0。次のビットは位置24にあり、ラウンドビットまたは丸めビット と呼ばれます。これは、33ビット近似値を最も近い24ビット数に丸めるために使用されます(中間値には特定のルールがありますが、ここでは該当しません)。このビットは、この例では、 1 が左端の 24 ビットで構成される整数に加算され、次のようになります。
これをIEEE 754エンコーディングを使用してメモリに格納すると、仮数sになります。仮数は、最左ビットの右側にバイナリ小数点があると想定されます。したがって、πのバイナリ表現は、左から右に次のように計算されます。
ここでpは精度 (この例では24 ですが、 nは仮数のビットの左からの位置です (0で終了23ここで)eは指数です(この例では1)。
非ゼロ数の仮数の最上位桁が非ゼロであることが要求される場合があります(対応する指数が最小の指数より小さくなる場合を除く)。このプロセスは正規化と呼ばれます。バイナリ形式(数字のみを使用する)の場合、0と1 ) このゼロ以外の数字は必ず1.したがって、メモリに表現する必要がないため、フォーマットの精度が1ビット高くなります。このルールは、先頭ビット規約、暗黙のビット規約、隠しビット規約[ 1 ]、または想定ビット規約などと呼ばれています。
浮動小数点表現は、コンピュータ上で実数の近似値を表現する最も一般的な方法です。しかし、他にも代替手段があります。

1914年、スペインのエンジニア、レオナルド・トーレス・ケベドは『自動計算機に関するエッセイ』 [ 9 ]を出版し、チャールズ・バベッジの解析機関に基づいた特殊用途の電気機械式計算機を設計し、浮動小数点数を一貫した方法で格納する方法を説明した。彼は、数値は指数形式で格納されると述べた。トーレスは、浮動小数点数を機械で一貫して操作するための 3 つのルールを提案した。トーレスによれば、「n は常に同じ桁数 (例えば 6 桁) であり、 nの最初の桁は 10 分の 1 のオーダー、2 番目は 100 分の 1 のオーダーなどであり、各数量はn ; mの形式で記述される」。彼が提案した形式は、現在浮動小数点データに使用されている固定サイズの仮数子の必要性、各表現が一意になるように仮数子内の小数点の位置を固定すること、そして1920 年の彼の電気機械式算術計の場合のように、タイプライターで入力できる構文を指定することによってそのような数値をフォーマットする方法を示している。 [ 10 ] [ 11 ] [ 12 ]

1938年、ベルリンのコンラート・ツーゼは、最初のバイナリ式プログラム可能な機械式コンピュータであるZ1を完成させました。[ 13 ] Z1は、7ビットの符号付き指数部、17ビットの仮数部(1ビットの暗黙のビットを含む)、および符号ビットを備えた24ビットのバイナリ浮動小数点数表現を使用しています。[ 14 ] 1941年に完成した、より信頼性の高いリレーベースのZ3は、正と負の無限大の両方の表現を備えています。特に、無限大による除算など、無限大を用いた定義済みの演算を実装しています。、そして、次のような未定義の操作で停止します。。
ツゼはまた、慎重に丸められた浮動小数点演算を提案したが、完成させることはなかった。また、NaN表現も実装しており、IEEE標準の機能を40年も先取りしていた。[ 15 ]対照的に、フォン・ノイマンは1951年のIASマシンでは浮動小数点数の使用を推奨せず、固定小数点演算の方が望ましいと主張した。[ 15 ]
浮動小数点ハードウェアを搭載した最初の商用コンピュータは、1942年から1945年にかけて設計されたZuseのZ4コンピュータでした。1946年には、ベル研究所が10進浮動小数点数を実装したModel Vを発表しました。[ 16 ]
Pilot ACEはバイナリ浮動小数点演算機能を備えており、1950年に英国国立物理研究所で運用が開始されました。その後、33台がEnglish Electric DEUCEとして市販されました。演算は実際にはソフトウェアで実装されていますが、1メガヘルツのクロック周波数により、このマシンの浮動小数点演算と固定小数点演算の速度は、当初は多くの競合コンピュータよりも高速でした。
1954年には量産型のIBM 704が登場し、バイアス付き指数法が導入されました。その後数十年間、浮動小数点ハードウェアは通常オプション機能であり、それを搭載したコンピュータは「科学コンピュータ」または「科学計算」(SC)機能を持つと言われていました(科学計算拡張機能(XSC)も参照)。汎用パーソナルコンピュータに浮動小数点機能が標準搭載されるようになったのは、1989年にIntel i486が発売されてからのことです。
1962年に発表されたUNIVAC 1100/2200シリーズは、2種類の浮動小数点表現をサポートしていました。
同じく1962年に発表されたIBM 7094は、単精度と倍精度の表現をサポートしていましたが、UNIVACの表現とは何の関係もありませんでした。実際、IBMは1964年にSystem/360メインフレームで16進浮動小数点表現を導入しました。これらの表現は、現代のz/Architectureシステムでも引き続き利用可能です。1998年には、IBMはメインフレームでIEEE互換の2進浮動小数点演算を実装し、2005年にはIEEE互換の10進浮動小数点演算も追加しました。
当初、コンピュータは浮動小数点数を表現するために様々な異なる方法を用いていました。1970年代初頭には、メインフレームレベルでの標準化の欠如が、高レベルのソースコードを記述・保守する人々にとって継続的な問題となっていました。これらのメーカー独自の浮動小数点規格は、ワードサイズ、表現方法、丸め動作、演算の全体的な精度において異なっていました。1980年代初頭には、複数のコンピュータシステム間での浮動小数点互換性の標準化が切実に求められており、32ビット(または64ビット)ワードが一般的になったことで、 IEEE 754規格が策定されました。この規格は、 i8087数値コプロセッサを設計していたインテルの提案に大きく基づいており、同時期に68000を設計していたモトローラも重要な貢献をしました。

1989年、数学者でコンピュータ科学者のウィリアム・カーンは、この提案の主要な立案者としてチューリング賞を受賞しました。彼は教え子のジェローム・クーネンと客員教授のハロルド・ストーンの協力を得ました。[ 17 ]
x86(より具体的にはi8087)の革新技術には、以下のようなものがある。
これらの機能は IEEE 754-1985 に継承されます (特殊値と例外のエンコードを除く)。ただし、x87 の内部精度が拡張されているため、標準の IEEE 754 の結果に合わせるには、正確な結果を宛先精度に直接明示的に丸める必要があります。[ 18 ]ただし、拡張フォーマットの指数範囲が広い可能性があるため、動作は宛先フォーマットへの丸めと同じではない場合があります。
浮動小数点数は、2つの固定小数点成分から構成され、その範囲は表現におけるビット数または桁数のみに依存します。固定小数点成分は範囲に線形的に依存するのに対し、浮動小数点数の範囲は仮数部の範囲に線形的に依存し、指数部の範囲には指数関数的に依存するため、数値の範囲が非常に広くなります。
一般的なコンピュータ システムでは、倍精度(64 ビット) のバイナリ浮動小数点数は、係数が 53 ビット (暗黙の 1 ビットを含む)、指数が 11 ビット、符号が 1 ビットです。2 10 = 1024 なので、この形式の正の正規浮動小数点数の完全な範囲は、2 −1022 ≈ 2 × 10 −308から約 2 1024 ≈ 2 × 10 308までです。
システム ( B、P、L、U )内の通常の浮動小数点数の数
は、 または値0を考慮する。
最小の正の通常の浮動小数点数があり、
仮数の先頭桁が1で、残りの桁が0であり、指数が可能な限り最小の値である。
最大の浮動小数点数があり、
これは、仮数の各桁の値がB − 1 であり、指数が可能な限り最大の値であることを意味します。
さらに、−UFLとUFLの間には厳密に表現可能な値が存在する。すなわち、正のゼロと負のゼロ、および正規化されていない数である。
IEEEは1985年に、バイナリ浮動小数点数のコンピュータ表現をIEEE 754(別名IEC 60559)で標準化しました。この最初の標準は、現代のほとんどすべてのマシンで採用されています。2008年に改訂されました。IBMメインフレームは、IEEE 754バイナリ形式に加えて、IBM独自の16進浮動小数点形式とIEEE 754-200810進浮動小数点形式をサポートしています。Cray T90シリーズにはIEEEバージョンがありましたが、SV1は依然としてCray浮動小数点形式を使用しています。
この規格では、細部がわずかに異なるだけで、非常に類似した多くのフォーマットが規定されています。これらのフォーマットのうち5つは基本フォーマットと呼ばれ、その他は拡張精度フォーマットおよび拡張可能精度フォーマットと呼ばれます。特にコンピュータハードウェアやプログラミング言語で広く使用されているフォーマットは次の3つです。
浮動小数点表現の精度を上げると、中間計算によって生じる累積丸め誤差が一般的に減少します。 [ 25 ] その他のIEEEフォーマットには以下が含まれます。
絶対値が2²⁴未満の整数は単精度形式で正確に表現でき、絶対値が 2⁵³ 未満の整数は倍精度形式で正確に表現できます。さらに、そのような数の 2 倍のべき乗の幅広い範囲を表現できます。これらの特性は、倍精度浮動小数点数は備えているものの 32 ビット整数しか扱えないプラットフォームで 53 ビット整数を取得するために、純粋な整数データに使用されることがあります。
この規格では、いくつかの特殊な値とその表現が規定されています。正の無限大(+∞)、負の無限大(−∞)、通常の(「正の」)ゼロとは異なる負のゼロ(−0)、および「非数」値(NaN)。
IEEE規格で定義されている浮動小数点数の比較は、通常の整数の比較とは少し異なります。負のゼロと正のゼロは等しいとみなされ、NaNはそれ自身を含め、他のすべての値とは等しくないとみなされます。すべての有限浮動小数点数は、+∞より厳密に小さく、 −∞より厳密に大きく、実数集合における値と同じ順序で並びます。
浮動小数点数は通常、左から右へ、符号ビット、指数部、仮数部の順にコンピュータデータに格納されます。現存するハードウェア実装を持つIEEE 754バイナリ形式(基本形式と拡張形式)では、以下のように割り当てられます。
指数は正または負の値をとることができますが、バイナリ形式では、固定の「バイアス」が加算された符号なし数として格納されます。このフィールドのすべての値が 0 の場合は、ゼロと非正規数用に予約されています。すべての値が 1 の場合は、無限大と NaN 用に予約されています。正規数の指数範囲は、単精度では [−126, 127]、倍精度では [−1022, 1023]、四倍精度では [−16382, 16383] です。正規数には、非正規値、ゼロ、無限大、および NaN は含まれません。
IEEEバイナリ交換フォーマットでは、正規化された仮数の先頭ビットは常に1であるため、コンピュータデータには実際には格納されません。これは「隠された」ビットまたは「暗黙の」ビットと呼ばれます。このため、単精度フォーマットでは仮数の精度は24ビット、倍精度フォーマットでは53ビット、4倍精度フォーマットでは113ビット、8倍精度フォーマットでは237ビットとなります。
例えば、上記で示したように、πを24ビット精度に丸めると、次のようになります。
指数バイアス(127)と指数(1)の合計は128なので、これは単精度形式で次のように表されます。
32ビット浮動小数点のレイアウトの例は次のとおりです。

64ビット(「倍精度」)レイアウトも同様です。
広く用いられているIEEE 754標準フォーマットに加えて、特定の分野においては、他の浮動小数点フォーマットが使用されている、あるいは使用されてきた。
浮動小数点形式で表現されるすべての数値は、その性質上、関連する基数で有限小数展開を持つ有理数です(たとえば、基数10での有限小数展開、または基数2での有限二進数展開)。πや1000などの無理数は、、または非終止有理数は近似する必要があります。精度の桁数(またはビット数)によって、正確に表現できる有理数のセットも制限されます。たとえば、10 桁の精度が 8 桁しかない場合、10 進数 123456789 を正確に表現することはできません (表現可能な 2 つの値、12345678 × 10 1または 12345679 × 10 1のいずれかに丸められます)。非終止桁の場合も同様です(. 5 は.55555555 または .55555556 のいずれかに丸められます)。
数値が、コンピュータの実装でサポートされているネイティブの浮動小数点表現ではない形式(文字列など)で表現されている場合、その実装で使用するには変換が必要です。数値が浮動小数点形式で正確に表現できる場合は、変換は正確です。正確な表現がない場合は、元の値を表すためにどの浮動小数点数を使用するかを選択する必要があります。選択された表現は元の値とは異なる値になり、このように調整された値は丸め値と呼ばれます。
有理数が有限展開を持つかどうかは、基数によって決まります。たとえば、10進数では、1/2 は有限展開 (0.5) を持ちますが、1/3 は有限展開を持ちません (0.333...)。2進数では、分母が 2 のべき乗 (1/2 や 3/16 など) の有理数のみが有限展開を持ちます。分母が 2 以外の素因数を持つ有理数は、無限の二進展開を持ちます。これは、10 進数で記述すると短く正確な数値に見える数値でも、2 進浮動小数点数に変換する際には近似値が必要になる場合があることを意味します。たとえば、10 進数の 0.1 は、有限精度の 2 進浮動小数点数では表現できません。正確な 2 進数表現では、「1100」のシーケンスが無限に続きます。
ここで、これまでと同様に、sは仮数、eは指数である。
24ビットに丸めると、
これは実際には10進数で0.100000001490116119384765625です。
さらに別の例として、実数πを無限ビット列としてバイナリで表すと次のようになります。
しかし、
24ビットの精度に丸めて近似した場合。
バイナリ単精度浮動小数点では、これはs = 1.10010010000111111011011 とe = 1 で表されます。これは 10 進数値で
一方、πの真の値のより正確な近似値は
丸め処理の結果は、真の値と約0.03ppmの差があり、πの小数表現の最初の7桁と一致します。この差は離散化誤差であり、マシンのイプシロンによって制限されます。
同じ指数を持つ連続する2つの表現可能な浮動小数点数の算術差を、最下位位の単位(ULP) と呼びます。たとえば、表現可能な数 1.45A70C22 16と 1.45A70C24 16の間に表現可能な数がない場合、ULP は 2×16 −8、つまり 2 −31です。2 進数の指数部が 0 である数、つまり絶対値が 1 以上 2 未満の数の場合、ULP は単精度では正確に 2 −23、つまり約 10 −7であり、倍精度では正確に 2 −53、つまり約 10 −16です。IEEE 準拠のハードウェアの必須動作は、結果が ULP の 1/2 以内であることです。
丸めは、浮動小数点演算 (または浮動小数点形式への変換) の正確な結果が、仮数の桁数よりも多くの桁数を必要とする場合に使用されます。 IEEE 754 では正しい丸めが要求されます。つまり、丸められた結果は、無限精度の算術を使用して値を計算し、その後丸めた場合と同じになります (ただし、実装では、これを保証するために 3 ビットだけ追加する必要があります)。丸め方式 (または丸めモード) にはいくつかの種類があります。 歴史的には、切り捨てが一般的なアプローチでした。 IEEE 754 の導入以来、デフォルトの方法 (最も近い値に丸め、同数の場合は偶数に丸める、バンカーズ ラウンドと呼ばれることもあります) がより一般的に使用されています。 この方法は、算術演算の理想的な (無限精度の) 結果を最も近い表現可能な値に丸め、その表現を結果として与えます。[ nb 8 ]同数の場合は、仮数が偶数で終わる値が選択されます。 IEEE 754規格では、平方根や変換を含むすべての基本的な代数演算において、数値(NaN以外)の結果が得られる場合、同じ丸め処理を適用することが求められています。つまり、IEEE 754演算の結果は、NaNの表現を除き、結果のすべてのビットで完全に決定されます。(cosやlogなどの「ライブラリ」関数は必須ではありません。)
代替の丸め方法も利用可能です。IEEE 754では、以下の丸めモードが規定されています。
代替モードは、導入される誤差の量を制限する必要がある場合に役立ちます。誤差の制限が必要なアプリケーションは、多倍長浮動小数点演算と区間演算です。代替丸めモードは、数値的不安定性の診断にも役立ちます。サブルーチンの結果が、+ 無限大と − 無限大への丸めで大きく異なる場合、数値的に不安定で丸め誤差の影響を受けている可能性が高いです。[ 35 ]
倍精度バイナリ浮動小数点数を10進数文字列に変換することは一般的な操作ですが、正確かつ最小限の計算量で結果を生成するアルゴリズムは、1990年にSteeleとWhiteによるDragon4が登場するまで出版されませんでした。それ以降の改良点には以下のようなものがあります。
多くの最新の言語ランタイムは、Dragon4 のフォールバックを備えた Grisu3 を使用しています。[ 42 ]
10進数文字列を2進数浮動小数点表現に解析する問題は複雑で、正確なパーサーは1990年のClingerの研究(dtoa.cに実装)まで登場しなかった。[ 36 ]同様に、より高速な解析の方向でさらなる研究が進められた。[ 43 ]
分かりやすくするために、例ではIEEE 754 decimal32形式と同様に、7桁の精度を持つ10進数を使用します。基数や精度に関わらず基本的な原理は同じですが、正規化は任意です(結果の数値には影響しません)。ここで、sは仮数、eは指数を表します。
浮動小数点数を加算する簡単な方法は、まず同じ指数で表現することです。以下の例では、2番目の数(指数が小さい方)を3桁右にシフトし、その後、通常の加算方法で計算を進めます。
123456.7 = 1.234567 × 10^5 101.7654 = 1.017654 × 10^2 = 0.001017654 × 10^5
したがって: 123456.7 + 101.7654 = (1.234567 × 10^5) + (1.017654 × 10^2) = (1.234567 × 10^5) + (0.001017654 × 10^5) = (1.234567 + 0.001017654) × 10^5 = 1.235584654 × 10^5
詳細:
e=5; s=1.234567 (123456.7) + e=2; s=1.017654 (101.7654)
e=5; s=1.234567 + e=5; s=0.001017654 (シフト後) -------------------- e=5; s=1.235584654 (真の合計: 123558.4654)
これは真の結果、つまりオペランドの正確な合計です。7桁に丸められ、必要に応じて正規化されます。最終結果は
e=5; s=1.235585 (最終合計: 123558.5)
2番目のオペランド(654)の下位3桁は実質的に失われます。これは丸め誤差です。極端な場合、2つのゼロ以外の数値の合計が、そのうちの1つと等しくなることがあります。
e=5; s=1.234567 + e=−3; s=9.876543
e=5; s=1.234567 + e=5; s=0.00000009876543 (シフト後) ---------------------- e=5; s=1.23456709876543 (真の合計) e=5; s=1.234567(丸めと正規化後)
上記の概念的な例では、正しい丸めを保証するために加算器が多数の追加桁を提供する必要があるように思われるが、慎重な実装技術を用いたバイナリ加算または減算では、オペランドの精度を超えて保持する必要があるのはガードビット、丸めビット、および1つの追加のスティッキービットのみである。[ 18 ] [ 44 ]: 218-220
ほぼ等しい2つの数の近似値を引き算すると、有効性が失われるという別の問題が発生します。次の例では、 e = 5; s = 1.234571 とe = 5; s = 1.234567 は、有理数 123457.1467 と 123456.659 の近似値です。
e=5; s=1.234571 − e=5; s=1.234567 ---------------- e=5; s=0.000004 e=−1; s=4.000000(丸めと正規化後)
浮動小数点の差は、数値が近いため正確に計算されます。これは、段階的アンダーフローがサポートされているアンダーフローの場合でも、スターベンツの補題によって保証されます。それにもかかわらず、元の数値の差はe = −1; s = 4.877000 であり、これは近似値の差e = −1; s = 4.000000と 20% 以上異なります。極端な場合、精度の有効桁がすべて失われる可能性があります。[ 18 ] [ 45 ]この相殺は、計算結果のすべての桁が意味を持つと仮定することの危険性を示しています。これらのエラーの結果に対処することは、数値解析のトピックです。精度の問題も参照してください。
乗算を行うには、仮数部同士を掛け合わせ、指数部同士を足し合わせ、結果を四捨五入して正規化します。
e=3; s=4.734612 × e=5; s=5.417242 ----------------------- e=8; s=25.648538980104 (真の積) e=8; s=25.64854(四捨五入後) e=9; s=2.564854(正規化後)
同様に、除算は、被除数の指数から除数の指数を引いて、被除数の仮数を除数の仮数で割ることによって行われます。
乗算や除算には、相殺や吸収の問題はありませんが、演算を連続して実行すると小さな誤差が蓄積される可能性があります。[ 18 ]実際には、デジタルロジックでこれらの演算を実行する方法は非常に複雑になることがあります(ブースの乗算アルゴリズムと除算アルゴリズムを参照)。[ nb 9 ]
浮動小数点数のリテラルは言語によって異なります。通常、科学的表記を表すにはeまたはを使用します。Cプログラミング言語とIEEE 754規格では、10 ではなく 2 を底とする指数を持つ16 進数リテラル構文も定義されています。Cのような言語では、10 進指数が省略されている場合、整数と区別するために小数点が必要です。他の言語には整数型がありません ( JavaScriptなど)、または数値型のオーバーロードを許可しています ( Haskellなど)。これらの場合、 などの数字列も浮動小数点リテラルとして使用できます。E123
浮動小数点リテラルの例は次のとおりです。
99.9-5000.126.02e23-3e-450x1.fffffep+127C言語およびIEEE 754コンピュータにおける浮動小数点演算には、次の3種類の問題が発生する可能性があります。
IEEE規格が制定される以前は、このような状況が発生すると、通常はプログラムが終了したり、プログラマが捕捉できる何らかのトラップが作動したりしていました。しかし、その仕組みはシステムに依存していたため、浮動小数点プログラムは移植性に欠けていました。
IEEE 754 で使用される「例外」という用語は、例外的な状態を意味する一般的な用語であり、必ずしもエラーを意味するものではありません。これは、C++ や Java などのプログラミング言語で一般的に定義されている使用法とは異なります。C++ や Java などのプログラミング言語では、「例外」は制御の代替フローであり、IEEE 754 の用語で「トラップ」と呼ばれるものに近いものです。ただし、そのような言語でも、制御フロー例外がArithmeticExceptionスローされる可能性があります。
ここでは、IEEE 754 に従って例外を処理するための必須のデフォルト方法について説明します (IEEE 754 のオプションのトラップやその他の「代替例外処理」モードについては説明しません)。算術例外は (デフォルトでは) 「スティッキー」ステータスフラグビットに記録する必要があります。「スティッキー」とは、次の (算術) 演算によってリセットされず、明示的にリセットされるまでセットされたままになることを意味します。したがって、「スティッキー」フラグを使用することで、例外条件のテストを完全な浮動小数点式またはサブルーチンの後に延期できます。これらがない場合、無視できない例外条件は、すべての浮動小数点演算の直後に明示的にテストする必要があります。デフォルトでは、演算は常に計算を中断することなく仕様に従って結果を返します。たとえば、1/0 は +∞ を返し、同時にゼロ除算フラグビットもセットします (このデフォルトの ∞ は、後続の演算で使用される場合に有限の結果を返すように設計されているため、安全に無視できます)。
しかし、オリジナルの IEEE 754 規格では、このような算術例外フラグビットのセットを処理するための操作が推奨されていませんでした。そのため、ハードウェアでは実装されていましたが、当初はプログラミング言語の実装では (アセンブラを除いて) それらにアクセスする手段が提供されていませんでした。時を経て、一部のプログラミング言語規格 ( C99 / C11 や Fortran など) が更新され、ステータスフラグビットにアクセスして変更する方法が規定されるようになりました。2008 年版の IEEE 754 規格では、算術フラグビットにアクセスして処理するためのいくつかの操作が規定されています。プログラミングモデルは単一の実行スレッドに基づいており、複数のスレッドによる使用は規格外の手段で処理する必要があります (例えば、 C11ではフラグがスレッドローカルストレージを持つことが規定されています)。
IEEE 754では、ステータスフラグ(「スティッキービット」)に記録されるべき5つの算術例外が規定されている。

各例外のデフォルトの戻り値は、ほとんどの場合正しい結果を返すように設計されているため、ほとんどのコードでは例外を無視できます。不正確は正しく丸められた結果を返し、アンダーフローは絶対値が最小の正の正規数以下の値を返し、ほぼ常に無視できます。[ 46 ]ゼロ除算は正確に無限大を返し、通常は有限数を除算してゼロになります。そうでない場合は、その後で無効な例外が発生するため、これも通常は無視できます。たとえば、n個の抵抗器を並列接続した場合の実効抵抗(図1参照)は、次のように表されます。短絡が発生した場合0に設定、は +infinity を返し、最終的な結果をもたらします。予想通り0になります[ 47 ] (別の例については、IEEE 754設計の根拠の連分数の例を参照してください)。
オーバーフローや無効な例外は通常無視できませんが、必ずしもエラーを表すわけではありません。たとえば、ルート探索ルーチンは、通常の動作の一部として、渡された関数をその定義域外の値で評価し、NaN と無効な例外フラグを返して、有用な開始点が見つかるまで無視する場合があります。[ 46 ]
浮動小数点数がすべての実数を正確に表現できないこと、また浮動小数点演算が真の算術演算を正確に表現できないという事実は、多くの驚くべき状況を引き起こします。これは、コンピュータが一般的に数値を表現する際の有限の精度に関係しています。
例えば、10進数の0.1と0.01は、バイナリ浮動小数点数として正確に表現することはできません。24ビットの仮数部を持つIEEE 754 binary32形式では、0.1の近似値を二乗しても、0.01でも、それに最も近い表現可能な数値でもありません。10進数の0.1は、バイナリではe = −4 ; s = 110011001100110011001101と表現されます。
この数を二乗すると
24ビット精度に丸めて二乗すると
しかし、0.01に最も近い表現可能な数値は
また、π(およびπ/2)は表現不可能であるため、tan(π/2)の計算を試みても無限大の結果は得られず、通常の浮動小数点形式でもオーバーフローしません(tanの正確な実装を前提としています)。π/2は正確に表現できないため、標準的な浮動小数点ハードウェアでtan(π/2)を計算することは単純に不可能です。C言語でのこの計算は次のとおりです。
// 正しい近似値が得られるように十分な桁数。const double pi = 3.1415926535897932384626433832795 ; double z = tan ( pi / 2.0 );結果は 16331239353195370.0 になります。単精度(tanf関数を使用)では、結果は −22877332.0 になります。
同様に、sin(π) の計算を試みてもゼロにはなりません。結果は、倍精度では (およそ) 0.1225 × 10 −15 、単精度では−0.8742 × 10 −7になります。 [ nb 10 ]
浮動小数点数の加算と乗算はどちらも交換法則が成り立ちますが( a + b = b + aおよびa × b = b × a )、必ずしも結合法則が成り立つとは限りません。つまり、( a + b ) + cは必ずしもa + ( b + c )と等しいとは限りません。7 桁の仮数を持つ 10 進数演算を使用すると次のようになります。
a = 1234.567、b = 45.67834、c = 0.0004
(a + b) + c: 1234.567 (a) + 45.67834 (b) ____________ 1280.24534を四捨五入すると1280.245になります。
1280.245 (a + b) + 0.0004 (c) ____________ 1280.2454 を四捨五入すると 1280.245 ← (a + b) + c
a + (b + c): 45.67834 (b) + 0.0004 (c) ____________ 45.67874
1234.567 (a) + 45.67874 (b + c) ____________ 1280.24574 を四捨五入すると 1280.246 ← a + (b + c)
また、それらは必ずしも分配法則を満たすとは限りません。つまり、( a + b ) × c はa × c + b × cと同じとは限りません。
1234.567 × 3.333333 = 4115.223 1.234567 × 3.333333 = 4.115223 4115.223 + 4.115223 = 4119.338 しかし 1234.567 + 1.234567 = 1235.802 1235.802 × 3.333333 = 4119.340
有効性の喪失、πや0.1などの数値を正確に表現できないこと、その他のわずかな不正確さに加えて、次のような現象が発生する可能性があります。
機械精度は、浮動小数点システムの精度を表す量であり、浮動小数点アルゴリズムの後方誤差解析に用いられます。単位丸め誤差またはマシンイプシロンとも呼ばれます。通常はΕmachで表され、その値は使用される丸め方法によって異なります。
ゼロに丸めると、 一方、最も近い値に丸めると、 ここで、Bはシステムの基数であり、Pは仮数の精度(基数B)である。
これは、浮動小数点システムの正規化された範囲内で、 ゼロ以外の実数xを表現する際の相対誤差を制限するため重要です。
後方誤差解析は、その理論がジェームズ・H・ウィルキンソンによって開発され普及したもので、数値関数を実装するアルゴリズムが数値的に安定していることを確立するために使用できます。[ 52 ]基本的なアプローチは、丸め誤差のために計算結果が厳密には正しくないとしても、わずかに摂動された入力データを持つ近傍の問題の正確な解であることを示すことです。必要な摂動が小さく、入力データの不確実性のオーダーであれば、結果は、ある意味でデータが「ふさわしい」精度になります。この場合、アルゴリズムは後方安定であると定義されます。安定性は、特定の数値手順の丸め誤差に対する感度の尺度です。対照的に、特定の問題に対する関数の条件数は、入力の小さな摂動に対する関数の固有の感度を示し、問題を解くために使用される実装とは無関係です。[ 53 ]
簡単な例として、長さ2のベクトルの内積を表す単純な式を考えてみましょう。そして、 それから など
どこ
どこ
定義により、これはわずかに摂動された(Εマッハのオーダーの)2 つの入力データの合計であり、後方安定です。数値線形代数におけるより現実的な例については、Higham 2002 [ 54 ]および以下の他の参考文献を参照してください。
IEEE 754 の個々の算術演算はULP の半分以内の精度が保証されていますが、より複雑な数式ではさまざまな理由で誤差が大きくなる可能性があります。問題やデータが悪条件である場合、つまり正しい結果がデータのわずかな変動に過敏な場合、精度の低下は相当なものになる可能性があります。しかし、条件の良い関数であっても、そのデータに対して数値的に不安定なアルゴリズムを使用すると、精度が大きく低下する可能性があります。プログラミング言語で表現された一見同等の式でも、数値的安定性は大きく異なる場合があるのです。このような精度低下のリスクを取り除くためのアプローチの 1 つは、数値的に安定したアルゴリズムの設計と解析であり、これは数値解析と呼ばれる数学の分野の目標です。数値不安定性のリスクから保護できるもう 1 つのアプローチは、アルゴリズムの中間値 (仮値) を最終結果に必要な精度よりも高い精度で計算することであり、[ 55 ]これにより、そのようなリスクを排除するか、桁違いに低減することができます。 [ 56 ] IEEE 754 四倍精度と拡張精度は、倍精度で計算する場合にこの目的のために設計されています。[ 57 ] [ nb 11 ]
例えば、次のアルゴリズムは関数を計算するための直接的な実装です。状態が良い[ nb 12 ]しかし、1.0 付近で計算すると数値的に不安定になり、演算によって保持される有効桁の最大半分を失うことが示されています。[ 58 ]
#include <math.h>double f ( double x ) { double y = x - 1.0 ; double z = exp ( y ); if ( z != 1.0 ) { z = y / ( z - 1.0 ); } return z ; }アルゴリズムの数値解析によると、以下の一見分かりにくい変更をz = y / (z - 1.0);行に加えると、
z = log ( z ) / ( z - 1.0 );すると、アルゴリズムは数値的に安定し、完全な倍精度で計算できるようになります。[ 58 ]
数値的に安定なプログラムの特性を厳密に維持するためには、コンパイラによる慎重な処理が不可欠です。コンパイラが行う特定の「最適化」(例えば、演算順序の変更など)は、適切に動作するソフトウェアの目標に反する場合があります。この分野におけるコンパイラと言語設計の欠点については議論があり、C99は数値精度を維持するために最適化が厳密に規定されている言語の一例です。詳細は、本記事末尾の外部参考文献をご覧ください。
高品質な浮動小数点ソフトウェアを作成するための技術の詳細な説明はこの記事の範囲外であるため、読者は[ 54 ] [ 59 ]およびこの記事の末尾にあるその他の参考文献を参照してください。Kahanは、より慎重な数値解析に加えて、またはその代わりに、数値異常のリスクを桁違いに大幅に低減できるいくつかの経験則を提案しています[ 59 ]。これらには、前述のように、すべての式と中間結果をハードウェアでサポートされている最高精度で計算すること(一般的な経験則は、目的の結果の2倍の精度を保持すること、つまり、最終的な単精度結果の場合は倍精度で計算し、倍精度結果までの場合は倍精度拡張または4倍精度で計算すること[ 60 ])が含まれます。また、入力データと結果を、入力データが必要とし、サポートする精度のみに丸めます(最終結果に、入力データが必要とし、サポートする精度を超える過剰な精度を持たせると、誤解を招く可能性があり、ストレージコストが増加し、速度が低下し、余分なビットが数値手順の収束に影響を与える可能性があります。[ 61 ]特に、以下に示す反復例の最初の形式は、この経験則を使用すると正しく収束します)。いくつかの追加の問題と手法について簡単に説明します。
小数部分はバイナリ浮動小数点では正確に表現できないことが多いため、このような演算は、土星の衛星の公転周期や陽子の質量など、広範囲にわたる実世界の量を測定するために単純に使用される場合に最も適しており、正確であることが期待される小数文字列で表現された量の相互作用をモデル化することが期待される場合は最悪です。[ 56 ] [ 59 ]後者の例としては、金融計算があります。このため、金融ソフトウェアはバイナリ浮動小数点表現を使用しない傾向があります。[ 62 ] C#およびPythonプログラミング言語の「decimal」データ型と、 IEEE 754-2008規格の decimal 形式は、人間が入力した正確な小数値に適用した場合のバイナリ浮動小数点表現の問題を回避し、数値が小数で印刷されたときに常に期待どおりに演算が動作するように設計されています。
数学から期待されることが、浮動小数点演算の分野では実現されない場合がある。例えば、そして、しかし、これらの事実は、関係する量が浮動小数点演算の結果である場合には当てはまらない。
等価性テスト()の使用は、if (x==y) ...浮動小数点数を扱う際には注意が必要です。 のような単純な式でさえ0.6 / 0.2 - 3 == 0、ほとんどのコンピュータでは真になりません[ 63 ](たとえば、IEEE 754 倍精度では、0.6 / 0.2 - 3はほぼ に等しくなります) 。−4.440 892 098 500 63 × 10 −16 )。したがって、このようなテストは、「あいまい」比較 ( if (abs(x-y) < epsilon) ...、ここで epsilon は十分に小さく、アプリケーションに合わせて調整されています。たとえば 1.0E−13 など) に置き換えられることがあります。これを行うことの妥当性は大きく異なり、epsilon を制限するために数値解析が必要になる場合があります。[ 54 ]丸め誤差によるこのような不整合のリスクを最小限に抑えるために、プライマリ データ表現から導出された値とその比較は、より広い拡張精度で実行する必要があります。[ 59 ]このようなテストが不要になるようにコードを整理する方が良い場合がよくあります。たとえば、計算幾何学では、点が他の点によって定義された線または平面上にあるか、または線から外れているかの正確なテストは、適応精度または正確な算術方法を使用して実行できます。[ 64 ]
浮動小数点演算における小さな誤差は、数学的アルゴリズムが膨大な回数演算を実行すると大きくなる可能性があります。いくつかの例としては、行列の逆行列計算、固有ベクトル計算、微分方程式の解法などがあります。これらのアルゴリズムは、うまく機能するためには、反復改良などの数値的手法を用いて非常に慎重に設計する必要があります。 [ 65 ]
浮動小数点値のベクトルの合計は科学計算における基本的なアルゴリズムであり、そのため、有効数字の損失が発生する可能性がある場合を認識することが不可欠です。たとえば、非常に多くの数値を加算する場合、個々の加数は合計に比べて非常に小さくなります。これにより、有効数字の損失が発生する可能性があります。典型的な加算は次のようになります。
3253.671 + 3.141276 ----------- 3256.812
加数の下位3桁は事実上失われます。たとえば、すべて約3に等しい多数の数を加算する必要があるとします。1000個の数を加算した後、累積和は約3000になります。失われた桁は回復されません。カハン加算アルゴリズムを使用すると、エラーを減らすことができます。[ 54 ]
丸め誤差は、反復数値計算手順の収束性と精度に影響を与える可能性があります。例えば、アルキメデスは、六角形から始めて辺の数を順次倍にして、円に内接および外接する多角形の周長を計算することでπを近似しました。前述のように、計算は数学的に等価でありながら誤差が生じにくい方法で再構成できます(数値解析)。外接多角形の漸化式の2つの形式は次のとおりです。
以下は、IEEEの「double」(53ビットの精度を持つ仮数)演算を用いた計算例です。
i 6 × 2 i × t i、第1形式 6 × 2 i × t i、第2形式 --------------------------------------------------------- 0 3 .4641016151377543863 3 .4641016151377543863 1 3 .2153903091734710173 3 .2153903091734723496 2 3.1 596599420974940120 3.1 596599420975006733 3 3.14 60862151314012979 3.14 60862151314352708 4 3.14 27145996453136334 3.14 27145996453689225 5 3.141 8730499801259536 3.141 8730499798241950 6 3.141 6627470548084133 3.141 6627470568494473 7 3.141 6101765997805905 3.141 6101766046906629 8 3.14159 70343230776862 3.14159 70343215275928 9 3.14159 37488171150615 3.14159 37487713536668 10 3.141592 9278733740748 3.141592 9273850979885 11 3.141592 7256228504127 3.141592 7220386148377 12 3.1415926 717412858693 3.1415926 707019992125 13 3.1415926 189011456060 3.14159265 78678454728 14 3.1415926 717412858693 3.14159265 46593073709 15 3.14159 19358822321783 3.141592653 8571730119 16 3.1415926 717412858693 3.141592653 6566394222 17 3.1415 810075796233302 3.141592653 6065061913 18 3.1415926 717412858693 3.1415926535 939728836 19 3.141 4061547378810956 3.1415926535 908393901 20 3.14 05434924008406305 3.1415926535 900560168 21 3.14 00068646912273617 3.141592653589 8608396 22 3.1 349453756585929919 3.141592653589 8122118 23 3.14 00068646912273617 3.14159265358979 95552 24 3 .2245152435345525443 3.14159265358979 68907 25 3.14159265358979 62246 26 3.14159265358979 62246 27 3.14159265358979 62246 28 3.14159265358979 62246 真の値は3.14159265358979323846264338327...です。
漸化式の 2 つの形式は明らかに数学的に等価ですが、[ nb 13 ]最初の形式は 1 に非常に近い数から 1 を減算するため、有効桁の損失がますます問題になります。漸化式を繰り返し適用すると、最初は精度が向上しますが、その後悪化します。53 ビット演算では約 16 桁の精度が可能であるにもかかわらず、精度は約 8 桁を超えることはありません。漸化式の 2 番目の形式を使用すると、値は 15 桁の精度に収束します。
浮動小数点演算の結合性の欠如は、一般的に、コンパイラが整数演算や固定小数点演算ほど効果的に算術式を並べ替えることができないことを意味し、共通部分式の削除や自動ベクトル化などの最適化の障害となります。[ 66 ]多くのコンパイラ(ICC、GCC、Clang、MSVCなど)の「高速演算」オプションは、再結合を有効にするとともに、IEEE 754 に NaN や無限数がないなどの安全でない仮定を伴います。一部のコンパイラは、再結合のみを有効にしたり、より積極的な最適化のためにコードの特定の領域をマークしたりする、よりきめ細かいオプションも提供しています。[ 67 ]いずれの場合も、プログラマは、「高速」演算を使用するプログラムの部分で、上記で述べた精度の落とし穴の多くにさらされます。[ 68 ]
一部のコンパイラ(GCC および Clang [GCC がインストールされているとき])では、「高速」演算を有効にすると、プログラムが起動時に非正規浮動小数点演算を無効にする可能性があり、生成されたコードだけでなく、そのようなコードをライブラリとして使用するすべてのプログラムの浮動小数点動作にも影響を及ぼします。これは GCC 13 で修正されました。[ 69 ]
ほとんどのFortranコンパイラでは、ISO/IEC 1539-1:2004 Fortran 規格で許可されているように、再関連付けがデフォルトであり、「括弧の保護」設定 (これもデフォルトで有効) によって、破損がほぼ防止されます。この設定により、コンパイラは括弧の境界を超えて再関連付けを行うことができません。[ 70 ] Intel Fortran コンパイラは注目すべき例外です。[ 71 ]
「高速」な数学における一般的な問題は、部分式が場所ごとに同じように最適化されない可能性があり、予期しない差異が生じることです。この問題の解釈の一つは、現在実装されている「高速」な数学のセマンティクスが十分に定義されていないということです。「高速」な数学の最適化を形式化しようとする試みの一つとして、検証済みコンパイラであるIcingが挙げられます。[ 72 ]
[…] [デジタルフィールドシステム] DFS IVやDFS Vなどのシステムは4進浮動小数点システムであり、12dBのゲインステップを使用していた 。[…](256ページ)
[…] マニアックの浮動小数点基数は
2¹⁶
= 65,536 である。 […] マニアックの大きな基数は、浮動小数点演算の速度を大幅に向上させる。このような大きな基数は、最大で15個の先頭ゼロの可能性を意味するが、48ビットの大きなワードサイズは十分な有効性を保証する。 […]
「拡張」とは、IEC 60559の二重拡張データフォーマットを指します。拡張とは、一般的な80ビットフォーマットと4倍128ビットフォーマットの両方を指します。
浮動小数点仕様では 16 ビット形式が定義されていないため、ILM は「half」形式を作成しました。half 値は、1 ビットの符号ビット、5 ビットの指数部、および 10 ビットの仮数部を持ちます。
…] _fmsbintoieee(float *src4, float *dest4) […] MS バイナリ形式 […] バイト順序 => m3 | m2 | m1 |指数 […] m1 は
最上位バイト
=> sbbb|bbbb […] m3 は
最下位バイト
[…] m = 仮数バイト […] s = 符号ビット […] b = ビット […] MBF はバイアス 128、IEEE はバイアス 127 です。 […] MBF は
想定ビット
の前に
小数点
を配置しますが、IEEE は想定ビットの後に小数点を配置します。 […] ieee_exp = msbin[3] - 2; /* 実際には、msbin[3]-1-128+127 */ […] _dmsbintoieee(double *src8, double *dest8) […] MS バイナリ形式 […] バイト順序 => m7 | m6 | m5 | m4 | m3 | m2 | m1 |指数 […] m1 は最上位バイト => smmm|mmmm […] m7 は最下位バイト […] MBF はバイアス 128、IEEE はバイアス 1023 です。 […] MBF は想定されるビットの前に小数点を配置し、IEEE は想定されるビットの後に小数点を配置します。 […] ieee_exp = msbin[7] - 128 - 1 + 1023; […]
あるキャンセルエラーです。
-ffast-math を使用すると、浮動小数点数の削減演算をサポートします。
{{cite book}}ISBN/日付の不一致(ヘルプ) (注:浮動小数点演算に関する古典的で影響力のある論文。)