본문 바로가기
Golang

golang의 실수 계산(부동소수점 오차, 머신 엡실론)

by isn`t 2022. 11. 13.

golang에서의 실수는 소수점을 찍거나 또는 지수 표기법 e / E를와 + / - 를 사용하여 소수점 위치를 지정합니다. 컴퓨터는 2진수를 사용하기 때문에 실수를 정확하게 표현할 수 없는데, 특히 무한 소수의 경우 2진수로 정확히 표현할 수 없고 아쉬운대로 근사값으로 표현해야 합니다. 따라서 아래와 같은 문제 상황이 발생할 수 있습니다.

1. 등호(==)로 비교 불가능

package main

import (
    "fmt"
    "math"
)

func main() {
    //variables
    var (
        a float64 = 9.9
    )

    const (
        epsilon = 1e-14
    )

    a = a - 0.7

    fmt.Println(a) //9.2000000000001
}

변수 a에 9.9를 할당하고 0.7을 빼면 9.2가 나와야 하는데 9.2000000000001이 나옵니다. 이러한 문제를 Rounding Error(부동소수점 반올림 에러)라고 하며, 실수는 연산한 값을 등호(==)로 직접 비교 하면 안됩니다.

이렇게 오차가 발생하기 때문에 실수를 비교하려면 오차(|a-9.2|) 를 구한 뒤, 머신 엡실론과 비교합니다. "어떤 실수를 가장 가까운 부동소수점 실수로 반올림 하였을 때 상대오차는 항상 Machine Epsilon 이하이다" 라는 명제로부터 따라 오차가 Machine Epsilon 보다 작거나 같다면 두 실수는 같은 값이라 정의합니다.

'차이'를 계산하는 과정에서 음수가 나올 수도 있으므로 이는 절대값으로 표현하며, golang의 머신 엡실론은 1e-14 입니다.

따라서 아래와 같이 코드를 수정하고, 실수의 연산 결과를 비교할 수 있겠습니다.

package main

import (
    "fmt"
    "math"
)

func main() {
    //variables
    var (
        a float64 = 9.9
    )

    const (
        epsilon = 1e-14
    )

    a = a - 0.7


    fmt.Println(a)                          //9.200000000000004

    fmt.Println(math.Abs(a-9.2) <= epsilon) //True

}