본문 바로가기
Unity/Optimization

Approximately Vs Epsilon (부동 소수점 값 비교)(Approximately의 모순)

by Unreal_Kim 2024. 3. 27.

코드 최적화 중에 문득 궁금해진 것

부동 소수점 값 비교 시에 사용할 수 있는 방법이 꽤 다양한데 뭐가 더 나을까?

더보기

※ 부동 소수점 오차 때문에 정확한 비교 필요 

-> A * B = 10f가 나오는 게 맞다고 보여도,

 10f가 실제로 9.999999f 라는 등 오차가 생기는 경우가 있다

(IEEE-754 표준법 사용해서 저장하기 때문에 지수 표현에 오차가 생기는 것)

 

그래서 정확한 비교를 위한 대표적인 방법 두 가지.

이 둘 중에 뭘 사용하는 게 나을까?라는 멍청한 생각을 가지고 가볍게 시작했다.

 


결론은 일단 당연히 케바케

 

Mathf.Approximately

Mathf의 구현 방식을 보면

단순 비교가 아니라 두 수가 0의 근사치일 때도 잘 동작하도록 구현돼있다.

또한 Epslion을 여기서 사용하는데 8을 곱해줌으로 허용 범위를 널널하게 잡은듯 싶다.

 

 

Mathf.Epsilon 과 float.Epsilon

근데 문서에는 Epsilon보다 작은 범위 내의 오차를 잡아준다고 돼있는데

이러면 Epsilon * 8 보다 작은 범위 내의 오차를 잡아준다고 적어놔야 되는 거 아닌가?

 

혹시 Mathf의 Epsilon과 float.Epsilon이 다르니까 그렇겠지라고 생각한다면

Mathf의 Epsilon을 타고 들어가보면?

<1차> MathfInternal.FloatMinNormal을 보자
<2차> struct MathfInternal

결국 float의 Epsilon을 가져온다. 

즉 float.Epsilon == Mathf.Epsilon임.(진짜 세세히 따지면 다른데 아무튼..)

 

나랑 같은 의문을 가진 사람이 이미 있었다 ㅋㅋ..

 

결국 보면 8 * Epsilon보다 오차가 작아야 됨

 

Mathf.Approximately 장단점

아무튼 Approximately는 내부적으로 하는 것도 많고 

오차를 따로 사용자가 정할 수 없다는 게 단점이다.

그래도 쓰기도 편하고, 가독성도 좋고, 0의 근사치 비교에서 안전장치도 있고 해서 장점도 많다.

 

 

뺄셈을 통한 직접 구현(Epsilon)

 

직접 구현은 threshold값을 직접 정해줄 수 있음이 큰 장점이 된다.

또한 지금 버전은 간단히 구현한 것이라 안전 장치 등등이 없지만 필요에 의해 추가할 수 있고

그 뜻은 프로젝트에 필요한 것만 넣어 Approximately보다 좋은 성능을 낼 수 있다는 것.

(너무 당연한 소리인가..)

 

오차 허용 범위 조절

그리고 사실 float.Epsilon의 값도 오차 찾기에 너무 작은 값이라

보통의 프로젝트에서 이렇게 작은 값으로 할 필요도 없다.

오히려 threshold(오차 허용 범위)를 필요에 의해 크게 잡는 편이 많지..

 

오차 허용 범위를 더 좁히고 싶을 때

Approximately는 안 되지만 더 좁히는 것도 가능

double로 하면 진짜 오차 허용 범위가 엄청 좁아짐(필요한 적은 없었음)

 

 

필요에 따라 알아서 쓰자!