浮動小数点データは、大きすぎるか小さすぎて固定小数点データでは表せない値を表現するために使用されます。また、各項の大きさが大きく異なる計算において、精度の低下を最小限に抑える目的で使用されることもあります。
浮動小数点値を使用すると予期しない結果になることがあります。浮動小数点変数では、精度に制限があり、実際のところほとんどの小数値を正確に表現できないため、プログラムの動作に問題が生じる可能性があります。さらに、多くのマシンの浮動小数点の実装では、中間結果の精度が PL/I の規則で厳密に要求される精度よりも高くなります。また、浮動小数点の変数と定数では、通常、実際の内部の精度値が 1 つか 2 つに制限されます。例えば、IEEE の浮動小数点のほとんどの実装では、「短精度」(23 ビット) と「長精度」(52 ビット) の浮動小数点値しか許可されません。最後に、正確な結果が得られるかどうかはプログラムの最適化レベルに左右されるという問題もあります。
例えば、次のようなプログラムがあるとします。
SAMPLE: PROCEDURE OPTIONS (MAIN); DECLARE (F,G) FLOAT BINARY (23); F = 3111; G = .14; IF F + G ^= 3111.14 THEN PUT LIST ('UNEQUAL RESULT'); END SAMPLE;
このプログラムを実際に実行すると、多くのマシンでは、定数 .14 および 3111.14 を浮動小数点 2 進数で正確に表現できないため、UNEQUAL RESULT というメッセージが出力されます。G に .14 を割り当てているため、定数の精度の約 23 ビットが変数に割り当てられます。ほとんどの実装では、実際の精度の 52 ビット以上を使用して合計が計算され、小数部に適用される 23 ビットは保持されますが、その合計値が定数 3111.14 と比較されます。定数の精度は 23 ビットまたは 52 ビットのどちらかになります(実際に言語の規則を厳密に実装すれば、精度は 20 ビットでなければなりません。詳細については、「データ型変換」の章を参照してください)。3111.14 を短精度浮動小数点数で表した場合、精度の 23 ビットのうちの 14 ビットが 3111 を表現するために使用され、定数の小数部は 9 ビットだけになります。これは、定数 3111.14 と比較して等しくはなりません。定数が長精度浮動小数点数の場合も、精度の 52 ビットのうちの 38 ビットが小数部となり、比較結果は等しくなりません。
これを修正するための 1 つの方法として、次のようにプログラムを変更してみます。
SAMPLE: PROCEDURE OPTIONS (MAIN); DECLARE (F, G, H) FLOAT BINARY (23); RESULT FLOAT BINARY (23) STATIC INITIAL (3111.14) F = 3111; G = .14; H = F + G IF H ^= 3111.14 THEN PUT LIST ('UNEQUAL RESULT') END SAMPLE;
このプログラムでは、合計値を実際の精度である 23 ビットまでで切り捨て、その値を精度がわかっている定数と比較しているように見えます。これであれば正常に機能します。ただし、最適化が適用されていれば、F + G の値を H に格納してから再ロードすることで、その値が精度を下げずに使用される可能性があります。
その場合、一般的には、浮動小数点数が等しいかどうかの比較が正しく機能しません。代わりに、次の方法で等しいかどうかをチェックします。
ABS(FIRST-SECOND) < EPSILON
定数 EPSILON は、アプリケーションの目的に応じて選択する必要があります。
浮動小数点数は、仮数 m、基数 b、および指数 e で構成されます。浮動小数点数は次の形式で表現されます。
m*b**e
仮数 m は、p 桁以上の小数です。b の値と e の有効範囲は、実装ごとに定義されます (この実装については『Open PL/I ユーザー ガイド』を参照してください)。ただし、基数が 2 進数の場合は m の値が 2 進 p 桁以上になり、基数が 10 進数の場合は m の値が 10 進 p 桁以上になります。次に例を示します。
DECLARE X FLOAT BINARY(23); DECLARE Y FLOAT DECIMAL(7);
この例では、X の値は仮数が 2 進 23 桁以上の浮動小数点数になり、Y の値は仮数が 10 進 7 桁以上の浮動小数点数になります。
記憶域における浮動小数点値の表現は、実装によっても異なります。実装においては、仮数が 2 進 p 桁以上または 10 進 p 桁以上であれば、任意の基数で仮数を表現できます。コンピューターによっては、10 進数の仮数を使用して 10 進浮動小数点値を表現するものもあれば、すべての浮動小数点数に 2 進数または 16 進数の仮数を使用するものもあります。
Open PL/I では、浮動小数点 10 進数の表現には 10 進数の仮数と指数を使用し、浮動小数点 2 進数の表現には 2 進数の仮数と指数を使用します。詳細については、『Open PL/I ユーザー ガイド』を参照してください。
浮動小数点値は、どちらの基数でも表現でき、計算時に超過した桁が失われる可能性があるため、概算の値となることがあります。ただし、整数値を浮動小数点に変換して整数に戻した場合は元の値に戻ります。同様に、浮動小数点の加算、減算、乗算の計算を実行した場合も、対象が整数値であれば結果も整数値になります。
浮動小数点定数は、次の例に示すように、固定小数点定数の後に指数を付けて記述されます。
5E+02 4.5E1 100E-04 .001E-04 0E0
浮動小数点定数の精度は 10 進 p 桁になります。この p は固定小数点定数の桁数です。例えば、4.5E1 の精度は 2 です。
1.5 のような固定小数点定数を浮動小数点値を含む演算で使用する場合、実行時に固定小数点 10 進値が浮動小数点に変換されないように、指数を付けて記述する必要があります。
浮動小数点値を文字列またはビット文字列に変換する場合、変換後の長さは実際の値ではなく p で決まります。変換規則については、「データ型変換」の章を参照してください。
浮動小数点定数を算術式で使用する際は注意が必要です。浮動小数点定数の型は Float Decimal と見なされますが、算術演算の結果の精度についての規則では、浮動小数点演算の結果の精度はオペランドのうちの最大の精度とするように規定されています。次の例について考えてみます。
SAMPLE2: PROCEDURE OPTIONS(MAIN); DECLARE X FLOAT BIN(52); X = 1E0 + .4999E0; PUT SKIP LIST(X); END SAMPLE2;
このプログラムでは、予期しない .500000000000000E+000 という結果が出力されます。これは、2 つの定数が Float Decimal で、精度がそれぞれ 1 と 4 であることが原因です。加算の実行結果が Float Decimal(4) に変換された後、中間結果の 1.4999 が 10 進 4 桁に丸められ、その結果が Float Binary に変換されて X に格納されます。これを修正するために、式を次のように変更してみます。
X = BINARY(1E0) + BINARY(.4999E0);
これにより、計算が Float Binary で実行されるようになります。ただし、ほとんどのマシンでは、最初の定数が Float Bin(4)、2 つ目の定数が Float Bin(14) に変換され、短精度浮動小数点で計算が実行されます。この短精度浮動小数点の結果が Float Bin(52) に変換されて X に格納されるため、結果は 1.499900013208389E+000 になります。これを正しく修正するには、2 つの引数を指定して BINARY 組み込み関数を使用します。
X = BINARY(1E0,52) + BINARY(.4999E0,52);
これにより、定数が長精度浮動小数点になり、最大精度で計算が実行され、1.499900000000000E+000 という結果が出力されます。別の方法として、後続のゼロを追加して定数を書き換えることで、より正確に定数を表す方法もあります。
X = 1.0000000000000000E0 + .4999000000000000E0;
この方法でも、計算が十分な精度で実行され、結果が高精度の浮動小数点値に直接変換されるため、1.499900000000000E+000 という同じ結果が得られます。
一般に、浮動小数点変数を含む算術式で浮動小数点定数を使用する際は、オペランドで組み込み関数の FLOAT および BINARY を使用して結果の精度を制御できます。2 つの浮動小数点定数の演算では、想定した結果にならないことがあります。
浮動小数点 10 進データに対する指数演算、MOD、およびすべての超越関数 (SORT を含む) の演算は、実際は浮動小数点 2 進演算を使用して実行されます。そのため、それらの演算のオペランドの範囲と結果は、浮動小数点 2 進数の範囲に制限されます。