Delphi에서 통화 가치를 비교할 때 반올림 문제를 방지하는 방법은 무엇입니까?

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

문제

AFAIK, Delphi Win32의 통화 유형은 프로세서 부동 소수점 정밀도에 따라 다릅니다.이로 인해 두 통화 값을 비교할 때 반올림 문제가 발생하고 컴퓨터에 따라 다른 결과가 반환됩니다.

지금은 소수점 2자리 정밀도만 필요하기 때문에 Epsilon 매개변수 = 0.009를 전달하는 SameValue 함수를 사용하고 있습니다.

이 문제를 피할 수 있는 더 좋은 방법이 있습니까?

도움이 되었습니까?

해결책

Delphi의 통화 유형은 1/10,000으로 확장된 64비트 정수입니다.즉, 가장 작은 증분은 0.0001과 같습니다.부동 소수점 코드와 같은 방식으로 정밀도 문제가 발생하지 않습니다.

그러나 통화 숫자를 부동 소수점 유형으로 곱하거나 통화 값을 나누는 경우 어떤 방식으로든 반올림을 수행해야 합니다.FPU는 이 메커니즘을 제어합니다("제어 단어"라고 함).Math 유닛에는 이 메커니즘을 제어하는 ​​몇 가지 절차가 포함되어 있습니다.특히 SetRoundMode.이 프로그램에서 효과를 볼 수 있습니다.

{$APPTYPE CONSOLE}

uses Math;

var
  x: Currency;
  y: Currency;
begin
  SetRoundMode(rmTruncate);
  x := 1;
  x := x / 6;
  SetRoundMode(rmNearest);
  y := 1;
  y := y / 6;
  Writeln(x = y); // false
  Writeln(x - y); // 0.0001; i.e. 0.1666 vs 0.1667
end.

사용 중인 타사 라이브러리가 제어 단어를 다른 값으로 설정하고 있을 가능성이 있습니다.제어 워드(예:반올림 모드)을 중요한 계산의 시작점에 명시적으로 지정합니다.

또한 계산이 일반 부동 소수점으로 전환된 다음 다시 통화로 전환되면 모든 베팅이 무효화됩니다. 감사하기가 너무 어렵습니다.모든 계산이 통화로 이루어졌는지 확인하세요.

다른 팁

아니요, 통화는 부동 소수점 유형이 아닙니다. 정수 스토리지로 구현 된 고정-정밀 소수점입니다. 정확히 비교할 수 있으며, 두 배의 반올림 문제가 없습니다. 따라서 통화 변수에 부정확 한 값을 보는 경우 문제는 통화 유형 자체가 아니라 그에 넣는 것입니다. 아마도 코드의 다른 곳에서 부동 소수점 계산이있을 것입니다. 해당 코드를 보여주지 않기 때문에이 질문에 더 많은 도움이되기가 어렵습니다. 그러나 일반적으로 말하면 솔루션은 통화 변수에 대한 비교를 수행하지 않고 통화 변수를 저장하기 전에 부동 소수점 번호를 올바른 정밀도로 반올림하는 것입니다.

더 빠르고 안전한 두 가지를 비교하는 방법 currency 값은 확실히 변수를 내부에 매핑하는 것입니다. Int64 대표:

function CompCurrency(var A,B: currency): Int64;
var A64: Int64 absolute A;
    B64: Int64 absolute B;
begin
  result := A64-B64;
end;

이렇게하면 비교 ( *100000 정수 값으로 작동) 중 하나는 반올림 오류를 피하며 기본 FPU 기반 구현 (특히 64 비트 XE2 컴파일러)보다 빠릅니다.

보다 이 기사 추가 정보.

당신의 상황이 내 것과 같다면, 당신은이 접근법이 도움이 될 수 있습니다. 나는 주로 급여에서 일합니다. 사업체가 3 개의 부서에 말하고이 세 부서 중 직원의 비용을 고르게 청구하려는 경우, 반올림 문제가있을 때가 많이 있습니다.

내가하고있는 일은 부서를 통한 루프가 총 비용의 3 분의 1을 청구하고 하위 토탈 (통화) 변수에 부과 된 비용을 추가하는 것입니다. 그러나 루프 변수가 분수를 곱하는 대신 한계와 동일하면 총 비용에서 하위 운동 변수를 빼고 마지막 부서에 넣습니다. 이 과정에서 발생하는 저널 항목은 항상 균형을 잡아야하기 때문에 항상 효과가 있다고 생각합니다.

스레드 참조 :

D7 / DUNIT : 모든 Checkequals (통화, 통화) 테스트가 갑자기 실패합니다 ...

https://forums.codegear.com/thread.jspa?threadid=16288

개발 워크 스테이션의 변화로 인해 통화 비교가 실패했습니다. 우리는 근본 원인을 찾지 못했지만 Windows 2000 SP4를 실행하는 두 대의 컴퓨터에서 GDS32.dll (Inter -Base 7.5.1 또는 2007) 및 Delphi (7 및 2009) 버전과 무관 하게이 라인

TIBDataBase.Create(nil);

현재 8087 통제 단어로 변경하십시오.

단위 테스트의 모든 통화 비교는 다음과 같은 재미있는 메시지로 실패합니다.

Expected: <12.34> - Found: <12.34>

gds32.dll은 수정되지 않았 으므로이 라이브러리에는 제 3 자 DLL에 대한 종속성이있는 것으로 보인다.

델파이의 통화 반올림에 대한 가능한 문제를 피하려면 4 진수 자리를 사용하십시오.

이렇게하면 매우 적은 양의 중산을 수행 할 때 반올림 문제가 없습니다.

"Been there. Done That. Written the unit tests."

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