written by yechoi

(번역) 부동소수점을 이해하고 사용하기 본문

Born 2 Code/C, C++

(번역) 부동소수점을 이해하고 사용하기

yechoi 2020. 11. 1. 15:21
반응형

👉이 글은 Jeff Bezanson의 Understanding and Using Floating Point Numbers를 번역했습니다. 다소 의역한 부분이 있으며, 오역한 부분이 있다면 댓글을 부탁드립니다.  

 

C++ Article - Understanding Floating Point Numbers - Cprogramming.com

Understanding and Using Floating Point Numbers by Jeff Bezanson Numbers are surely the most prevalent kind of data in computer programs. They are so fundamental that people don't spend much time talking about them—surely everybody knows how to use number

www.cprogramming.com

 

숫자가 컴퓨터 프로그램에서 가장 흔한 데이터라는 것은 확실합니다. 너무나도 기초적인 나머지 사람들은 숫자에 대해 많이 논의하지 않습니다. 모든 사람들은 프로그램에서 숫자를 사용하는 방법을 알고 있다고 생각해요. 그렇지만 프로그래밍의 세계에서 가장 환상적인 것 중 하나는 당신이 마주하는 모든 것이 상상이상이라는 것이죠.

 

대부분의 프로그래머들은 부동소수점 실수에 대해 이상한 점을 듣거나 봤을 것입니다. 예를 들어, 우리는 종종 같아 보이는 부동소수점 실수가 C의 '==' 조건에 부합하지 않는다는 것을 발견하곤 합니다. 이러한 이유로 초보 프로그래머들은 부동소수점 실수에는 ==를 절대 사용하지 않도록 배우기도 하죠. 때때로 우리는 다른 예외적인 경우에 부딪히기도 합니다. 예를 들어 수학적으로 말이 되는 수식이, 부동소수점을 쓰기만 하면 실망스러울 정도로 정확하지 않거나 무작위의 결과를 내뱉기도 합니다.

 

어떤 일이 일어나는 걸까요? 부동소수점 실수에 관해선 직관에 어긋나는 것들이 많고, 이러한 특성 때문에 우리는 부동소수점 실수를 프로그램에서 사용하면서 여러가지를 배우게 됩니다.

 

부동소수점 실수는 착시 효과를 일으킵니다. 10진법이나 아주 작거나 큰 수로도 표현되면서 ’실제’ 숫자처럼 보이는 거죠. 현실에서 같은 4바이트로 표현한다고 했을 때, 실수보단 정수를 제대로 표현합니다. 이유는 당연하게도 부동 소수점 실수에 대한 내부적인 표현이 간단하지 않기 때문입니다. 정수를 표현하는 비트는 그 자체로 이진법의 수이지만, 부동소수점 실수를 표현하는 비트는 좀더 복잡하게 해석됩니다. 이 표현법에 대해선 나중에 길게 설명하도록 하고, 먼저 정수와 실수의 개념적인 차이를 알아보도록 할게요.

 

 

1. Accuracy vs. Precision

 

측정 개념 중에서 Accuracy와 Precision은 정수와 실수의 다른 특성을 잘 설명합니다(어떤 시스템에서도, 어떤 소수 표현법이 사용되더라도 이는 마찬가지예요.). "accuracy"는 측정치가 실제 값에 얼마나 비슷한지를 나타내는 값입니다. 반면 "precision"은 양에 관해 얼마 만큼의 정보를 가지고 있는지, 이를 당신이 얼마나 독창적으로 표현해냈는지에 관련돼 있습니다.

 

정수 계산은 완벽히 정확해요. (정수 "2"가 있다면, 그건 정확히 2인거죠. 누구도 이 사실에 이의 제기할 순 없어요.) 더욱이 여기에 1을 더하면, 정확히 3을 얻을 것이란 걸 알죠. 정수로 어떤 계산에 하든 간에, 오버플로우만 없다면야 비트 단위로 정확한 수를 얻게 될 겁니다. 그러나 정수엔 precision이 부족해요. 예를 들어 5와 4를 각각 2로 나누면, 둘다 2라는 결과를 내요. 정수는 조각난 부분에 대해선 정보를 가지고 있지 않아요. 4보다 약간 크고 5보다는 작은 수가 있다고 하면, 4보다 큰 부분의 정보는 잃어버리죠. 정수는 미세한 변화를 대표하기엔 너무 투박해요. 정수를 사용하는 건 벽돌을 쌓는 것과 같죠. 정육면체를 만든다면 벽돌이 아주 딱이겠지만, 구를 만든다고 생각하면 벽돌은 그닥 좋은 선택은 아니죠. (구가 벽돌보다 아주 크다면, 비슷하게 만들어볼 수는 있겠네요.)

 

퍼티로 벽돌을 쌓아 올리는 모습

 

실수는 accuracy와 precision에 있어서 정수와 정반대입니다. 당신이 표현하려는 수에 대한 정보를 의도적으로 버리는 일은 절대 없으므로 좋은 precision을 가지고 있어요. 비트만 많다면 원래의 수를 얻기 위해 어떤 FP 계산도 되돌릴 수 있죠. 마치 비트만 충분하면 아주 큰 정수도 표현할 수 있는 것처럼요. 그러나 소수점이 있는 수는 정확도가 부족합니다. 정수가 벽돌같다면, 실수는 멍청한 퍼티 같아요. 복잡한 곡면 모양에 바르도록 통제할 수는 있지만, 아주 딱 맞게 칠하려면 삐져나오죠. 퍼티로 완벽한 정육면체를 만든다고 생각해보세요. 모서리 부분을 완벽하게 날카롭게 만들 순 없을 거예요. 사실 많은 경우에서 소수점 숫자의 결과가 실제 수와 비트 단위로 정확히 일치하리라고 기대하는 건 말그대로 가망없는 일입니다.

 

모든 면이 바이너리에서 정확히 표현될 수는 없다는 점에서 실수는 태생적으로 정수와 다릅니다. 바이너리 계산을 탓하는 건 아닙니다. 어떤 진법 시스템에서도 이러한 제약은 마찬가지입니다. 1/3을 생각해보세요. 끝나지 않는 10진법 표현(e.g 0.333333)도 1/3과 같다고 할 수 없죠. 3을 끝도 없이 가져다 쓴다해도 정확하게 표현할 수 없을 겁니다. 따라서 한정된 소수점 자리수론 계산된 결과를 정확히 표현할 수 없다고 보는 게 낫겠네요. 당신이 무얼하든 결과는 실제와 조금은 틀릴 수 밖에 없습니다. 그럼에도 우리는 실수가 여전히 유용하다는 것을 알기 때문에, 반올림 에러 상황을 파악해 문제를 방지하는 편이 낫죠. 이를 위해서나 아니면 교양을 위해서라도, 소수가 실제로 어떻게 작동하는지 아는 건 좋은 일입니다.

반응형