サーチ…


前書き

浮動小数点数は、小数部を持つ数値です(通常は小数点以下で表されます)。 Javaでは、 float (4バイト使用)とdouble (8バイト使用)の2つのプリミティブ型があります。このドキュメンテーションページは、Javaの浮動小数点で実行できる操作例を詳しく説明しています。

浮動小数点値の比較

関係演算子( ==!=<など)を使用して浮動小数点値( floatまたはdouble )を比較するときは注意が必要です。これらの演算子は、浮動小数点値のバイナリ表現に従って結果を返します。例えば:

public class CompareTest {
    public static void main(String[] args) {
        double oneThird = 1.0 / 3.0;
        double one = oneThird * 3;
        System.out.println(one == 1.0);      // prints "false"
    }
}

計算oneThird小さな丸め誤差を導入しており、我々は掛けたときにoneThirdすることによって3我々はわずかに異なる結果を得る1.0

この不正確な表現の問題は、計算でdoublefloatを混ぜようとすると、より強くなります。例えば:

public class CompareTest2 {
    public static void main(String[] args) {
        float floatVal = 0.1f;
        double doubleVal = 0.1;
        double doubleValCopy = floatVal;

        System.out.println(floatVal);      // 0.1
        System.out.println(doubleVal);     // 0.1
        System.out.println(doubleValCopy); // 0.10000000149011612
        
        System.out.println(floatVal == doubleVal); // false
        System.out.println(doubleVal == doubleValCopy); // false
    }
}

float型とdouble型のJavaで使用される浮動小数点表現は、精度の桁数に制限があります。 float型の場合、精度は23バイナリまたは約8桁です。 doubleタイプの場合、52ビットまたは約15桁の10進数です。さらに、算術演算によっては丸め誤差が発生することがあります。したがって、プログラムが浮動小数点値を比較する場合、比較のための許容デルタを定義するのが標準的な方法です。 2つの数の差がデルタより小さい場合、それらは等しいとみなされる。例えば

if (Math.abs(v1 - v2) < delta)

デルタ比較例:

public class DeltaCompareExample {

    private static boolean deltaCompare(double v1, double v2, double delta) {
        // return true iff the difference between v1 and v2 is less than delta
        return Math.abs(v1 - v2) < delta;
    }
    
    public static void main(String[] args) {
        double[] doubles = {1.0, 1.0001, 1.0000001, 1.000000001, 1.0000000000001};
        double[] deltas = {0.01, 0.00001, 0.0000001, 0.0000000001, 0};

        // loop through all of deltas initialized above
        for (int j = 0; j < deltas.length; j++) {
            double delta = deltas[j];
            System.out.println("delta: " + delta);

            // loop through all of the doubles initialized above
            for (int i = 0; i < doubles.length - 1; i++) {
                double d1 = doubles[i];
                double d2 = doubles[i + 1];
                boolean result = deltaCompare(d1, d2, delta);

                System.out.println("" + d1 + " == " + d2 + " ? " + result);
                
            }

            System.out.println();
        }
    }
}

結果:

delta: 0.01
1.0 == 1.0001 ? true
1.0001 == 1.0000001 ? true
1.0000001 == 1.000000001 ? true
1.000000001 == 1.0000000000001 ? true

delta: 1.0E-5
1.0 == 1.0001 ? false
1.0001 == 1.0000001 ? false
1.0000001 == 1.000000001 ? true
1.000000001 == 1.0000000000001 ? true

delta: 1.0E-7
1.0 == 1.0001 ? false
1.0001 == 1.0000001 ? false
1.0000001 == 1.000000001 ? true
1.000000001 == 1.0000000000001 ? true

delta: 1.0E-10
1.0 == 1.0001 ? false
1.0001 == 1.0000001 ? false
1.0000001 == 1.000000001 ? false
1.000000001 == 1.0000000000001 ? false

delta: 0.0
1.0 == 1.0001 ? false
1.0001 == 1.0000001 ? false
1.0000001 == 1.000000001 ? false
1.000000001 == 1.0000000000001 ? false

また、 doublefloatプリミティブ型のcompareために、対応するboxing型のstatic compareメソッドを使用できます。例えば:

double a = 1.0;
double b = 1.0001;

System.out.println(Double.compare(a, b));//-1
System.out.println(Double.compare(b, a));//1

最後に、どのデルタが比較に最も適切かを判断するのは難しいことがあります。一般的に使用されている方法は、デルタ値を選択することです。しかし、入力値の尺度と(真の)正確さ、および実行された計算を知っている場合、結果の精度、したがってデルタの数学的に健全な境界を思い付くことができます。 (この種の分析を扱う計算科学者に教えられていた数値解析として知られている正式な数学の枝があります。)

オーバーフローとアンダーフロー

浮動小数点データ型

浮動小数点データ型は、単精度の32ビットIEEE 754浮動小数点です。

Floatオーバーフロー

可能な最大値は3.4028235e+38 、この値を超えるとInfinity

float f = 3.4e38f;
float result = f*2;        
System.out.println(result); //Infinity

Float アンダーフロー

最小値は1.4e-45fで、この値を下回ると0.0生成されます。

    float f = 1e-45f;
    float result = f/1000;
    System.out.println(result);

ダブルデータ型

doubleデータ型は、倍精度の64-bit IEEE 754浮動小数点です。

Double オーバーフロー

可能な最大値は1.7976931348623157e+308 。この値を超えると、 Infinity

double d = 1e308;
double result=d*2;      
System.out.println(result); //Infinity

Double アンダーフロー

最小値は4.9e-324で、この値を下回ると0.0生成されます。

    double d = 4.8e-323;
    double result = d/1000;
    System.out.println(result); //0.0

浮動小数点値の書式設定

浮動小数点数は、 'f'フラグを持つString.formatを使用して10進数でフォーマットできます

    //Two digits in fracttional part are rounded
    String format1 = String.format("%.2f", 1.2399);
    System.out.println(format1); // "1.24"

    // three digits in fractional part are rounded 
    String format2 = String.format("%.3f", 1.2399);
    System.out.println(format2); // "1.240"
    
    //rounded to two digits, filled with zero 
    String format3 = String.format("%.2f", 1.2);
    System.out.println(format3); // returns "1.20"
    
    //rounder to two digits
    String format4 = String.format("%.2f", 3.19999);
    System.out.println(format4); // "3.20"

浮動小数点数は、 DecimalFormatを使用して10進数としてフォーマットできます

   // rounded with one digit fractional part 
    String format = new DecimalFormat("0.#").format(4.3200);
    System.out.println(format); // 4.3
    
   // rounded with two digit fractional part 
    String format = new DecimalFormat("0.##").format(1.2323000);
    System.out.println(format); //1.23

    // formatting floating numbers to decimal number
    double dv = 123456789;
    System.out.println(dv); // 1.23456789E8
    String format =  new DecimalFormat("0").format(dv);
    System.out.println(format); //123456789

IEEE仕様への厳格な遵守

デフォルトでは、 floatdouble浮動小数点演算は、IEEE 754仕様の規則に厳密に従わない 。式では、これらの値の範囲に対する実装固有の拡張を使用することができます。基本的にそれらが必要以上に正確であることを可能にする。

strictfpはこの動作を無効にします。それはこのようなその他のクラス、インタフェース、メソッド、コンストラクタ、変数イニシャライザなど、クラス、インタフェース、またはメソッドに適用され、その中に含まれるすべてのものに適用されるstrictfp 、浮動小数点表現の中間値は以内でなければなりません float値セットまたはdouble値セット。これにより、そのような式の結果は、IEEE 754仕様が予測する結果と正確に一致します。

すべての定数式はstrictfpスコープ内になくても、暗黙的に厳密です。

したがって、 strictfpは時には特定のコーナーケースの計算の精度を低下させる正味の効果を持ちます。また、浮動小数点演算を遅くすることもできます (CPUがネイティブの精度を確保して結果に影響を与えないようにします)。ただし、結果はすべてのプラットフォームでまったく同じになります。それは、再現性がスピードよりも重要である科学的プログラムのようなものに有用です。

public class StrictFP { // No strictfp -> default lenient
    public strictfp float strict(float input) {
        return input * input / 3.4f; // Strictly adheres to the spec.
                                     // May be less accurate and may be slower.
    }

    public float lenient(float input) {
        return input * input / 3.4f; // Can sometimes be more accurate and faster,
                                     // but results may not be reproducable.
    }

    public static final strictfp class Ops { // strictfp affects all enclosed entities
        private StrictOps() {}

        public static div(double dividend, double divisor) { // implicitly strictfp
            return dividend / divisor;
        }
    }
}


Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow