🔥 숫자 상수

252자
3분

숫자 상수는 높은 정밀도의 을 나타냅니다. 상수를 선언할 때 타입을 지정하지 않으면 컨텍스트에 맞는 타입이 자동으로 부여되죠. 아래 코드에서 Big이라는 상수를 만들어 봅시다. 이 상수는 1을 왼쪽으로 100번 시프트한 값, 즉 2의 100제곱을 나타낼 거예요. 엄청나게 큰 수겠죠?

go
const (
    // 1을 왼쪽으로 100번 시프트하여 엄청나게 큰 수를 만듭니다.
    // 바이너리로 표현하면 1 뒤에 0이 100개 붙은 형태입니다.
    Big = 1 << 100
    // 다시 오른쪽으로 99번 시프트하면 1<<1, 즉 2가 됩니다.
    Small = Big >> 99
)
 
go
const (
    // 1을 왼쪽으로 100번 시프트하여 엄청나게 큰 수를 만듭니다.
    // 바이너리로 표현하면 1 뒤에 0이 100개 붙은 형태입니다.
    Big = 1 << 100
    // 다시 오른쪽으로 99번 시프트하면 1<<1, 즉 2가 됩니다.
    Small = Big >> 99
)
 

Big은 1을 왼쪽으로 100번 시프트한 값이에요. 바이너리로 표현하면 1 뒤에 0이 100개 붙은 형태가 됩니다. 그리고 SmallBig을 다시 오른쪽으로 99번 시프트한 값이에요. 따라서 Small의 값은 2가 됩니다.

이제 needIntneedFloat 함수를 정의해 볼까요? needInt 함수는 인자로 받은 int 타입 변수에 10을 곱하고 1을 더해서 반환합니다. needFloat 함수는 인자로 받은 float64 타입 변수에 0.1을 곱해서 반환하죠.

go
func needInt(x int) int { return x*10 + 1 }
func needFloat(x float64) float64 {
    return x * 0.1
}
 
go
func needInt(x int) int { return x*10 + 1 }
func needFloat(x float64) float64 {
    return x * 0.1
}
 

자, 이제 main 함수에서 needIntneedFloat 함수를 호출해 봅시다. Small을 인자로 넘기면 어떤 결과가 나올까요?

go
func main() {
    fmt.Println(needInt(Small))
    fmt.Println(needFloat(Small))
    fmt.Println(needFloat(Big))
}
 
go
func main() {
    fmt.Println(needInt(Small))
    fmt.Println(needFloat(Small))
    fmt.Println(needFloat(Big))
}
 

needInt(Small)은 21을 출력할 거예요. needFloat(Small)은 0.2를 출력하겠죠. 그런데 needFloat(Big)은 어떤 결과가 나올까요? 실행해 보면 오버플로우가 발생한다는 걸 알 수 있어요.

text
21
0.2
+Inf
text
21
0.2
+Inf

Big은 너무 큰 숫자라서 float64 타입으로 표현할 수 없습니다. 따라서 오버플로우가 발생하고 +Inf(양의 무한대)가 출력되는 거죠.

참고로 int 타입은 최대 64비트 정수까지 저장할 수 있어요. 하지만 플랫폼에 따라서는 더 작은 범위만 표현할 수도 있습니다. 따라서 아주 큰 숫자를 다룰 때는 주의해야 해요.

YouTube 영상

채널 보기
곱타입 - 튜플과 레코드(구조체) | 프로그래머를 위한 카테고리 이론
관계로 정의하는 곱과 쌍대곱의 기초 | 프로그래머를 위한 카테고리 이론
모듈과 프로바이더 | NestJS 가이드
Haskell로 배우는 Writer 모나드 | 클라이슬리 카테고리 마지막편 | 프로그래머를 위한 카테고리 이론
합타입 - Either, Maybe, List | 프로그래머를 위한 카테고리 이론
모듈을 공유하는 방법은? | NestJS 가이드
함수 합성을 추상화 할 수 있을까? | 클라이슬리 카테고리 2편 | 프로그래머를 위한 카테고리 이론
NestJS 프로바이더와 @Injectable 데코레이터 | NestJS 가이드