Go 언어 big 사용법
고(Golang)에서 큰 숫자를 처리하는 방법.
golang4/11/2024
컴퓨터 연산에 사용하는 일반적인 숫자 타입 범위는 다음과 같습니다.
컴퓨팅 연산 숫자 타입 범위
타입 | 최소값 | 최대값 | 용량(비트) | 용량(바이트) |
---|---|---|---|---|
int8 | -128 | 127 | 8-bit | 1 byte |
uint8 | 0 | 255 | 8-bit | 1 byte |
int16 | -32,768 | 32,767 | 16-bit | 2 bytes |
uint16 | 0 | 65,535 | 16-bit | 2 bytes |
int32 | -2,147,483,648 | 2,147,483,647 | 32-bit | 4 bytes |
uint32 | 0 | 4,294,967,295 | 32-bit | 4 bytes |
int64 | -9,223,372,036,854,775,808 | 9,223,372,036,854,775,807 | 64-bit | 8 bytes |
uint64 | 0 | 18,446,744,073,709,551,615 | 64-bit | 8 bytes |
읽어 보자면 int32
최대값은 21억 4748만 3647 이고 uint32
최대값은 42억 9496만 7295 입니다.
int64
최대값은 922경 3372조 368억 5477만 5807, uint64
최대값은 1844경 6744조 737억 955만 1615 입니다. (영어로는 18.44... quintillion, 영어 이름은 이 문서 맨아래를 참조하세요.)
이 숫자도 어마어마하지만 이보다 더 높은 값의 숫자를 다루고 싶다면? Go에서는 big
라이브러리를 사용합니다.
Go에서 큰 숫자 연산하기
만약 uint64
로 1600경 + 1200경 = 2800경의 연산을 한다면 어떻게 될까요?
var x uint64 = 16000000000000000000
var y uint64 = 12000000000000000000
var z = x + y
fmt.Println(x)
fmt.Println(y)
fmt.Println(z)
16000000000000000000
12000000000000000000
9553255926290448384
수치가 uint64
의 한계(1844경...)를 넘어 버려 0으로 돌아가서 다시 시작했습니다. 래핑(wrapping)된 거죠.
그럼 big
라이브러리를 써 보겠습니다.
var x int64 = 8000000000000000000
var y int64 = 6000000000000000000
var xx = big.NewInt(x)
var yy = big.NewInt(y)
fmt.Println(xx)
fmt.Println(yy)
8000000000000000000
6000000000000000000
큰 숫자는 big.NewInt
함수에 넣어 big.Int
타입으로 변환합니다.
이때 big.Int
타입을 리터럴 값으로 선언할 수는 없습니다. 반드시 big.NewInt
함수를 이용해야 합니다.
(다만 new(big.Int)
로 초기값 0을 설정할 수는 있습니다. 이건 바로 다음 코드에서 살펴보겠습니다.)
big.NewInt
함수에는 uint64
타입의 값을 넣을 수도 없기 때문에, 일단 수치를 절반으로 줄여 int64
타입으로 만들었습니다.
그럼 원래 계산하고자 했던 1600경과 1200경을 만든 후에, z
에 1600경 + 1200경 = 2800경 결과를 산출해 보겠습니다.
var x int64 = 8000000000000000000
var y int64 = 6000000000000000000
var xx = big.NewInt(x) // 큰 수 800경
var yy = big.NewInt(y) // 큰 수 600경
var doubleX = new(big.Int)
var doubleY = new(big.Int)
doubleX.Add(xx, xx) // doubleX = 800경 + 800경
doubleY.Mul(yy, big.NewInt(2)) // doubleY = 600경 * 2
fmt.Println(doubleX)
fmt.Println(doubleY)
var z = new(big.Int).Add(doubleX, doubleY)
fmt.Println(z)
16000000000000000000
12000000000000000000
28000000000000000000
우선 xx
에는 800경, yy
에는 600경이 big.Int
타입으로 할당되었습니다.
그다음에 1600경을 할당할 doubleX
변수와 1200경을 할당할 doubleY
변수를 선언합니다. 선언할 때 new(big.Int)
statement를 썼습니다. 그러면 doubleX
와 doubleY
에는 각각 0이 할당됩니다.
0이 들어 있는 두 변수에 big.Int
타입의 리시버 함수(receiver function)로 더하기와 곱하기를 수행합니다.
doubleX
는 Add
함수로 800경 더하기 800경을 했습니다.
doubleY
는 Mul
함수로 600경 곱하기 2를 했습니다. 이때 2조차도 일반 int
를 넣으면 안 되고 big.NewInt(2)
에서 반환되는 2를 넣어야 합니다.
마지막으로 z
에 big.Int
0을 초기화한 후 Add
함수로 doubleX
와 doubleY
의 합을 구해 할당합니다. 최종값 2800경이 출력되었습니다.
스트링으로 큰 수를 직접 할당하기
하지만 큰 수 2800경을 처음부터 변수에 할당할 수는 없을까요? string
타입으로 할당할 수 있습니다.
var z = new(big.Int)
z.SetString("28000000000000000000", 10)
fmt.Println(z)
28000000000000000000
SetString
함수의 두 번째 인자 10
은 10진수를 의미합니다.
상수의 연산과 표현
Go는 const
로 받아들이는 상수값 또는 리터럴 값이 큰 수일 때 암묵적으로 big
큰 수로 변환해 연산하지만, 이를 표현하지는 않습니다.
const d = 28000000000000000000
const e = d / 1000000000000000
fmt.Print(e)
28000
위 코드에서 d
에 큰 수 2800경을 할당했습니다. 타입에 관해 아무 지정을 하지 않아도 Go가 암묵적으로 big
을 이용해 연산을 수행합니다.
그런데 d
를 곧바로 출력할 수는 없습니다. 출력하려면 big
을 이용해야 합니다.
한편 큰 수 d
를 1000조로 나눈 값은 더 이상 큰 수가 아니므로, e
를 출력하면 int
28000이 출력됩니다.
참고: 큰 숫자 영어 이름
Million(100만): 1,000,000 (6 zeros)
Billion(10억): 1,000,000,000 (9 zeros)
Trillion(1조): 1,000,000,000,000 (12 zeros)
Quadrillion(1000조): 1,000,000,000,000,000 (15 zeros)
Quintillion(100경): 1,000,000,000,000,000,000 (18 zeros)
Sextillion(10해): 1,000,000,000,000,000,000,000 (21 zeros)
Septillion(1자): 1,000,000,000,000,000,000,000,000 (24 zeros)
Octillion(1000자): 1,000,000,000,000,000,000,000,000,000 (27 zeros)
Nonillion(100양): 1,000,000,000,000,000,000,000,000,000,000 (30 zeros)
Decillion(10구): 1,000,000,000,000,000,000,000,000,000,000,000 (33 zeros)