回答:
他の人が述べたように、BigDecimal
11.4の正確な表現が必要な場合は、おそらくクラスを使用する必要があります。
さて、なぜこれが起こっているのかについて少し説明します:
float
そしてdouble
Javaでプリミティブ型である点フローティング数は分数と指数のバイナリ表現として記憶される数値を、。
より具体的には、double
型などの倍精度浮動小数点値は64ビット値です。ここで、
これらの部分が組み合わされてdouble
、値の表現が生成されます。
(出典:ウィキペディア:倍精度)
Javaでの浮動小数点値の処理方法の詳細については、セクション4.2.3: Java言語仕様の浮動小数点型、形式、および値を参照してください。
byte
、char
、int
、long
タイプは、固定小数点数の正確なrepresentionsある数字、。固定小数点数とは異なり、浮動小数点数は(「ほとんどの場合」と想定しても安全)、数値の正確な表現を返すことができない場合があります。これがの11.399999999999
結果としてあなたが終わる理由です5.6 + 5.8
。
1.5や150.1005などの正確な値が必要な場合は、固定小数点型のいずれかを使用すると、数値を正確に表すことができます。
すでに何度か言及されているように、JavaにはBigDecimal
非常に大きな数と非常に小さな数を処理するクラスがあります。
BigDecimal
クラスのJava APIリファレンスから:
不変の任意精度の符号付き10進数。BigDecimalは、任意の精度の整数のスケールなしの値と32ビット整数のスケールで構成されます。ゼロまたは正の場合、位取りは小数点の右側の桁数です。負の場合、数値のスケーリングされていない値に、スケールの否定の累乗に10を掛けます。したがって、BigDecimalで表される数値の値は(unscaledValue×10 ^ -scale)になります。
浮動小数点数とその精度の問題に関して、スタックオーバーフローに関する多くの質問がありました。興味があるかもしれない関連する質問のリストはここにあります:
浮動小数点数の細部までこだわる必要がある場合は、「すべてのコンピューター科学者が浮動小数点演算について知っておくべきこと」をご覧ください。
BigDecimal
よりもはるかに低速double
ですが、丸めが必要なだけであることに注意してください。
たとえば、のように倍精度数を入力すると33.33333333333333
、実際に得られる値は、最も近い表現可能な倍精度値であり、正確には次のようになります。
33.3333333333333285963817615993320941925048828125
それを100で割ると、次のようになります。
0.333333333333333285963817615993320941925048828125
これも倍精度数として表現できないため、正確に次の最も近い表現可能な値に丸められます。
0.3333333333333332593184650249895639717578887939453125
あなたは、この値をプリントアウトするとき、それは丸められます再び与えて、17桁に:
0.33333333333333326
値を分数として処理する場合は、分子と分母のフィールドを保持するFractionクラスを作成できます。
加算、減算、乗算、除算のメソッドとtoDoubleメソッドを記述します。このようにして、計算中にフロートを回避できます。
編集:迅速な実装、
public class Fraction {
private int numerator;
private int denominator;
public Fraction(int n, int d){
numerator = n;
denominator = d;
}
public double toDouble(){
return ((double)numerator)/((double)denominator);
}
public static Fraction add(Fraction a, Fraction b){
if(a.denominator != b.denominator){
double aTop = b.denominator * a.numerator;
double bTop = a.denominator * b.numerator;
return new Fraction(aTop + bTop, a.denominator * b.denominator);
}
else{
return new Fraction(a.numerator + b.numerator, a.denominator);
}
}
public static Fraction divide(Fraction a, Fraction b){
return new Fraction(a.numerator * b.denominator, a.denominator * b.numerator);
}
public static Fraction multiply(Fraction a, Fraction b){
return new Fraction(a.numerator * b.numerator, a.denominator * b.denominator);
}
public static Fraction subtract(Fraction a, Fraction b){
if(a.denominator != b.denominator){
double aTop = b.denominator * a.numerator;
double bTop = a.denominator * b.numerator;
return new Fraction(aTop-bTop, a.denominator*b.denominator);
}
else{
return new Fraction(a.numerator - b.numerator, a.denominator);
}
}
}
numerator
、s であるdenominator
必要がありint
ますか?浮動小数点の精度が必要なのはなぜですか?
精度が制限された10進算術を使用していて、1/3を処理したい場合、同じ問題があることに注意してください。0.333333333* 3は、1.00000000ではなく0.999999999です。
残念ながら、5.6、5.8、11.4は5分の1を含むため、2進数で丸めた数値ではありません。したがって、0.3333が正確に1/3ではないように、それらの浮動小数点表現は正確ではありません。
使用するすべての数値が非繰り返しの小数であり、正確な結果が必要な場合は、BigDecimalを使用します。または、他の人が言ったように、値がすべて0.01、0.001、または何かの倍数であるという意味で値がお金の場合、10の固定べき乗ですべてを乗算し、intまたはlongを使用します(加算と減算はささいなこと:乗算に注意してください)。
ただし、計算用のバイナリには満足しているが、少しわかりやすい形式で出力したい場合は、java.util.Formatter
またはを試してくださいString.format
。フォーマット文字列では、倍精度の完全精度よりも低い精度を指定します。たとえば、有効桁数が10桁の場合、11.399999999999は11.4なので、2進数の結果が小数点以下の数桁しか必要としない値に非常に近い場合、結果はほぼ正確になり、人間が読めるようになります。
指定する精度は、数値を使用して行った計算の量に少し依存します。一般的に、実行するほどエラーが蓄積されますが、一部のアルゴリズムは他のアルゴリズムよりもはるかに速く蓄積します(「不安定」と呼ばれます)。丸め誤差に関する「安定」とは対照的です)。あなたがしているすべてがいくつかの値を追加することであるなら、私は小数点以下1桁の精度を落とすことで物事が整理されると思います。実験。
精度の計算が本当に必要な場合は、javaのjava.math.BigDecimalクラスの使用を検討してください。BigDecimalのケースに関するOracle / Sunの優れた記事を次に示します。誰かが言及したように1/3を表すことはできませんが、、結果をどの程度正確にしたいかを正確に決定する力を持つます。setScale()はあなたの友達です.. :)
さて、現時点では手に余りにも時間がかかりすぎているので、ここにあなたの質問に関連するコード例があります:
import java.math.BigDecimal;
/**
* Created by a wonderful programmer known as:
* Vincent Stoessel
* xaymaca@gmail.com
* on Mar 17, 2010 at 11:05:16 PM
*/
public class BigUp {
public static void main(String[] args) {
BigDecimal first, second, result ;
first = new BigDecimal("33.33333333333333") ;
second = new BigDecimal("100") ;
result = first.divide(second);
System.out.println("result is " + result);
//will print : result is 0.3333333333333333
}
}
そして、私の新しいお気に入りの言語であるGroovyをプラグインするために、同じもののより良い例を次に示します。
import java.math.BigDecimal
def first = new BigDecimal("33.33333333333333")
def second = new BigDecimal("100")
println "result is " + first/second // will print: result is 0.33333333333333
double型の精度制限に直面しています。
Java.Mathには、任意精度の演算機能がいくつかあります。
7.3にはバイナリでの有限表現がないため、できません。あなたが得ることができる最も近いものは、2054767329987789/2 ** 48 = 7.3 + 1/1407374883553280です。
詳細については、http://docs.python.org/tutorial/floatingpoint.htmlをご覧ください。(PythonのWebサイトにありますが、JavaとC ++には同じ「問題」があります。)
解決策は、問題の内容によって異なります。
private void getRound() {
// this is very simple and interesting
double a = 5, b = 3, c;
c = a / b;
System.out.println(" round val is " + c);
// round val is : 1.6666666666666667
// if you want to only two precision point with double we
// can use formate option in String
// which takes 2 parameters one is formte specifier which
// shows dicimal places another double value
String s = String.format("%.2f", c);
double val = Double.parseDouble(s);
System.out.println(" val is :" + val);
// now out put will be : val is :1.67
}
java.math.BigDecimalを使用します
倍精度浮動小数点数は内部では2進分数であるため、小数部分を正確な10進数に表現できない場合があります。
すべてを100倍して、セント単位で保存します。
浮動小数点数は、任意の特定の浮動小数点数に対して次に高い浮動小数点数があるという点で実数とは異なります。整数と同じ。1から2までの整数はありません。
1/3を浮動小数点数として表現する方法はありません。その下にフロートがあり、その上にフロートがあり、それらの間には一定の距離があります。そして1/3はその空間にあります。
Apfloat for Javaは任意精度の浮動小数点数で機能すると主張していますが、私はこれを使用したことがありません。おそらく一見の価値があります。 http://www.apfloat.org/apfloat_java/
Java浮動小数点高精度ライブラリの前に同様の質問がここで行われました
BigDecimalを使用します。丸めルールを指定することもできます(ROUND_HALF_EVENのように、両方が同じ距離である場合、つまり、1.5と2.5の両方が2に丸められる場合に、偶数の隣に丸めることによって統計エラーを最小化します)。
短い回答:常にBigDecimalを使用し、コンストラクタを二重ではなく文字列引数で使用していることを確認してください。
例に戻ると、次のコードは、必要に応じて11.4を出力します。
public class doublePrecision {
public static void main(String[] args) {
BigDecimal total = new BigDecimal("0");
total = total.add(new BigDecimal("5.6"));
total = total.add(new BigDecimal("5.8"));
System.out.println(total);
}
}
double値を使用する以外に選択肢がない場合は、以下のコードを使用できます。
public static double sumDouble(double value1, double value2) {
double sum = 0.0;
String value1Str = Double.toString(value1);
int decimalIndex = value1Str.indexOf(".");
int value1Precision = 0;
if (decimalIndex != -1) {
value1Precision = (value1Str.length() - 1) - decimalIndex;
}
String value2Str = Double.toString(value2);
decimalIndex = value2Str.indexOf(".");
int value2Precision = 0;
if (decimalIndex != -1) {
value2Precision = (value2Str.length() - 1) - decimalIndex;
}
int maxPrecision = value1Precision > value2Precision ? value1Precision : value2Precision;
sum = value1 + value2;
String s = String.format("%." + maxPrecision + "f", sum);
sum = Double.parseDouble(s);
return sum;
}
BigDecimalを使用して、努力を無駄にしないでください。99.99999%のケースでは必要ありません。java double型は、おおよその値ですが、ほとんどすべての場合、十分に正確です。14桁目でエラーがあることに注意してください。これはごくわずかです!
適切な出力を取得するには、次を使用します。
System.out.printf("%.2f\n", total);