프로그래밍은 하면 할 수록 오차와의 씨름이라는 생각이 든다. 컴퓨터라는 물건이 오차가 없는 이론적으로 완벽한 기계라면 문제가 없겠지만, 언제나 오차가 있기 때문에, 그 오차가 어떻게 영향을 주는지에 따라서 결과가 많이 바뀐다. 특히, 새로운 방법을 테스트 해볼 때는, 이 문제가 오차 때문에 발생하는 어쩔 수 없는 문제인지, 아니면 방법이 문제가 있어서 오차가 없이도 좋아 질 수 없는 것인지 알기 힘들기도 하다.
이번 문제는 내가 겪은건 아니고 동료가 겪은 것이다. 역시 이론적으로는 문제가 없는 문제인데, 계산의 순서 때문에 결과가 달라지는 문제였다.
삼각형의 세 꼭지점을 P0, P1, P2 라고 하고, 꼭지점을 잇는 벡터 Edge1 을 P0->P1, Edge2 는 P0->P2 라고 한다. 일반적으로 Ray 의 방향과 culling 계산을 할 때 삼각형의 Normal 과 Ray 를 내적해서 계산한다. 아래 가상 코드는 삼각형의 Normal 과 Ray 가 수직일 때를 걸러주는 코드이다. (backface 는 culling 하는 것이 아니라, 삼각형이 ray 방향으로 누워있는 것을 culling 하는 코드다.)
Normal = Edge1 X Edge2;
if (Normal dot Ray) == 0 then culling
그런데 무슨 일인지, == 0 을 Epsilon 으로 계산해버렸다. (개인적으로는 굳이 할 필요가 없는 부분이라고 보이지만..., 그냥 문제가 생기는 예시라고 생각하면 될듯 하다.)
- if abs(Normal dot Ray) < EPSILON_FLOAT then culling
위 코드는 문제가 없다. 일단은 원하는대로 결과가 나온다. 그런데 이론적으로는 전혀 문제 수식을 살짝 적용하면 문제가 생긴다.
일반적으로 가 성립한다. 이 수식은 이론적으로는 아무런 문제가 없는 간단한 공식이다. 이 공식을 위에 적용해본다.
Temp = Ray X Edge1;
if abs(Temp dot Edge 2) < EPSILON_FLOAT then culling
Epsilon 을 제외하면 수학적으로는 아무 문제가 없다. 하지만 epsilon 을 고려하게 되면 삼각형의 Normal 로는 culling 이 되지 않아야 할때도, Edge1 과 Edge2 가 매우 가까울 때 culling 이 되어버리는 문제가 생긴다. 결국 이 문제 때문에 다른 물체는 다 렌더링이 정상적으로 되는데, 전체적으로 삼각형의 Edge 1, 2 가 매우 좁게 형성된 물체는 아에 렌더링이 안되는 신기한 결과가 생겼었다.
모로 가도 서울만 가면 된다라는 말이 있는데, 프로그래밍에서는 이 말을 사용하지 말아야할듯하다.
첫번째는, 이론적으로 틀려도(알수가 없어도, 버그가 있어도), 일단 결과만 나오면 그냥 넘기는 경우가 있는데, 이런 코드는 나중에 두 세배로 문제가 생기는 경우가 허다하다(모-증명 없는 코딩, 서울-결과 출력). 두번째는 이론적으로는 아무런 문제가 없어도(없는 것 처럼 보여도) 알고보면 수치적인 오류 때문에 문제가 생기는 경우가 있다(모-수치 오차, 서울-이론만 완벽).
정리
가급적 이론적으로 증명을 하자. 근사 값이 필요할 때는 근사 값을 쓸 수 있는지 가급적 증명을 하자(최소한 근사를 쓰면 안될 수도 있는 상황도 염두는 해두자)[1].
이론적으로 증명 되었다 하더라도, 실제로는 수치적 오차가 있을 수 있다. 이런 것을 항시 염두해야한다.
기타 1. Matlab 에서의 경험
다른 얘기인데, 처음으로 수치 오차에 대해 경험한 일이다. 그땐 잘 몰랐기 때문에, 사실상 Matlab 이나, C 로 짜는 프로그램이나 근본적으로는 수치 계산이 별반다르지 않는 다는 것을 몰랐을 때였다.
Matlab 으로 0.08 - 0.5 + 0.52 을 계산해보면 0이 나온다. 0이 맞다. 그런데, 순서를 바꿔서 0.42 - 0.5 + 0.08 을 계산하면 0 이 아니라, 아주 극히 작은 값이 들어간다. 그때 처음으로 느꼈다. 컴퓨터는 진짜 멍청하구나.
기타 2. 기타 상식
아주 기초적인 상식 두가지
매우 큰 값과 작은 값을 더할 때도 오차의 문제가 더 생긴다. 가급적 비슷한 크기로 더해나가야 한다.
비슷한 수끼리의 뺄셈을 할때 오차가 생긴다. - Loss of Significance - 위키 링크
기타 3. 수학과 프로그래밍
공부하면 공부할수록, 경험이 쌓이면 쌓일 수록, 수학과 프로그래밍은 밀접한 것 같다.
예를 들어, 수학을 잘하는 사람, 증명에 익숙한 사람들은 뭔가를 증명할 때
라고 쓰는 것에 그치지 않고,
이라는 조건을 달아줄 것이다.
또한, 방금의 문제를 생각하면, 는 사실 아무때나 써먹을 수 있는 공식이 아니다. 수학적으로는 A 와 B 가 같으면 안된다. 위에서 제시한 culling 오차 문제는 A 와 B 가 극히 가까울 때 생기는 문제니까, 결과적으로는 수학적으로 A 와 B 가 같으면 안된다는 조건과 어느정도 연관이 있다.
이런 사람들이 코딩을 하면 그 버릇을 그대로 활용할 수 있다. assert 를 둔다던지, 또 다른 에러 처리를 한다던지, 공식 자체를 변형해서 사전에 공식의 문제점을 발견한다던지 해서 말이다.
- Genetic Algorithm 같은 무턱대고 하는 것 같은(?) 알고리즘도 실제로는 수렴 여부가 증명되어 있다. 실제로 이런 알고리즘은 Parameter 값에 따른 수렴 범위를 이론적으로 어느정도 알 수 있기 때문에, 이런 증명이 선행 된다면 효율성에서 많은 차이가 있을 것이다. 이 문제를 깊히 다루면 역시 또 복잡한 문제가 된다. 몇%의 확률로 어떤 step 안에 수렴될 확률 등이 증명이 될수도 있기 때문이다. [본문으로]







878826
462
576





댓글을 달아 주세요