akios @ ウィキ
4.2.4. 浮動小数点演算
最終更新:
akios
-
view
4. 型と値と変数
4.1. 型と変数の種類
4.2. プリミティブ型と値
4.2.1. 整数型と値
4.2.2. 整数演算
4.2.3. 浮動小数点型と書式と値
4.2.4. 浮動小数点演算
Javaプログラミング言語は浮動小数点値に対する演算として以下を提供しています。:
- 比較演算子はboolean型の値を返します。:
- 数値演算子はfloat型もしくはdouble型を返します。
他にも便利なコンストラクターやメソッドや定数がFloatやDouble、Mathクラス内に定義されています。
2項演算子の少なくとも一つのオペランドに浮動小数点型があれば、他方がリテラルであっても、演算は浮動小数点で行われます。
数値演算子で少なくとも一つのオペランドがdouble型があれば、演算は64ビット精度浮動小数点で行われ、数値演算子の戻り値はdouble型になります。他のオペランドがdouble型でなければ、数値昇格によって最初にdouble型に拡幅されます。
そうでなければ、演算は32ビット浮動小数点精度で行われ、数値演算子の戻り値はfloat型になります。(オペランドがfloat型でなければ、数値昇格によって最初にfloat型に拡幅されます。)
浮動小数点型の任意の値を任意の数値型へキャストしたり、任意の数値型の値からキャストして浮動小数点型の任意の値を得ることができます。boolean型と浮動小数点型の間はキャストできません。
浮動小数点式をbooleanに変換する方法は4.2.5.を参照してください。
浮動小数点数の演算はIEEE754で定義されている通りに行われます(剰余演算子を除く)。特に、Javaプログラミング言語は、特定の数値アルゴリズムの望ましい特性の証明を容易にする、IEEE754非正規化浮動小数点数と緩やかなアンダーフロー(gradual underflow)を扱います。浮動小数点演算は計算結果が非正規化数であれば"ゼロにフラッシュする(flush to zero)"ということはありません。
プログラミング言語Javaはすべての浮動小数点演算子がその浮動小数点演算の結果を結果精度に丸めたかのよう振る舞う計算を行うことを要求しています。不正確な結果は,正確な結果に限りなく最も近い表現可能な値に丸められます。二つの同程度に近い代表値があるときは、もっとも重みのないビット(least significant bit)がゼロのものを選びます。これは直近への丸めとして知られているIEEE 754規格のデフォルト丸めモードです。
プログラミング言語Javaは浮動小数点値を整数に変換するときに,ゼロに向かう丸めを適用します。この場合、仮数ビットを切り捨てます。ゼロに向かう丸めでは、その形式の値が大きさに関して正確な値に限りなく最も近くて,しかも大きくない結果を選びます。
浮動小数点演算はオーバーフローを起こした時、符号付き無限大を返します。
浮動小数点演算はアンダーフローを起こした時、非正規化数もしくは符号付きゼロを返します。
浮動小数点演算は数学的に確定した結果をもたらさない演算に対しては、NaNを返します。
全ての数値演算はオペランドとしてNaNがあると、NaNを結果として返します。
浮動小数点演算は以下の場合において例外をスローします。:
- ヌル参照のボックス化解除変換が行われる場合、浮動小数点演算子はNullPointerExceptionをスローする。
- インクリメント演算子++(15.14.2.、15.15.1.)とデクリメント演算子--(15.14.3.、15.15.2.)でボックス化変換が要求されたが実際に変換するのに必要なメモリーを確保できない場合、OutOfMemoryErrorをスローする。
class Test {
public static void main(String[] args) {
// An example of overflow:
double d = 1e308;
System.out.print("overflow produces infinity: ");
System.out.println(d + "*10==" + d*10);
// An example of gradual underflow:
d = 1e-305 * Math.PI;
System.out.print("gradual underflow: " + d + "\ n ");
for (int i = 0; i < 4; i++)
System.out.print(" " + (d /= 100000));
System.out.println();
// An example of NaN:
System.out.print("0.0/0.0 is Not-a-Number: ");
d = 0.0/0.0;
System.out.println(d);
// An example of inexact results and rounding:
System.out.print("inexact results with float:");
for (int i = 0; i < 100; i++) {
float z = 1.0f / i;
if (z * i != 1.0f)
System.out.print(" " + i);
}
System.out.println();
// Another example of inexact results and rounding:
System.out.print("inexact results with double:");
for (int i = 0; i < 100; i++) {
double z = 1.0 / i;
if (z * i != 1.0)
System.out.print(" " + i);
}
System.out.println();
// An example of cast to integer rounding:
System.out.print("cast to int rounds toward 0: ");
d = 12345.6;
System.out.println((int)d + " " + (int)(-d));
}
}
このプログラムは以下を出力します。:
overflow produces infinity: 1.0e+308*10==Infinity gradual underflow: 3.141592653589793E-305 3.1415926535898E-310 3.141592653E-315 3.142E-320 0.0 0.0/0.0 is Not-a-Number: NaN inexact results with float: 0 41 47 55 61 82 83 94 97 inexact results with double: 0 49 98 cast to int rounds toward 0: 12345 -12345
この例は、穏やかなアンダーフローが精度の穏やかな損失という結果を生じる場合があることを示しています。
iが0の時の結果はゼロの割り算を含んでいるので、zは正の無限大となります。z*0はNaNであり、1.0ではありません。