🔥 숫자 상수

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 영상

채널 보기
투영과 예측, 그리고 선형 결합 | 선형대수학
행렬의 가장 중요한 연산 - 행렬 곱셈 | 선형대수학
AI는 왜 수백 차원의 벡터를 사용할까? 고차원 공간과 행렬 | 선형대수학
숫자 하나가 AI 모델의 운명을 바꾼다? | 선형대수학
우리가 매일 쓰는 맞춤법 검사기와 라우터 속에 숨겨진 알고리즘은? | Trie 자료구조 이야기
트라이(Trie)를 이용한 자동 완성 알고리즘 | Trie 자료구조 이야기
인공지능은 세상을 어떻게 숫자로 읽는가? - 이미지, 소리 그리고 텍스트가 행렬이 되는 원리 | 선형대수학
스칼라 곱셈과 내적의 기하학적 의미 | 선형대수학