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
}