문제

이 질문은 이미 여기에 답이 있습니다.

뺄셈이 어떤 종류의 문제를 유발하고 결과 값이 잘못되었습니다.

double tempCommission = targetPremium.doubleValue()*rate.doubleValue()/100d;

78.75 = 787.5 * 10.0/100D

double netToCompany = targetPremium.doubleValue() - tempCommission;

708.75 = 787.5 - 78.75

double dCommission = request.getPremium().doubleValue() - netToCompany;

877.8499999999999 = 1586.6 - 708.75

결과 예상 값은 877.85입니다.

올바른 계산을 보장하기 위해 무엇을해야합니까?

도움이 되었습니까?

해결책

플로팅 포인트 산술의 정밀도를 제어하려면 사용해야합니다. java.math.bigdecimal. 읽다 Bigdecimal의 필요성 자세한 내용은 John Zukowski.

당신의 예를 감안할 때, 마지막 줄은 bigdecimal을 사용하는 것과 같습니다.

import java.math.BigDecimal;

BigDecimal premium = BigDecimal.valueOf("1586.6");
BigDecimal netToCompany = BigDecimal.valueOf("708.75");
BigDecimal commission = premium.subtract(netToCompany);
System.out.println(commission + " = " + premium + " - " + netToCompany);

이로 인해 다음 출력이 발생합니다.

877.85 = 1586.6 - 708.75

다른 팁

이전 답변에서 언급 한 바와 같이, 이것은 플로팅 포인트 산술을 수행 한 결과입니다.

이전 포스터가 제안한 것처럼 숫자 계산을 할 때 사용하십시오. java.math.BigDecimal.

그러나 사용하기에는 gotcha가 있습니다 BigDecimal. 이중 값에서 BigDecimal, 당신은 새로운 것을 선택할 수 있습니다 BigDecimal(double) 생성자 또는 BigDecimal.valueOf(double) 정적 공장 방법. 정적 공장 방법을 사용하십시오.

이중 생성자는 전체 정밀도를 변환합니다 double a BigDecimal 정적 공장은 효과적으로 그것을 a로 변환합니다 String, 그런 다음 그것을 a로 변환합니다 BigDecimal.

미묘한 반올림 오류가 발생할 때 관련이 있습니다. 숫자는 .585로 표시 될 수 있지만 내부적으로 그 값은 '0.58499999999999996472863211994907064437862109375'입니다. 당신이 사용했다면 BigDecimal 생성자, 0.585와 같지 않은 숫자를 얻는 반면, 정적 방법은 0.585와 같은 값을 제공합니다.

double value = 0.585;
System.out.println(new BigDecimal(value));
System.out.println(BigDecimal.valueOf(value));

내 시스템에서 제공됩니다

0.58499999999999996447286321199499070644378662109375
0.585

또 다른 예:

double d = 0;
for (int i = 1; i <= 10; i++) {
    d += 0.1;
}
System.out.println(d);    // prints 0.9999999999999999 not 1.0

대신 BigDecimal을 사용하십시오.

편집하다:

또한,이를 지적하기 위해 '자바'반올림 문제가 아닙니다. 다른 언어는 비슷한 행동 (반드시 일관성이 없지만) 행동을 나타냅니다. Java는 적어도 이와 관련하여 일관된 행동을 보장합니다.

위의 예를 다음과 같이 수정합니다.

import java.math.BigDecimal;

BigDecimal premium = new BigDecimal("1586.6");
BigDecimal netToCompany = new BigDecimal("708.75");
BigDecimal commission = premium.subtract(netToCompany);
System.out.println(commission + " = " + premium + " - " + netToCompany);

이렇게하면 처음부터 문자열을 사용하는 함정을 피합니다. 또 다른 대안 :

import java.math.BigDecimal;

BigDecimal premium = BigDecimal.valueOf(158660, 2);
BigDecimal netToCompany = BigDecimal.valueOf(70875, 2);
BigDecimal commission = premium.subtract(netToCompany);
System.out.println(commission + " = " + premium + " - " + netToCompany);

이 옵션이 복식을 사용하는 것보다 낫다고 생각합니다. WebApps에서 숫자는 어쨌든 문자열로 시작됩니다.

두 배로 계산할 때마다 이런 일이 발생할 수 있습니다. 이 코드는 877.85를 제공합니다.

Double Answer = Math.round (dcommission * 100000) / 100000.0;

달러가 아닌 센트 수를 저장하고 출력 할 때는 금액을 달러로 만 수행하십시오. 그렇게하면 정밀 문제로 고통받지 않는 정수를 사용할 수 있습니다.

응답을 참조하십시오 이 질문. 본질적으로 당신이보고있는 것은 플로팅 포인트 산술을 사용한 자연스러운 결과입니다.

편안하다고 느끼면 임의의 정밀도 (입력의 중요한 숫자?)를 선택하고 결과를 반올림 할 수 있습니다.

이것은 재미있는 문제입니다.

Timons Reply의 아이디어는 합법적 인 두 배가 될 수있는 가장 작은 정밀도를 나타내는 Epsilon을 지정한다는 것입니다. 응용 프로그램에서 0.00000001 미만의 정밀도가 필요하지 않다는 것을 알고 있다면 그가 제안한 것은 진실과 매우 가까운 결과를 얻기에 충분합니다. 최대 정밀도 (예 : 통화 정밀도의 금융 등)를 알고있는 응용 프로그램에 유용합니다.

그러나 반올림을 시도하는 데있어 근본적인 문제는 요소로 나눌 때 실제로 정밀 문제에 대한 또 다른 가능성을 소개한다는 것입니다. 복식의 조작은 다양한 주파수에 대한 부정확 한 문제를 일으킬 수 있습니다. 특히 TIMONS 코드로 다음을 실행하는 경우 매우 중요한 숫자로 반올림하려는 경우 (따라서 피연산자는 <0입니다).

System.out.println(round((1515476.0) * 0.00001) / 0.00001);

결과가 나옵니다 1499999.9999999998 여기서 목표는 500000 단위로 반올림하는 것입니다 (즉, 1500000을 원합니다)

실제로 부정확성을 완전히 제거했다고 확신하는 유일한 방법은 넓은 규모를 통과하여 축소하는 것입니다. 예를 들어

System.out.println(BigDecimal.valueOf(1515476.0).setScale(-5, RoundingMode.HALF_UP).doubleValue());

Epsilon 전략과 Bigdecimal 전략의 혼합을 사용하면 정밀도를 잘 통제 할 수 있습니다. Epsilon이라는 아이디어는 당신을 매우 가까워지고 Bigdecimal은 나중에 재조정으로 인한 부정확성을 제거합니다. BigDecimal을 사용하면 응용 프로그램의 예상 성능이 줄어 듭니다.

BigDecimal을 사용하여 최종 부서가 오류를 다시 도입 할 수있는 입력 값이 없다고 판단 할 수있는 경우 일부 용도 사례에 항상 필요하지는 않다는 것이 나에게 지적되었습니다. 현재 나는 이것을 올바르게 결정하는 방법을 모르기 때문에 누군가가 어떻게 알고 있다면, 나는 그것에 대해 기뻐할 것입니다.

지금까지 Java에서 가장 우아하고 효율적인 방법 :

double newNum = Math.floor(num * 100 + 0.5) / 100;

더 나은 아직 사용 jscience bigdecimal이 상당히 제한적이므로 (예 : SQRT 기능 없음)

double dCommission = 1586.6 - 708.75;
System.out.println(dCommission);
> 877.8499999999999

Real dCommissionR = Real.valueOf(1586.6 - 708.75);
System.out.println(dCommissionR);
> 877.850000000000
double rounded = Math.rint(toround * 100) / 100;

정확한 계산을 위해 복식을 사용해서는 안되지만 다음 트릭은 결과를 반올림하는 경우 도움이되었습니다.

public static int round(Double i) {
    return (int) Math.round(i + ((i > 0.0) ? 0.00000001 : -0.00000001));
}

예시:

    Double foo = 0.0;
    for (int i = 1; i <= 150; i++) {
        foo += 0.00010;
    }
    System.out.println(foo);
    System.out.println(Math.round(foo * 100.0) / 100.0);
    System.out.println(round(foo*100.0) / 100.0);

어떤 인쇄 :

0.014999999999999965
0.01
0.02

더 많은 정보: http://en.wikipedia.org/wiki/double_precision

아주 간단합니다.

출력을 위해 %.2F 연산자를 사용하십시오. 문제 해결됨!

예를 들어:

int a = 877.8499999999999;
System.out.printf("Formatted Output is: %.2f", a);

위의 코드는 877.85의 인쇄 출력을 초래합니다.

%.2F 운영자는 두 십수 자리 만 사용해야한다고 정의합니다.

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