同じ指数になるように数値をスケーリングする必要があります。次に、仮数フィールドを追加し、必要に応じて結果を正規化します。
そうそう、それらが異なる符号の場合は、代わりに減算関数を呼び出すだけです:-)
わかりやすいので、10進数で例を見てみましょう。さらに、小数点以下8桁で格納されていると仮定します(数値は0から1までです)。
2つの数値を追加します。
sign exponent mantissa value
1 42 18453284 + 0.18453284 x 10^42
1 38 17654321 + 0.17654321 x 10^38
これらの数値を最大の指数にスケーリングすると、仮数フィールドを追加できるものが得られます。
sign exponent mantissa value
1 42 18453284 + 0.18453284 x 10^42
1 42 1765 + 0.00001765 x 10^42
= == ========
1 42 18455049 + 0.18455049 x 10^42
そして、あなたはあなたの番号を持っています。これは、シフトによって精度が失われる可能性があることも示しています。たとえば、IEEE754単精度浮動小数点数は次のようになります。
1e38 + 1e-38 = 1e38
など:
#include <stdio.h>
int main (void) {
float f1 = 1e38;
float f2 = 1e-38;
float f3 = f1 + f2;
float f4 = f1 - f3;
printf ("%.50f\n", f4);
return 0;
}
オーバーフローで何が起こるかという点では、それは私が述べた正規化の一部です。99999.9999
に追加しましょう99999.9993
。それらはすでに同じ指数を持っているので、スケーリングする必要はありません。したがって、次を追加するだけです。
sign exponent mantissa value
1 5 99999999 + 0.99999999 x 10^5
1 5 99999993 + 0.99999999 x 10^5
= == ========
1 5 199999992 ???
ここでは、キャリーの状況があるため、8桁に制限されているため、そのキャリーを数字に入れることができないことがわかります。次に、キャリーを挿入できるように、数値を右にシフトします。そのシフトは事実上10による除算であるため、それに対抗するために指数をインクリメントする必要があります。
それで:
sign exponent mantissa value
1 5 199999992 ???
になります:
sign exponent mantissa value
1 6 19999999 + 0.19999999 x 10^6
実際には、最も近い数値に丸める必要があるため、単純な右シフトではありません。シフトアウトする数が5以上の場合は、左側の数字に1を加える必要があります。そのため99999.9993
、2番目の番号として選択しました。私が自分自身に追加99999.9999
した場合、私は次のようになっていたでしょう:
sign exponent mantissa value
1 5 199999998 ???
これは、右シフトで、左に向かってかなりの数のキャリーをトリガーします。
sign exponent mantissa value
1 6 20000000 + 0.2 x 10^6