가장 빨리 만나는 Go 언어 Unit 8.2 실수

저작권 안내
  • 책 또는 웹사이트의 내용을 복제하여 다른 곳에 게시하는 것을 금지합니다.
  • 책 또는 웹사이트의 내용을 발췌, 요약하여 강의 자료, 발표 자료, 블로그 포스팅 등으로 만드는 것을 금지합니다.

숫자 사용하기

이재홍 http://www.pyrasis.com 2014.12.17 ~ 2015.02.07

실수

실수는 소수점을 사용하거나 지수 표기법으로 표기할 수 있으며 변수에 저장될 때는 부동소수점 방식을 사용합니다. 여기서 지수 표기법은 e 또는 E를 사용하고 +, -로 소수점의 위치를 지정합니다(밑수는 10).

// 소수점 사용
var num1 float32 = 0.1
var num2 float32 = .35
var num3 float32 = 132.73287

// 지수 표기법
var num4 float32 = 1e7
var num5 float64 = .12345E+2
var num6 float64 = 5.32521e-10

컴퓨터는 2진수를 사용하므로 2진수로는 실수를 정확하게 표현할 수 없습니다. 왜냐하면 수학적으로 실수는 무한히 많은데 이 실수를 유한 개의 비트로 표현하기 위해서는 근사 값으로 표현해야 하기 때문입니다. 이런 문제를 부동소수점 반올림 오차(Rounding error)라고 합니다. 따라서 다음과 같이 실수는 연산한 값을 == (등호)로 직접 비교하면 안됩니다.

package main

import "fmt"

func main() {
	var a float64 = 10.0

	for i := 0; i < 10; i++ {
		a = a - 0.1
	}

	fmt.Println(a)        // 9.000000000000004: 반올림 오차 발생
	fmt.Println(a == 9.0) // false: 실수는 ==로 비교하면 안됨
}

10에서 0.1을 10번 빼면 9.0이 나와야하는데 9.000000000000004가 나왔습니다. 이처럼 실수형 값을 연산하면 오차가 발생합니다. 따라서 실수형 값을 연산한 뒤 a == 9.0과 같이 등호로 비교하면 잘못된 결과가 나오므로 주의합니다.

실수를 비교하려면 다음과 같이 연산한 값과 비교할 값의 차이를 구한 뒤 머신 입실론보다 작거나 같은지 확인하면 됩니다.

package main

import "fmt"
import "math"

func main() {
	var a float64 = 10.0

	for i := 0; i < 10; i++ {
		a = a - 0.1
	}

	fmt.Println(a) // 9.000000000000004

	const epsilon = 1e-14                   // Go 언어 머신 입실론
	fmt.Println(math.Abs(a-9.0) <= epsilon) // true: 연산한 값과 비교할 값의 차이를 구한 뒤
	                                        // 머신 입실론보다 작거나 같은지 비교
}

어떤 실수를 가장 가까운 부동소수점 수로 반올림하였을 때 상대 오차는 항상 머신 입실론 이하입니다(Go 언어의 머신 입실론 값은 1e-14입니다). 따라서 연산한 값과 비교할 값의 차이가 머신 입실론보다 작거나 같다면 두 실수는 같은 값이라 할 수 있습니다.

연산한 값과 비교할 값의 차이를 구할 때는 음수가 나올 수도 있으므로 Math 패키지의 Abs 함수를 사용하여 절댓값으로 만듭니다.


저작권 안내

이 웹사이트에 게시된 모든 글의 무단 복제 및 도용을 금지합니다.
  • 블로그, 게시판 등에 퍼가는 것을 금지합니다.
  • 비공개 포스트에 퍼가는 것을 금지합니다.
  • 글 내용, 그림을 발췌 및 요약하는 것을 금지합니다.
  • 링크 및 SNS 공유는 허용합니다.

Published

2015-06-01