Go 언어 big 사용법

고(Golang)에서 큰 숫자를 처리하는 방법.

golang

4/11/2024

컴퓨터 연산에 사용하는 일반적인 숫자 타입 범위는 다음과 같습니다.


컴퓨팅 연산 숫자 타입 범위

타입최소값최대값용량(비트)용량(바이트)
int8-1281278-bit1 byte
uint802558-bit1 byte
int16-32,76832,76716-bit2 bytes
uint16065,53516-bit2 bytes
int32-2,147,483,6482,147,483,64732-bit4 bytes
uint3204,294,967,29532-bit4 bytes
int64-9,223,372,036,854,775,8089,223,372,036,854,775,80764-bit8 bytes
uint64018,446,744,073,709,551,61564-bit8 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를 썼습니다. 그러면 doubleXdoubleY에는 각각 0이 할당됩니다.

0이 들어 있는 두 변수에 big.Int 타입의 리시버 함수(receiver function)로 더하기와 곱하기를 수행합니다.

doubleXAdd 함수로 800경 더하기 800경을 했습니다.

doubleYMul 함수로 600경 곱하기 2를 했습니다. 이때 2조차도 일반 int를 넣으면 안 되고 big.NewInt(2)에서 반환되는 2를 넣어야 합니다.

마지막으로 zbig.Int 0을 초기화한 후 Add 함수로 doubleXdoubleY의 합을 구해 할당합니다. 최종값 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)

참고: 위키백과