Go 언어 부동소수점 완벽 정복 오차 없는 계산을 위한 필독 가이드

 

Go 언어 부동소수점 완벽 정복 오차 없는 계산을 위한 필독 가이드

 

프로그래밍에서 소수점이 있는 실수를 다루려면 '부동소수점' 숫자가 꼭 필요하거든요.

특히 Go 언어에서는 이 숫자들이 어떻게 표현되고 다뤄지는지 제대로 이해하는 것이 정확하고 효율적인 계산의 첫걸음입니다.

Go의 부동소수점 타입

Go 언어에는 크게 두 가지 부동소수점 타입이 있는데요.

바로 'float32'와 'float64'입니다.

이 타입들은 현대 CPU에서 널리 지원하는 'IEEE-754' 표준을 따르고 있거든요.

'float32'는 단정밀도(single-precision)라고도 불리는데, 4바이트 크기에 약 6자리의 십진수 정밀도를 제공합니다.

반면에 'float64'는 배정밀도(double-precision)라고 불리며 8바이트 크기를 차지하고, 약 15자리의 십진수 정밀도를 가집니다.

이 타입들이 표현할 수 있는 값의 범위는 정말 어마어마한데요.

예를 들어, float32의 최댓값은 대략 3.4e38이고, float64는 무려 1.8e308에 달합니다.

덕분에 Go는 아주 큰 숫자부터 아주 작은 숫자까지 효과적으로 처리할 수 있습니다.

 

정밀도와 표현의 한계

부동소수점 숫자는 넓은 범위의 값을 표현할 수 있지만, 정밀도에는 명확한 한계가 있거든요.

모든 십진수 소수를 이진수 형태로 완벽하게 표현할 수는 없기 때문에, 잠재적인 정밀도 문제가 발생할 수 있습니다.

가장 대표적인 예시가 바로 숫자 '0.1'인데요.

이 숫자는 이진수로 정확하게 표현되지 않아 아주 작은 표현 오차를 갖게 됩니다.

아래 Go 코드를 한번 보시죠.

package main

import "fmt"

func main() {
    a := 0.1
    b := 0.2
    c := a + b
    fmt.Println(c) // 0.3을 기대했지만, 결과는 0.30000000000000004
}

이 예제에서 0.1과 0.2를 더하면 우리가 기대하는 0.3이 정확하게 나오지 않거든요.

이것이 바로 이진 부동소수점 표현 방식이 가진 내재적인 한계 때문입니다.

정밀도 문제 해결하기

이런 정밀도 문제를 해결하기 위한 방법도 물론 있는데요.

특히 정확성이 생명인 금융 관련 계산에서는 'decimal' 패키지를 사용하는 것이 아주 좋은 해법입니다.

이 패키지는 임의 정밀도(arbitrary-precision) 고정소수점 십진수를 제공하거든요.

덕분에 이진 부동소수점 연산의 함정에 빠지지 않고 십진수를 정확하게 표현하고 다룰 수 있습니다.

'decimal' 패키지는 이런 식으로 사용할 수 있는데요.

아래 예시를 통해 직접 확인해 보겠습니다.

package main

import (
    "fmt"
    "github.com/shopspring/decimal"
)

func main() {
    a := decimal.NewFromFloat(0.1)
    b := decimal.NewFromFloat(0.2)
    c := a.Add(b)
    fmt.Println(c) // 정확하게 0.3 출력
}

'decimal' 패키지를 활용하니 0.1과 0.2의 덧셈이 우리가 기대했던 결과인 0.3을 정확하게 내놓는 것을 볼 수 있는데요.

이처럼 중요한 계산에서는 정밀도를 보장하는 것이 핵심입니다.

핵심 실천 수칙

웬만하면 float32 대신 'float64'를 사용하세요.

더 높은 정밀도와 넓은 표현 범위를 가지고 있기 때문에, 메모리 제약이 아주 까다로운 상황이 아니라면 float64를 선택하는 것이 일반적입니다.

동등성 비교는 항상 조심해야 하는데요.

정밀도 문제 때문에 부동소수점 숫자를 직접 비교하면 예상치 못한 결과를 낳을 수 있습니다.

대신, 두 숫자의 차이가 아주 작은 '엡실론(epsilon)' 값 이내에 있는지 확인하는 방법을 고려해야 합니다.

아주 중요한 계산에는 정밀한 라이브러리를 활용하세요.

금융 소프트웨어처럼 정확한 십진수 표현이 필수적인 애플리케이션에서는, 앞서 소개한 'decimal' 같은 라이브러리를 사용해 부동소수점 연산의 위험을 피하는 것이 좋습니다.

결론

Go 언어에서 부동소수점의 미묘한 특징을 이해하는 것은 신뢰할 수 있고 정확한 애플리케이션을 개발하는 데 정말 중요하거든요.

이진수 표현의 한계를 인식하고 적절한 전략을 사용한다면, 정밀도를 효과적으로 관리하고 계산의 정확성을 보장할 수 있을 것입니다.