多くの無限の実数を有限数のビットに圧縮するには、近似表現が必要です。ほとんどのプログラムは、整数計算の結果を最大 32 ビットまたは 64 ビットで保存します。ビット数が固定されていると、実数を使ったほとんどの計算では、そのビット数を使用しても正確に表現できない量が生成されます。したがって、浮動小数点計算の結果は、多くの場合、有限表現に収まるように丸める必要があります。この丸め誤差は浮動小数点演算の特徴です。したがって、浮動小数点数で計算を処理するとき (特に計算が金銭に関するものである場合)、プログラミング言語での丸め誤差に注意する必要があります。例を見てみましょう:
Javapublic class Main { public static void main(String[] args) { double a = 0.7; double b = 0.9; double x = a + 0.1; double y = b - 0.1; System.out.println('x = ' + x); System.out.println('y = ' + y ); System.out.println(x == y); } }
Linuxのディレクトリ名を変更する
出力:
x = 0.7999999999999999
y = 0.8
false
ここでの答えは、Java コンパイラによって四捨五入が行われたため、予想したものと異なります。
丸め誤差の原因
Float および Double データ型は、IEEE 浮動小数点 754 仕様を実装します。これは、数値が次のような形式で表現されることを意味します。
SIGN FRACTION * 2 ^ EXP 0.15625 = (0.00101)2浮動小数点形式では、1.01 * 2^-3 として表されます。
すべての分数を 2 のべき乗の分数として正確に表現できるわけではありません。簡単な例として、 0.1 = (0.000110011001100110011001100110011001100110011001100110011001…)2 したがって、浮動小数点変数内に格納することはできません。
別の例:
javapublic class Main { public static void main(String[] args) { double a = 0.7; double b = 0.9; double x = a + 0.1; double y = b - 0.1; System.out.println('x = ' + x); System.out.println('y = ' + y ); System.out.println(x == y); } }
出力:
x = 0.7999999999999999
y = 0.8
false
別の例:
Javapublic class Main { public static void main(String args[]) { double a = 1.0; double b = 0.10; double x = 9 * b; a = a - (x); // Value of a is expected as 0.1 System.out.println('a = ' + a); } }
出力:
a = 0.09999999999999998丸め誤差を修正するにはどうすればよいですか?
- 結果を四捨五入します。 Round() 関数を使用すると、浮動小数点演算ストレージの不正確さの影響を最小限に抑えることができます。ユーザーは、計算に必要な小数点以下の桁数に数値を四捨五入できます。たとえば、通貨を扱う場合、小数点以下第 2 位に四捨五入する可能性があります。
- アルゴリズムと関数: このような場合に対処するには、数値的に安定したアルゴリズムを使用するか、独自の関数を設計してください。正しいかどうかわからない数字は切り捨て/四捨五入できます (演算の数値精度も計算できます)。
- BigDecimal クラス: を使用できます。 java.math.BigDecimal このクラスは、特に大きな小数の場合に精度を与えるように設計されています。次のプログラムは、エラーを削除する方法を示しています。
import java.math.BigDecimal; import java.math.RoundingMode; public class Main { public static void main(String args[]) { BigDecimal a = new BigDecimal('1.0'); BigDecimal b = new BigDecimal('0.10'); BigDecimal x = b.multiply(new BigDecimal('9')); a = a.subtract(x); // Rounding to 1 decimal place a = a.setScale(1 RoundingMode.HALF_UP); System.out.println('a = ' + a); } }
出力:
0.1ここ a = a.setScale(1 RoundingMode.HALF_UP);
ラウンド aHALF_UP 丸めモードを使用して小数点以下 1 桁に変換します。したがって、BigDecimal を使用すると、算術演算と丸め演算をより正確に制御できるため、財務計算やその他の精度が重要な場合に特に役立ちます。
重要な注意事項:
Math.round は、値を最も近い整数に丸めます。 0.10 は 1 よりも 0 に近いため、0 に丸められます。四捨五入して 1.0 で除算すると、結果は 0.0 になります。したがって、BigDecimal クラスと Maths.round 関数を使用した出力の違いに気づくことができます。
Javapublic class Main { public static void main(String args[]) { double a = 1.0; double b = 0.10; double x = 9 * b; a = a - (x); /* We use Math.round() function to round the answer to closest long then we multiply and divide by 1.0 to to set the decimal places to 1 place (this can be done according to the requirements.*/ System.out.println('a = ' + Math.round(a*1.0)/1.0); } }
出力:
0.0