[GPG 4 글 2.3] 부동소수점 오차의 해결 방법은?

GPG 시리즈 관련 질답, 논의 공간.

Moderator: 류광

그레이오거
Posts: 322
Joined: 2006-01-18 13:25

부동소수점 오차의 해결 방법은?

Post by 그레이오거 »

아무생각없이 살다가 문득 부동소수점(float, double)의 오차 테스트를 해보니 좀 깨네요.;;

렌더링이야 그럭저럭 무시할만 하다지만 이걸로 엄격한 게임 진행(물리, 상태관리 등등)을 하기는 어렵다는 결론을 얻었습니다.

해결방법이 뭐가 있을까요? 일단 생각해본 바로는 [계산은 정수로, 사용시에만 실수로] 입니다.

0. 예를 들어 계산이 되는 범위가 -500.0 ~ 1000.0 정도의 작은 값일때는 int나 long으로 일정 비율만큼 변환해 계산한다음 필요할때만 실수로 변환하는 방법입니다. 일종의 고정소수이며 계산은 정수형으로, 렌더링시에만 실수로 사용한다는게 목적입니다... 만, 범위가 크거나 정밀계산을 요할 경우는 오히려 단점이 두드러지겠네요. 사용 가능 예가 상당히 제한될듯 싶습니다.

1. 실수형을 관리할 별도의 자료형을 만들어줍니다. 부동소수보단 고정소수가 편하겠네요. int 두세개정도만 써도 될듯. 대신 모든 오퍼레이터를 재정의 해줘야 되고 타 api와 연계하려면 반드시 래퍼를 만들어주어야 하는 귀찮음이 있습니다.

2. double을 넘어가는 실수 자료형을 만들던가, 일정이상의 오차를 최대한 보간해주는 자료형을 재정의합니다. 기존 float, double의 보완방식이며 기존의 알고리즘을 크게 건드리지 않아도 된다는 장점이 있을듯 합니다.

다른 방법으로는 뭐가 좋을까요? 일단 임시로 0.의 방법을 쓰고 차차 1.의 방법으로 나가는 편이 좋을 듯 합니다만...
비회원

Post by 비회원 »

저도 정밀도를 필요로 하는 모듈 하나 건들다가 삽질한 경험이 있네요.

분명 변수에 저장될 때는 0.000578 뭐 이 정도 였다고 치면..
다음 번에 변수에 접근할 때는 0.000610 뭐 이 정도로 바뀌어 버리는;;
물론 그 사이 변수에 아무런 접근은 없었구요.

_control87, _controlfp 이용해서 일차적으로 해결은 했지만,
속도가 느려질 수 있다는 경고 때문에 어쩔 수 없이 정수형으로 바꿔버렸습니다.

걍 단순하게 생각해보면..
속도 문제 없다면 _control87, _controlfp 쓰고,
아니면 처음부터 정수형을 쓰도록 하는게 좋을거 같네요.
오차 상관없다면 부동소수점 그대로 쓰면될테고..

뭔가 좋은 방법을 머리 좋은 사람들이 생각해 내지 않았을가 생각은 했지만,
해당 문제를 해결 해버려서 더 이상 생각은 해보지 못 했네요.
류광
Posts: 3805
Joined: 2001-07-25 09:00
Location: GPGstudy
Contact:

Post by 류광 »

벡터 분수는 어떨까요 - http://www.gpgstudy.com/catalog/3:2.2
suma
Posts: 160
Joined: 2005-02-21 09:32

위치관련한 계산 문제라면...

Post by suma »

GPG 4권에 2.3 Solving Accuracy Problem in Large World Coordinates 항목이 있더군요..
이 항목에서는 좌표계의 위치값이 아주 클 경우에 생기는 오차를 줄일수 있도록
offset을 두는 방식으로 해결하고 있습니다. 만일 위치와 관련된 계산이라면 이런식으로 오차를
줄일수 있겠지요.
그거랑 관련없이 큰 float 계산이라면...OTL.. 이죠..
저라면 그냥 double로..할 수 밖에 없지 않을까라는;;;;
Testors
Posts: 557
Joined: 2003-07-26 00:34
Location: (주)nFlavor
Contact:

Re: 부동소수점 오차의 해결 방법은?

Post by Testors »

그레이오거 wrote:아무생각없이 살다가 문득 부동소수점(float, double)의 오차 테스트를 해보니 좀 깨네요.;;
렌더링이야 그럭저럭 무시할만 하다지만 이걸로 엄격한 게임 진행(물리, 상태관리 등등)을 하기는 어렵다는 결론을 얻었습니다.
대신 오차를 줄이게 되면 비용이 커지기 때문에 연산이 많은 일들은 하기는 어렵게 되겠죠...
그레이오거 wrote:0. 예를 들어 계산이 되는 범위가 -500.0 ~ 1000.0 정도의 작은 값일때는 int나 long으로 일정 비율만큼 변환해 계산한다음 필요할때만 실수로 변환하는 방법입니다. 일종의 고정소수이며 계산은 정수형으로, 렌더링시에만 실수로 사용한다는게 목적입니다... 만, 범위가 크거나 정밀계산을 요할 경우는 오히려 단점이 두드러지겠네요. 사용 가능 예가 상당히 제한될듯 싶습니다.

1. 실수형을 관리할 별도의 자료형을 만들어줍니다. 부동소수보단 고정소수가 편하겠네요. int 두세개정도만 써도 될듯. 대신 모든 오퍼레이터를 재정의 해줘야 되고 타 api와 연계하려면 반드시 래퍼를 만들어주어야 하는 귀찮음이 있습니다.

2. double을 넘어가는 실수 자료형을 만들던가, 일정이상의 오차를 최대한 보간해주는 자료형을 재정의합니다. 기존 float, double의 보완방식이며 기존의 알고리즘을 크게 건드리지 않아도 된다는 장점이 있을듯 합니다.

다른 방법으로는 뭐가 좋을까요? 일단 임시로 0.의 방법을 쓰고 차차 1.의 방법으로 나가는 편이 좋을 듯 합니다만...
아마도 유리수 타입이 필요하신것 같은데...
새로 만드시는 것보다 일단 GMP 같은 라이브러리를 사용해 보시는것을 추천합니다.
GMP 같은 경우 - 100만년 전에 - 써본경험으로는 C++ 에서 바로 사용이 가능한 타입을 제공해 줬던걸로 기억합니다.

참고로 일반적으로 사용하는 소수(小數)표기법은 1을 유효자리수가 허용하는만큼 계속 등분해서 실수에 도달 하거나 혹은 근사치를 가르키는 방식이기 때문에 근본적으로 10진법이든 16진법이든 숫자의 크기에 관계없이 정밀도의 한계를 지닐수밖에 없습니다. (16진법에서 3/10 을 유한소수로 표현 못하는 것처럼 10진법 역시 1/3 이나 1/7을 유한소수로 표현할 수 없죠) 덕분에 연산을 거듭할수록 오차는 누적되구요. 그럼에도 불구하고 렌더링과 물리등에 사용하는 이유는... 무지하게 빠르기 때문입니다. ( -_-)
플머/모델러/애니메이터 구해염 **현역/보충역 병특가능** / http://testors.net/
그레이오거
Posts: 322
Joined: 2006-01-18 13:25

음... 결국 주고받고인가요

Post by 그레이오거 »

실버불렛은 역시 없었군요;;

상황에 따라 선택해야 할 듯 싶습니다.

그리고 __int64 연산하고 float연산하고 비교하면 어느쪽이 빠를까요? 재미삼아 __int64 변수 하나로 부동소수 자료형을 만들어봤는데 아직 퍼포먼스 테스트는 해보지 않았습니다. 양쪽 다 백만번씩 돌리면 차이가 나올려나요?
Post Reply