procedure TForm1.Button1Click(Sender: TObject);
var
a: Extended;
s: String;
begin
a:=어떻게어떻게 뽑아낸 실수값;
s:=FloatToStr(Trunc(a));
Memo1.Lines.Add(s);
end;
위와 같은 코드를 돌렸는데 손으로 계산해보면 604 가 나올 값이 603 이 나오는 현상이 있었음.
실수타입의 저장형태와 연산과정에서 2진수로 처리된 것이 십진수로 변환되면서 일어나는 문제이다.
만약 0.1 이 2진수로 저장될 경우, 아래와 같은 형태로 저장된다.
0.1 x 2 -> 0.2 0
0.2 x 2 -> 0.4 0
0.4 x 2 -> 0.8 0
0.8 x 2 -> 1.6 1
0.6 x 2 -> 1.2 1
0.2 x 2 -> 0.4 0 (여기와 두번째 행은 같음. 즉 반복시작)
0.2 x 2 -> 0.4 0
0.4 x 2 -> 0.8 0
0.8 x 2 -> 1.6 1
0.6 x 2 -> 1.2 1
0.2 x 2 -> 0.4 0 (여기서 또 반복시작)
:
즉 0.1은 0.0001100110011001100110011.... 와 같은 영원한 순환소수임.
따라서 시스템 내부의 유한비트안에 저장할 자리수만 남기고 나머지 무한부분은 절사.
그러므로 시스템 내부적으로 저장된 2진수를 다시 10진수 형태의 실수로 전환시 오차 발생.
위에서 알 수 있는 실수연산의 문제점으로 인해 Trunc(604) 가 603으로 나와버리는 현상이 일어나는 경우가 있음.
그러므로 이것을 방지하기 위해 일반적으로 권장되는 방법은 계산결과값에 영향을 미치지 못하면서,
실수연산에서 일어날 수 있는 오차를 줄이기 위한 범위 내의 허용가능수치를 더해주는 방법이다.
원래 있던 코드를 아래와 같이 변경하면 정확하게 604라는 값을 출력한다.
굵은글씨와 주황색(?) 바탕으로 처리되어 있는 라인에 나름의 허용가능수치인 0.0000001 을 더해줬다.
procedure TForm1.Button1Click(Sender: TObject);
var
a, b: Extended;
s: String;
begin
a:=어떻게어떻게 뽑아낸 실수값;
b:=Trunc(a+0.0000001);
s:=FloatToStr(Trunc(b));
Memo1.Lines.Add(s);
end;
그냥 Trunc 함수 자체를 오버로딩해버리는 방법도 생각해볼 수 있다.
function Trunc(X: Real): Int64;
begin
Result:=System.Trunc(X+0.0000001);
end;
'Delphi' 카테고리의 다른 글
[Delphi] 웹페이지에서 텍스트 긁어와서 뒤지기 (0) | 2009.04.18 |
---|---|
[Delphi] 웹페이지의 html 긁어와서 뒤지기 (0) | 2009.04.18 |
[Delphi] GetDC(0) 으로 캡쳐되지 않는 윈도우 (0) | 2009.04.18 |
Delphi 레퍼런스 사이트 (0) | 2009.04.18 |
[Windows] netsh - 네트워크 관련 쉘 명령어 (0) | 2009.04.18 |