BigDecimal에서 정확한 소수점 계산 수행

4938 단어 bigdecimal
이러한 상황을 고려하여 먼저 코드를 살펴보자.
public static void main(String[] args){

        System.out.println(0.4 + 0.8); // = 1.2 ?
        System.out.println(2 - 1.1);      // = 0.9 ?
        System.out.println(0.2 * 3);  // = 0.6 ?
        System.out.println(1.2 / 3); // = 0.4 ?

    }

아마도 당신은 첫 번째 줄 1.2, 두 번째 줄 0.9, 세 번째 줄 0.6, 네 번째 줄 0.4를 인쇄한다고 천진할 것입니다. 왜냐하면 다년간의 수학 관성 논리에 근거하여 출력 결과가 예상한 것과 일치하는 것은 매우 당연한 일이기 때문입니다!그러나 프로그램이 끝난 후에 출력의 결과가 예상한 것과 크게 다르기 때문에 다음 백그라운드의 인쇄 결과를 보십시오.
1.2000000000000002
0.8999999999999999
0.6000000000000001
0.39999999999999997

  
결과적으로 이런 결과를 보니 답답하지 않습니까?물론 이 데이터들은 내가 고의로 고른 것이다. 부동점수와 관련된 모든 연산 조작이 이렇게 예상치 못한 결과를 산출하는 것은 아니다. 그러나 명백한 것은 조작이 부동점수 연산과 관련될 때 우리는 반드시 이런 일이 발생하지 않도록 조심해야 한다는 것이다.위 코드에서 더하기, 빼기, 곱하기, 나누기, 모두 더블 레벨에 속하는 연산인데, 왜 이런 결과를 출력할 수 있습니까?모든 부동점수가 하나의 더블 유형 값으로 정확하게 표현되는 것은 아니기 때문에, 일부 부동점수는 더블 유형 값으로 정확하게 표현되지 못하기 때문에 가장 가까운 더블 유형 값으로 표현된다.그래서 아쉽게도 0.4+0.8≠1.2...어떻게 이 문제를 해결합니까?자바에서 정확한 소수 계산을 수행하기 위해 BigDecimal 클래스를 제공했고 BigDecimal 클래스는 다음과 같은 조작을 제공했다. 산술, 눈금 조작, 반올림, 비교, 해시 알고리즘과 형식 변환이다.BigDecimal 클래스가 제공하는 방법: 덧셈:add 뺄셈:subtract 곱셈:multiply 나누기:divide......BigDecimal 클래스가 제공하는 더 많은 방법은 API를 직접 보십시오. 다음은 BigDecimal 클래스로 위의 코드를 덮어쓰십시오.
    public static void main(String[] args){

        System.out.println(new BigDecimal(0.4).add(new BigDecimal(0.8)));      // = 1.2 ?
        System.out.println(new BigDecimal(2).subtract(new BigDecimal(1.1)));   // = 0.9 ?
        System.out.println(new BigDecimal(0.2).multiply(new BigDecimal(3))); // = 0.6 ?
        System.out.println(new BigDecimal(1.2).divide(new BigDecimal(3)));     // = 0.4 ?
        
    }

    
아마도 당신은 클래스 BigDecimal의 API를 찾고 있을 것입니다. API에서 클래스 BigDecimal에 대해 한 줄의 문자 설명을 가지고 있을 것입니다. 아마도 당신은 아직 다 보지 못했을 것입니다. 그러나 확실한 것은 클래스 BigDecimal이 정확한 소수의 집행을 확실히 보장할 수 있다는 것입니다. 그러면 제 위 코드의 주석을 잊어버린 것이 아닙니까?아니야.만약 정말 이렇게 한다면 큰 화를 초래하게 될 것이다.먼저 백그라운드의 인쇄 출력 결과를 살펴보겠습니다.
1.20000000000000006661338147750939242541790008544921875
0.899999999999999911182158029987476766109466552734375
0.60000000000000003330669073875469621270895004272460937

Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.    at java.math.BigDecimal.divide(BigDecimal.java:1603)    at example.BigDecimalApp.main(BigDecimalApp.java:20)   
만약 정말 이렇게 놀았다면 너는 결과가 더욱 징그러워지는 것을 보았을 것이다. 이것은 문제도 아니고 이상도 던졌을 것이다. 이것은 왜 그런가?서두르지 말고 API에서 어떻게 말했는지 살펴보자."
public BigDecimal(double val)은 더블의 바이너리 부동 소수점 값이 정확한 십진수 표현 형식인 BigDecimal로 더블을 변환합니다.반환된 BigDecimal의 눈금은 (10scale× val)은 정수의 최소값입니다.참고:
1. 이 구조 방법의 결과는 어느 정도 예측할 수 없는 것이 있다.자바에 new Big Decimal(0.1)을 써서 만든 Big Decimal은 0.1(비표도값 1, 그 표도 1)과 같다고 생각할 수도 있지만 실제로는 0.100000000000000000000551112531257827021181583404541015625와 같다.이는 0.1을 더블로 정확하게 표시할 수 없기 때문이다(또는 이 상황에 대해 그 어떠한 유한한 길이의 이진 소수도 표시할 수 없다). 이렇게 하면 구조 방법에 전달된 값이 0.1과 꼭 같지 않기 때문이다(표면적으로는 이 값과 같지만). 2. 다른 한편, String 구조 방법은 완전히 예측할 수 있다. new BigDecimal ("0.1") 을 쓰면 예상한 0.1과 같은 BigDecimal을 만들 것이다.따라서 일반적으로 String 구성 방법을 사용하는 것이 좋습니다.Double이 BigDecimal의 원본으로 사용되어야 할 경우 이 구조 방법은 정확한 변환을 제공합니다.Double을 먼저 사용하면 다음과 같은 결과가 제공되지 않습니다.toString(double) 방법을 사용한 다음 BigDecimal(String) 구조 방법을 사용하여 Double을 String으로 변환합니다.결과를 가져오려면 static value Of 방법을 사용합니다. 
매개 변수: val - BigDecimal의 더블 값으로 변환합니다.버퍼링: NumberFormatException - val이 무한대 또는 NaN이면
"위 글은 API에서 발췌한 것으로, API에서 명확하게 설명했으니 여기서 더 이상 말하지 않겠습니다. API는 String 구조 방법을 우선적으로 사용하라고 권장합니다. 그럼 한번 시도해 보겠습니다.
public static void main(String[] args){

   System.out.println(new BigDecimal("0.4").add(new BigDecimal("0.8")));//=1.2√
   System.out.println(new BigDecimal("2").subtract(new BigDecimal("1.1")))//=0.9√
   System.out.println(new BigDecimal("0.2").multiply(new BigDecimal("3")));//=0.6√
   System.out.println(new BigDecimal("1.2").divide(new BigDecimal("3")));//=0.4√
        
}

    
출력 백그라운드 인쇄:
1.2
0.9
0.6
0.4

 
OK, 이번에야말로 큰일이 나지 않을 것이다. 따라서 절대로 빅 데시멜 구조기를 함부로 사용해서 빅 데시멜 대상을 만들 수 없다. 왜냐하면 이 구조기는 그의 매개 변수의 정확한 값에 따라 실례 대상을 만들 수 있기 때문이다. 이 구조 방법의 결과는 어느 정도 예측할 수 없기 때문에 빅 데시멜 구조기로 빅 데시멜 실례를 만들면 문제가 없을 것이다.위에서 언급한 바와 같이 유형 BigDecimal 중의dd,subtract,multiply,divide 방법은 API에서 볼 수 있듯이 이 몇 가지 방법은 각각 자신의 재부팅 방법이 있다. 예를 들어add(BigDecimal augend,MathContext mc)...두 번째 매개 변수 mc는 무슨 뜻입니까?먼저 코드 세그먼트를 살펴보겠습니다.
public static void main(String[] args){

        //            
        System.out.println(new BigDecimal(Math.PI + "").add(new BigDecimal("0.89842"),new MathContext(2))); //   4.0
        
}

   
두 번째 매개 변수 mc는 계산 결과의 유효 비트를 보존하는 데 사용되며 다른 세 가지 방법의 재부팅 방법은 똑같다. 여기에 일일이 열거하지 않는다.
다음으로 이동:http://www.blogjava.net/fancydeepin/archive/2012/08/29/java_bigdecimal.html

좋은 웹페이지 즐겨찾기