171
public class doublePrecision {
    public static void main(String[] args) {

        double total = 0;
        total += 5.6;
        total += 5.8;
        System.out.println(total);
    }
}

上記のコードは次を出力します。

11.399999999999

これを11.4で印刷する(または使用できるようにする)にはどうすればよいですか?

4

23 に答える 23

166

BigDecimal他の人が述べたように、11.4 の正確な表現が必要な場合は、おそらくクラスを使用することをお勧めします。

ここで、なぜこれが起こっているのかを少し説明します。

Javaのfloatおよびdoubleプリミティブ型は浮動小数点数であり、数値は分数と指数のバイナリ表現として格納されます。

より具体的には、型などの倍精度浮動小数点値doubleは 64 ビット値です。

  • 1 ビットは符号 (正または負) を示します。
  • 指数の 11 ビット。
  • 有効桁数 (2 進数としての小数部分) は 52 ビット。

これらのパーツを組み合わせてdouble、値の表現を生成します。

(出典:ウィキペディア: 倍精度)

Java での浮動小数点値の処理方法の詳細については、Java 言語仕様のセクション 4.2.3: Floating-Point Types, Formats, and Valuesを参照してください。

bytechar、型は固定小数点数であり、数値の正確な表現ですint。固定小数点数とは異なり、浮動小数点数は、数値の正確な表現を返すことができない場合があります (「ほとんどの場合」と想定しても問題ありません)。これが、の結果として になる理由です。long11.3999999999995.6 + 5.8

1.5 や 150.1005 などの正確な値が必要な場合は、数値を正確に表すことができる固定小数点型のいずれかを使用する必要があります。

すでに何度か述べたように、Java にはBigDecimal非常に大きな数と非常に小さな数を処理するクラスがあります。

BigDecimalクラスの Java API リファレンスから:

不変の任意精度の符号付き 10 進数。BigDecimal は、スケーリングされていない任意精度の整数値と 32 ビットの整数スケールで構成されます。ゼロまたは正の場合、位取りは小数点以下の桁数です。負の場合、数値のスケーリングされていない値は、10 のスケールの負の累乗で乗算されます。したがって、BigDecimal で表される数値の値は (unscaledValue × 10^-scale) です。

浮動小数点数とその精度の問題に関連して、スタック オーバーフローに関する多くの質問がありました。興味のある関連する質問のリストを次に示します。

浮動小数点数の核心に迫りたい場合は、What Every Computer Scientist Should Know About Floating-Point Arithmeticをご覧ください。

于 2008-11-27T03:27:46.780 に答える
108

のように double の数値を入力すると、33.33333333333333取得される値は実際には最も近い表現可能な倍精度値であり、正確には次のとおりです。

33.3333333333333285963817615993320941925048828125

それを 100 で割ると、次のようになります。

0.333333333333333285963817615993320941925048828125

これも倍精度数として表現できないため、ここでも表現可能な最も近い値に丸められます。これは正確には次のとおりです。

0.3333333333333332593184650249895639717578887939453125

この値を出力すると、さらに丸められて 17 桁になり、次のようになります。

0.33333333333333326
于 2010-03-18T00:41:56.650 に答える
24

値を分数として処理するだけの場合は、分子と分母フィールドを保持する 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);
    }
}

}
于 2010-03-18T01:09:06.223 に答える
16

限られた精度の 10 進演算を使用し、1/3 を処理したい場合、同じ問題が発生することに注意してください: 0.333333333 * 3 は 0.999999999 であり、1.00000000 ではありません。

残念ながら、5.6、5.8、および 11.4 は 5 分の 1 を含むため、2 進法では丸められません。したがって、0.3333 が正確に 1/3 ではないのと同様に、それらの float 表現は正確ではありません。

使用するすべての数値が循環しない 10 進数であり、正確な結果が必要な場合は、BigDecimal を使用します。または、他の人が言ったように、値がすべて 0.01、または 0.001、または何かの倍数であるという意味でお金のようなものである場合は、すべてを 10 の固定乗数で乗算し、int または long を使用します (加算と減算は自明: 乗算に注意してください)。

ただし、計算用のバイナリに満足しているが、もう少し使いやすい形式で出力したい場合は、java.util.Formatterまたはを試してくださいString.format。書式文字列で、double の完全な精度よりも低い精度を指定します。たとえば、有効数字 10 桁に対して 11.399999999999 は 11.4 であるため、バイナリ結果が少数の小数点以下の桁数しか必要としない値に非常に近い場合、結果はほぼ同じくらい正確で、人間が読みやすいものになります。

指定する精度は、数値に対してどれだけの計算を行ったかによって少し異なります。一般に、計算を行うほど誤差が蓄積されますが、アルゴリズムによっては他のものよりもはるかに速く蓄積されます (それらは「不安定」と呼ばれます)。丸め誤差に関しては「安定」ではありません)。いくつかの値を追加するだけの場合は、精度の小数点以下 1 桁を削除するだけで問題が解決すると思います。実験。

于 2008-11-27T03:11:07.640 に答える
9

正確な計算が本当に必要な場合は、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
于 2010-03-18T01:08:35.713 に答える
5

7.3 にはバイナリの有限表現がないため、できません。最も近い値は 2054767329987789/2**48 = 7.3+1/1407374883553280 です。

詳細については、 http://docs.python.org/tutorial/floatingpoint.htmlをご覧ください。(Python の Web サイトにありますが、Java と C++ には同じ「問題」があります。)

解決策は、問題が正確に何であるかによって異なります。

  • これらのノイズ数字がすべて表示されるのが気に入らない場合は、文字列の書式設定を修正してください。有効桁数が 15 桁 (float の場合は 7 桁) を超えて表示しないでください。
  • 数値の不正確さが「if」ステートメントのようなものを壊している場合は、if (x == 7.3) の代わりに if (abs(x - 7.3) < TOLERANCE) を書く必要があります。
  • お金を扱っている場合、おそらく本当に必要なのは 10 進固定小数点です。セントの整数値または通貨の最小単位を格納します。
  • (非常にまれ) 有効桁数 53 ビット (有効桁数 15 ~ 16 桁) を超える精度が必要な場合は、BigDecimal などの高精度の浮動小数点型を使用します。
于 2010-03-18T00:30:23.337 に答える
5

double 型の精度制限に直面しています。

Java.Math には、任意精度の演算機能がいくつかあります。

于 2010-03-18T00:35:13.283 に答える
5

これを 3 行の例にすることもできたはずです。:)

正確な精度が必要な場合は、BigDecimal を使用してください。それ以外の場合は、任意の精度で ints に 10 ^ を掛けて使用できます。

于 2008-11-27T01:57:20.970 に答える
5

他の人が指摘したように、10 進数は 10 の累乗に基づいており、2 進数は 2 の累乗に基づいているため、すべての 10 進数値を 2 進数として表すことはできません。

精度が重要な場合は BigDecimal を使用しますが、わかりやすい出力が必要な場合は次のようにします。

System.out.printf("%.2f\n", total);

あなたに与えます:

11.40
于 2008-11-27T03:52:24.920 に答える
4
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
}
于 2011-12-07T13:41:19.717 に答える
4

java.math.BigDecimal を使用

double は内部的に 2 進数の分数であるため、10 進数を正確な 10 進数で表すことができない場合があります。

于 2010-03-17T23:15:40.087 に答える
3
        /*
        0.8                     1.2
        0.7                     1.3
        0.7000000000000002      2.3
        0.7999999999999998      4.2
        */
        double adjust = fToInt + 1.0 - orgV;
        
        // The following two lines works for me. 
        String s = String.format("%.2f", adjust);
        double val = Double.parseDouble(s);

        System.out.println(val); // output: 0.8, 0.7, 0.7, 0.8
于 2020-09-18T10:25:31.107 に答える
2

コンピュータは数値を 2 進数で格納するため、実際には 33.333333333 や 100.0 などの数値を正確に表すことはできません。これは、double を使用する際の注意が必要なことの 1 つです。ユーザーに表示する前に、回答を丸める必要があります。幸いなことに、ほとんどのアプリケーションでは、小数点以下の桁数は必要ありません。

于 2010-03-18T00:38:54.410 に答える
2

浮動小数点数は、特定の浮動小数点数に対して次に大きい浮動小数点数があるという点で実数とは異なります。整数と同じ。1 と 2 の間に整数はありません。

1/3 を float として表現する方法はありません。その下にフロートがあり、その上にフロートがあり、それらの間には一定の距離があります。そして 1/3 はそのスペースにあります。

Java 用の Apfloat は、任意精度の浮動小数点数で動作すると主張していますが、私はそれを使用したことがありません。おそらく一見の価値があります。 http://www.apfloat.org/apfloat_java/

Java浮動小数点高精度ライブラリの前に同様の質問がここで尋ねられました

于 2010-03-18T00:40:47.543 に答える
2

すべてに 100 を掛けて、セント単位の long に格納します。

于 2008-11-27T01:56:29.223 に答える
1

Math クラスの round() メソッドを使用しないのはなぜですか?

// The number of 0s determines how many digits you want after the floating point
// (here one digit)
total = (double)Math.round(total * 10) / 10;
System.out.println(total); // prints 11.4
于 2015-11-14T16:05:34.067 に答える
1

double は、Java ソース内の 10 進数の近似値です。double (バイナリ コード化された値) とソース (10 進数コード化された) の間の不一致の結果が表示されます。

Java は、最も近いバイナリ近似を生成します。java.text.DecimalFormat を使用して、見栄えの良い 10 進数値を表示できます。

于 2008-11-27T02:22:49.407 に答える
1

BigDecimal を使用します。丸めルールを指定することもできます (ROUND_HALF_EVEN のように、両方が同じ距離である場合に偶数近傍に丸めることで統計誤差を最小限に抑えます。つまり、1.5 と 2.5 の両方が 2 に丸められます)。

于 2008-11-27T02:36:26.227 に答える
0

BigDecimal をチェックしてください。これは、そのような浮動小数点演算を扱う問題を処理します。

新しい呼び出しは次のようになります。

term[number].coefficient.add(co);

使用する小数点以下の桁数を設定するには、setScale() を使用します。

于 2010-03-17T23:14:14.300 に答える
0

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;
}
于 2018-05-07T10:59:58.363 に答える
-2

BigDecimal を使用して労力を無駄にしないでください。99.99999% の場合、必要ありません。Javaのdouble型はもちろん概算ですが、ほとんどの場合、十分に正確です。有効数字の 14 桁目に誤りがあることに注意してください。これは本当に無視できます!

適切な出力を取得するには、次を使用します。

System.out.printf("%.2f\n", total);
于 2010-05-21T12:16:14.860 に答える