2011-12-06 1 views
2

double/float의 문제점을 알고 있으며 화폐 필드를 나타 내기 위해 double/float 대신 BigDecimal을 사용하는 것이 좋습니다. 그러나 double/float은보다 효과적이고 공간을 절약합니다. 그럼 내 질문은 : Java 클래스의 통화 필드를 나타 내기 위해 double/float을 사용할 수 있지만 BigDecimal을 사용하여 산술 (즉, 산술 연산을 수행하기 전에 double/float을 BigDecimal로 변환) 및 등가 확인을 처리 할 수 ​​있습니까?화폐 필드를 저장하고 BigDecimal을 산술로 사용하려면 double을 사용할 수 있습니까?

이유는 공간을 절약하기 위해서입니다. 그리고 저는 많은 프로젝트가 이중/부동을 사용하여 통화 필드를 나타냅니다.

이 문제가 있습니까? 미리 감사드립니다.

+0

돈이 사라지기를 원하지 않는 한, 수레/두 배로 화폐 가치를 저장하지 마십시오. –

+0

나는 오직 하나의 대답만을 받아 들일 수 있기 때문에, 많은 분들께 감사드립니다. – lostinmoney

답변

5

아니요, 불가능합니다.

doublexy의 두 값을 저장하기에 충분하다고 가정합니다. 그런 다음 이들을 안전한 BigDecimal으로 변환하고 여러 개를 변환합니다. 결과는 정확하지만, 승수 결과를 double에 다시 저장하면 정확도가 떨어질 가능성이 있습니다. 증명 :

double x = 1234567891234.0; 
double y = 1234567891234.0; 
System.out.println(x); 
System.out.println(y); 

BigDecimal bigZ = new BigDecimal(x).multiply(new BigDecimal(y)); 
double z = bigZ.doubleValue(); 
System.out.println(bigZ); 
System.out.println(z); 

결과 :

1.234567891234E12   //precise 'x' 
1.234567891234E12   //precise 'y' 
1524157878065965654042756 //precise 'x * y' 
1.5241578780659657E24  //loosing precision 

xy 정확한뿐만 아니라 BigDecimal를 사용하여 곱셈이다. 그러나 double으로 다시 캐스팅 한 후 최하위 자리가 풀립니다.

+0

많은 감사. 그럼 어느 것이 당신의 제안입니까? 1. 모든 필드에 BigDecimal을 사용하십시오. 2.이 필드를 나타 내기 위해 long을 사용하십시오. – lostinmoney

+0

'double'은 16 자리의 최상위 자릿수를 저장할 수 있습니다. 'long'- 0부터 시작하는 18 자리 숫자. 'double'은 경고없이 최하위 자리수를 떨어 뜨릴 수 있고, 반면에 'long'은 오버 플로우 할 수 있습니다.정확성과 신뢰성에 정말로 관심이 있다면 항상 BigDecimal을 사용하십시오 (** 실제적으로 ** 낮은 값과 높은 값의 범위를 미리 알지 못한다면). 결국 빠르고 정확하게 프로그램하는 것이 낫습니까? –

+1

문자 그대로 1 달러를 다른 금액으로 곱하면 데이터 유형 선택보다 더 큰 문제가 발생합니다. . . – ruakh

2

double/float보다 훨씬 더 좋습니다.

BigDecimal 유형을 사용하면 실제 병목 현상이 발생합니까?

+0

이것은 센트만을 취급하는 간단한 화폐 응용 프로그램이 아니기 때문에. 소수점 이하 5 자리를 유지해야하는 가격이나 금액이있을 수 있습니다. – lostinmoney

+0

+1. 그러나 명확히하기 위해 :'int' 또는'long's를 사용한다면, 하나의 화폐 단위보다 작은 단위를 지원하기 위해 어떤 종류의 상수 요소, 보통 100 또는 1000을 써야 할 것입니다. 예를 들어 $ 1을 1000L, 1 ¢를 10L로 나타낼 수 있습니다. 이것을 자체 데이터 유형으로 포장하는 것이 좋습니다. – ruakh

0

핏이 떨어지는 것은 float/double이 정밀도를 잃지 않고 모든 값을 저장할 수 없다는 것입니다. BigDecimal을 사용하고 계산 중에 정밀도를 유지하더라도 최종 제품을 플로트/이중으로 저장하는 중입니다.

"적절한"해결책은 금전적 가치를 수천 달러를 나타내는 정수 (예 : Long)로 저장하는 것입니다. 대부분의 작업에 충분한 해상도를 제공합니다 (예 : 이자가 발생하는 반면, 부채꼴/복식을 사용하는 문제는 스테핑됩니다. 추가 된 "보너스"로, 이것은 float/double만큼의 저장 공간을 필요로합니다.

2

허용되는 것은 프로젝트에 따라 다릅니다. 일부 프로젝트에서는 double과 long을 사용할 수 있습니다. 그러나 다른 프로젝트에서는 이것이 받아 들일 수없는 것으로 간주됩니다. 두 배로 값을 70000000000000.00까지 (미국의 국가 채무보다 큼) 표시 할 수 있으며, 고정 된 장소는 오래도록 90000000000000000.00을 정확하게 나타낼 수 있습니다. 당신은 여전히 ​​각 센트를 설명 할 필요가 하이퍼 인플레이션 통화 (어떤 경우에도 나쁜 생각)와 함께하지만 어떤 이유로 처리해야하는 경우

, BigDecimal를 사용합니다.

당신은 이중 또는 길거나의 BigDecimal을 사용하는 경우, 당신은 결과를 반올림해야합니다. 당신이 어떻게 이런 일이 각 데이터 유형에 따라 다릅니다 당신이 무엇을 반올림 다른 작업에 대한 정밀도를 지정하는 데 필요한만큼의 BigDecimal는 경향이 최소한의 오류입니다. 2 배나 길게, 당신은 당신의 장치에 남아 있습니다.

2

통화가 포함될 수있는 모든 산술에 BigDecimal 외에는 사용하지 않는 것이 좋습니다.

항상 BigDecimal의 String 생성자를 사용해야합니다. 왜? JUnit 테스트에 다음 코드를보십시오 :

assertEquals(new BigDecimal("0.01").toString(), new BigDecimal(0.01).toString()); 

당신은 다음과 같은 출력을 얻을 :

expected:<0.01[]> but was <0.01[000000000000000020816681711721685132943093776702880859375]> 

진실은, 당신이 '더블'양이 정확히 0.01 을 저장할 수 없습니다. BigDecimal은 원하는 번호를 EXACTLY으로 저장합니다.

그리고 BigDecimal은 변경할 수 없음을 기억하십시오.

BigDecimal amount = new BigDecimal("123.45"); 
BigDecimal more = new BigDecimal("12.34"); 
amount.add(more); 
System.out.println("Amount is now: " + amount); 

을하지만, 결과 출력은 다음과 같습니다 : 다음은 컴파일

금액은 지금 : 123.45 새에 결과를 할당 할 필요가 있기 때문이다

(또는 동일) BigDecimal 변수. 당신이 당신의 값이 더 이상 15 이상이 없다고 보장 할 수있는 경우 :

amount = amount.add(more) 
+0

BigDecimal을위한 최고의 연습에 많은 감사드립니다. – lostinmoney

0

double의 유일한 사용 인 경우 소수 값은 다음 네, 당신은 어떤 조건에서 할 수 저장 에 : 즉

십진수를 입력 한 다음 double (53 비트 정밀도)으로 변환하고 double을 15 자리 정밀도 (또는 그 이하)로 십진수로 다시 변환하면 데이비드 Matula의 정리에서 손실없이 원래 값을 얻을 수 있습니다 그의 기사에서 증명 된 In-and-out conversions. 이 결과를 적용하려면 correct rounding으로 변환해야합니다.

참고 그러나 double 최선의 선택이 아닐 수 있음 : 소수점 몇 자리 (P)와 통화 값은 일반적으로 부동 소수점 않고 표현되지만, 고정 점에 있고,이 경우에, 변환 값을 10^p으로 스케일링하고이 정수를 저장하는 정수로 변환하는 것이 좋습니다.