수색…


소개

부동 소수점 숫자는 소수 부분이있는 숫자입니다 (일반적으로 소수점으로 표시). Java에서는 float (4 바이트 사용) 및 double (8 바이트 사용) 인 부동 소수점 숫자에 대해 두 가지 기본 유형이 있습니다. 이 문서 페이지는 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 계산은 작은 반올림 오류를 가져 oneThird3 을 곱하면 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
    }
}

자바에서 사용되는 부동 소수점 표현 floatdouble 종류의 정밀도 숫자의 제한된 수있다. float 유형의 경우 정밀도는 23 진수 또는 약 8 자리입니다. double 유형의 경우 52 비트 또는 약 15 자리 10 진수입니다. 그 중 일부 산술 연산은 반올림 오류를 발생시킵니다. 따라서 프로그램이 부동 소수점 값을 비교할 때 비교할 수있는 델타 를 정의하는 것이 표준 방법입니다. 두 숫자의 차이가 델타보다 작 으면 델타는 동일하다고 간주됩니다. 예를 들어

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 메소드를 사용할 수 있습니다. 예 :

double a = 1.0;
double b = 1.0001;

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

마지막으로 어떤 델타가 비교에 가장 적합한 지 결정하는 것은 까다로울 수 있습니다. 일반적으로 사용되는 접근법은 델타 값을 선택하는 것입니다. 우리의 직감은 올바른 것이라고 생각합니다. 그러나 입력 값의 정확성과 정확성을 확인하고 수행 된 계산을 알고있는 경우 결과의 정확성 및 따라서 델타에 대해 수학적으로 건전한 경계를 제시 할 수 있습니다. (이 종류의 분석을 다루는 계산 과학자들에게 가르쳐 지곤했던 Numerical Analysis로 알려진 공식적인 수학 분과가 있습니다.)

오버 플로우 및 언더 플로우

부동 데이터 유형

float 데이터 유형은 단 정밀도 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