"New Bigdecimal (13.3d)"은 "13.300000000000000007105 .."가 부정확하게 발생합니다.

StackOverflow https://stackoverflow.com/questions/460755

  •  19-08-2019
  •  | 
  •  

문제

Java는 어떻습니까? BigDecimal 이 고통이 될 수 있습니까?

Double d = 13.3D;

BigDecimal bd1 = new BigDecimal(d);
BigDecimal bd2 = new BigDecimal(String.valueOf(d));


System.out.println("RESULT 1: "+bd1.toString());
System.out.println("RESULT 2: "+bd2.toString());

RESULT 1: 13.300000000000000710542735760100185871124267578125
RESULT 2: 13.3

결과 1이 원하는 상황이 있습니까? 나는 Java 1.5가 바뀌 었다는 것을 알고 있습니다 toString() 방법이지만 이것이 의도 된 결과입니까?

또한 나는 그것을 알고 있습니다 BigDecimal 가지다 doubleValue() 기타, 그러나 내가 함께 일하는 도서관은 toString() 그리고 나는 그것을 바꿀 수 없습니다 :-(

건배.

도움이 되었습니까?

해결책

글쎄, API 생성자 에서이 명백한 불일치를 해결합니다 BigDecimal(double val):

  1. 이 생성자의 결과는 다소 예측할 수 없을 수 있습니다. One might assume that writing new BigDecimal(0.1) in Java creates a BigDecimal which is exactly equal to 0.1 (an unscaled value of 1, with a scale of 1), but it is actually equal to 0.1000000000000000055511151231257827021181583404541015625. 0.1이기 때문입니다 정확히 이중으로 표현할 수 없습니다 (또는 그 문제에 대해 유한 길이의 이진 분율로). 따라서, 생성자로 전달되는 값은 정확히 0.1과 같지 않으며, 외관에도 불구하고.

  2. 반면에 문자열 생성자는 완벽하게 예측 가능합니다. 새로운 bigdecimal ( "0.1")을 작성하면 예상대로 0.1과 정확히 같은 큰 부문을 만듭니다. 그러므로, 일반적으로 문자열 생성자 가이 제품보다 우선적으로 사용하는 것이 좋습니다.

  3. 더블을 bigdecimal의 소스로 사용해야하는 경우,이 생성자는 정확한 변환을 제공합니다. Double.toString (Double) 메소드를 사용하여 Double을 문자열로 변환 한 다음 BigDecimal (String) 생성자를 사용하여 동일한 결과를 제공하지 않습니다. 그 결과를 얻으려면 정적 값의 (이중) 방법을 사용하십시오.

이야기의 도덕 : 고통은 자기 감염된 것 같습니다. new BigDecimal(String val) 또는 BigDecimal.valueOf(double val) 대신 =)

다른 팁

당신의 문제는 아무 관련이 없습니다 BigDecimal, 그리고 모든 것 Double, 이진 분획을 내부적으로 사용하므로 정확하게 13.3을 나타내는 것은 아닙니다.

따라서 오류는 첫 번째 줄에 소개됩니다. 첫번째 BigDecimal 단순히 그것을 보존합니다 String.valueOf() 두 번째는 운이 좋은 콘텐츠를 갖도록하는 비린내 반올림을 수행합니다.

부동 소수점 값이 어떻게 구현되는지에 대해 스스로에게 알릴 수 있습니다 (IEEE 754-1985). 그리고 갑자기 모든 것이 결정적이 될 것입니다.

이것은 결점이 아닙니다 BigDecimal - 그것은 잘못입니다 double. BigDecimal 정확하게 표현하고 있습니다 정확한 가치 d. String.valueOf 결과를 소수점 이하 자리에만 보여줍니다.

이진수 유형으로 표시되는 분획 (즉 double, float) 이러한 유형에 정확하게 저장할 수 없습니다.

    Double d = 13.3;        
    BigDecimal bdNotOk = new BigDecimal(d);
    System.out.println("not ok: " + bdNotOk.toString());

    BigDecimal bdNotOk2 = new BigDecimal(13.3);
    System.out.println("not ok2: " + bdNotOk2.toString());

    double x = 13.3;
    BigDecimal ok = BigDecimal.valueOf(x);
    System.out.println("ok: " + ok.toString());

    double y = 13.3;
    // pretty lame, constructor's behavior is different from valueOf static method
    BigDecimal bdNotOk3 = new BigDecimal(y);
    System.out.println("not ok3: " + bdNotOk3.toString());

    BigDecimal ok2 = new BigDecimal("13.3");
    System.out.println("ok2: " + ok2.toString());

    Double e = 0.0;
    for(int i = 0; i < 10; ++i) e = e + 0.1; // some fractions cannot be accurately represented with binary
    System.out.println("not ok4: " + e.toString()); // should be 1


    BigDecimal notOk5 = BigDecimal.valueOf(e);
    System.out.println("not ok5: " + notOk5.toString()); // should be 1

    /* 
     * here are some fractions that can be represented exactly in binary:
     * 0.5   = 0.1   = 1 / 2
     * 0.25  = 0.01  = 1 / 4
     * 0.75  = 0.11  = 3 / 4
     * 0.125 = 0.001 = 1 / 8
     */

산출:

not ok: 13.300000000000000710542735760100185871124267578125
not ok2: 13.300000000000000710542735760100185871124267578125
ok: 13.3
not ok3: 13.300000000000000710542735760100185871124267578125
ok2: 13.3
not ok4: 0.9999999999999999
not ok5: 0.9999999999999999

그냥 사용하십시오 BigDecimal.valueOf(d) 또는 new BigDecimal(s).

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top