기술자료
DBMS, DB 구축 절차, 빅데이터 기술 칼럼, 사례연구 및 세미나 자료를 소개합니다.
data-p로 열어가는 새로운 세상 구글, 구골과 프로그래밍 세계 최대 인터넷 검색엔진 중 하나인 구글(Google)은 수학 용어인 ‘구골(Googol)’에서 유래했다. 10의 100제곱을 의미하는 구골과 구골플렉스는 어떻게 탄생했고 그 크기는 얼마나 큰 것일까 또한 이처럼 어마어마한 크기의 수를 프로그래밍 언어가 과연 지원할 수 있을까 이 글에서는 그간 당연하게 여겨지던 프로그래밍 언어에서 수의 크기란 제약에 대해 고찰해본다. 이미 잘 알려져 있듯 구글이란 이름은 아주 큰 수를 뜻하는 구골에서 유래했다. 어떻게 구골이 구글이 됐는지에 대해서 크게 두 가지 설이 존재하는데 이와 관련된 사실 관계를 따져보면 감춰진 진실에 도달할 수 있을 것이다. 구글과 얽힌 가설 중 가장 널리 알려진 이야기는 구글의 첫 투자자인 벡톨샤임이 구골을 구글로 잘못 적었다는 것이다. 구글 검색엔진을 개발한 세르게이 브린과 래리 페이지는 기술에 대한 확신이 있었지만 당시 대학생이던 그들에게는 창업자금이 없었다. 이를 구하기 위해 이 둘은 실리콘밸리의 팔토 알토에 있는 지도교수의 친구인 엔젠 투자자 벡톨샤임과 만났다. 당시 바쁜 일이 있던 벡톨샤임은 그들에게 구체적인 사업 설명을 듣는 대신 10만 달러 수표를 줬는데, 이 수표에 구골을 구글(google inc)이라고 잘못 적었고, 이 수표를 사용하기 위해 회사명을 구글로 정했다는 이야기가 있다. 구글의 이름이 유래된 구골은 과연 무엇일까 구골은 10의 100승을 뜻하며, 이를 더 쉽게 표현하면 1을 적고 그 뒤에 0을 100개 적어야 한다. 이렇게 큰 수도 우리가 수학시간에 배웠던 팩토리얼과 관련지으면 생각만큼 큰 수는 아니다. 한 계산에 따르면 구골은 70!(팩토리얼) 값 수준이란 점만으로 팩토리얼이 예상보다 더 큰 수를 만드는 개념적인 도구임을 재차 깨닫게 된다. 만일 누가 장난삼아 1000!를 계산한다면 그 크기는 실로 우리의 생각보다 훨씬 엄청날 것이다.
<리스트 1> 팩토리얼 함수 factorial 함수를 활용해 69!와 70!을 계산한 결과는 <리스트 2>와 같다. 이를 통해 구골의 값은 69!보다 크고, 70!보다 작다는 것이 쉽게 증명됐다.
<리스트 2> 69!와 70! 계산 만일 구골을 2진법으로 표현하면 몇 자리나 차지할까 어떤 이의 계산에 따르면 구골의 크기는 2의 333 승에 가깝다.
<리스트 3> 구골과 2의 333승 값 비교 “구골을 2진법으로 표현하면 몇 개의 자리수가 필요할까”란 질문은 “디지털 기기로 표현하면 몇 개의 비트가 필요한가”란 질문과 같다. 그러므로 디지털 기기에 333개의 비트만 있다면 구골을 표현할 수 있다. 이와 같은 맥락에서 CPU가 몇 비트까지 발전하면 구골과 같은 수를 소프트웨어적인 도움 없이 하드웨어 수준에서 계산할 수 있을까 따지고 보면 구골은 그렇게 큰 수는 아니다. 실제 프로그래밍에서 구골의 크기도 부족한 경우는 많다. 바둑에서의 인공지능과 사람의 대결을 예로 들면 인공지능 프로그램은 바둑판의 여러 가지 경우의 수를 모두 계산해야 한다. 바둑판에는 가로로 19줄, 세로로 19줄이 있으므로 총 361곳에 바둑돌을 둘 수 있다.
<리스트 4> 바둑에서 돌을 놓을 수 있는 경우의 수 data-p 언어는 사칙연산도 분수로 정확하게 계산한다. 만약 소수점 형태의 수로 알고 싶다면 <리스트 5>처럼 math.decimal이란 함수를 이용하면 된다. 이처럼 구골은 바둑에서의 경우의 수를 표현하기에 턱 없이 부족하다. 쓰일 것 같지 않던 구골처럼 큰 수도 지금 우리들에게 있어 그리 큰 수만은 아닌 것이다.
<리스트 5> 소수점 형태로 <리스트 4> 출력 앞서 언급했듯 에드워드 캐스너는 구골뿐 아니라 구골플렉스란 수의 이름도 만들었다. 구골플렉스는 원래 1을 쓰고 그 뒤에 0을 지칠 때까지 써야 하는 수를 의미하지만 사람들마다 다른 값이 되기 때문에 후에 구골플렉스의 크기는 1 뒤에 0의 개수를 구골 크기만큼 붙인 수로 수정됐다. 말하자면 다음 수식이 바로 구골플렉스다.
<리스트 6> 우주에서 가장 큰 것을 가장 작은 것으로 나눈 값 과거 윈도우 운영체제가 나오기 이전에 DOS란 운영체제가 사용됐다. 당시 대부분의 CPU는 16비트였고, C 언어에서 표현 가능한 최대 크기는 2의 16승인 65,536이었다. 메모리의 주소도 이 범위 내에서 다 해결됐고, 데이터를 읽고 쓸 때에도 16비트만 사용해 전혀 문제가 없었다. 시간이 흘러 32비트 CPU가 등장하면서 컴퓨터로 232(2의 32승)을 표현할 수 있게 됐다. 사실 대부분의 프로그래밍 언어에서 이 정도의 크기면 충분하다고 생각했고 64비트 CPU가 등장한 지금도 대부분의 프로그램은 32비트로 개발되고 있다.data-p로 열어가는 새로운 세상 : 구글, 구골과 프로그래밍
구글 이름의 유래
또 다른 설은 검색엔진 도메인을 등록하는 과정에서 구골이 아닌 구글이 사명이 됐다는 것이다. 래리 페이지는 첫 개발한 검색엔진을 BackRub이라고 불렀다. 당시 래리 페이지의 사무실은 스탠포트대학교의 Gates Computer Science Building 건물 302호였고, 그 곳을 샨 앤더슨 등의 다른 대학생들과 함께 사용했다. 당시 래리 페이지와 샨 엔더슨은 BackRub의 새로운 이름을 짓기 위해 토론을 거듭했으며, 샨 엔더슨이 제안한 구골플렉스란 이름이 너무 길다고 생각한 래리 페이지는 구골로 이름을 줄이자고 말했다. 괜찮은 생각이라 여긴 샨 레이지는 구골이란 도메인을 검색했는데 이 과정에서 googol의 스펠링을 google로 잘못 생각했다. 때마침 google 도메인은 등록이 가능했고, 몇 시간 뒤에 래리 페이지는 자신과 동료인 세르게이 브린 이름으로 google. com을 등록했다.
이 두 이야기는 모두 그럴싸하지만 벡톨샤임이 투자한 시기는 1998년이고, 구글 도메인은 1997년 9월 15일 첫 등록됐다. 이로 인해 많은 이들은 후자의 이야기가 더 사실에 가깝다고 보고 있다.
구골
10,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,
000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000
구골이란 이름의 탄생 과정은 이러하다. 1938년 미국 수학자인 에드워드 캐스너가 당시 9살이었던 조카에게 가장 큰 수가 무엇이냐고 물었고, 조카는 ‘googol’이라고 답했다. 그 조카가 왜 구골이라고 답했는지 누구도 알 수 없지만 몇 년 뒤에 에드워드 캐스너는 1940년에 출간된 란 책에 구골을 처음 소개했고 이 이름이 오늘날까지 사용되고 있다. 추후 구골플렉스란 이름도 그에 의해 만들어졌다.
이렇게 큰 수는 우리가 일생생활에서 사용할 일이 없을 것만 같지만 좀더 세상을 넓게 바라보면 우주에 퍼져 있는 원자의 개수나 원자를 구성하는 소립자를 수로 표현하는 데 구골은 유용하게 쓰인다.
구골과 70!
구골이 70!과 크기가 비슷하다는 점은 어떻게 확인할 수 있을까 사람이 계산하기에는 한계가 있기 때문에 결국 컴퓨터 프로그래밍을 이용하는 방법이 유일할 것이다. 컴퓨터가 이 세상에 없다면 어떤 수학자가 몇 개월간 70!의 값을 계산하고 논문이나 책으로 발표했을지도 모른다. 본론으로 돌아와 구골의 값이 70!의 크기와 비슷하다는 것은 다음과 같은 식이 성립함을 의미한다.
69! < 구골 < 70! ①식
70!-구골 < 구골-69! ②식
data-p는 수의 크기에 제한이 없어 이러한 큰 수를 계산하는 데 유용하기 때문에 이를 data-p 언어로 표현하면, 자연수 n을 입력받아 n!을 계산하는 함수를 factorial 함수라고 할 때 이 함수를 통해 ①식을 표현하면 다음과 같다. ②식의 경우 독자들이 스스로 표현해보길 바란다.
10**100 > factorial(69)
10**100 < factorial(70)
data-p 언어로 factorial 함수를 만드는 방법에는 여러 가지가 있다. factorial 함수를 재귀적으로나 순차적 함수로 구성할 수도 있지만 여기서는 이해를 돕기 위해 순차적인 함수로 구현했다(<리스트 1> 참조). data-p 언어와 관련된 자세한 정보는 2012년 11월호의 data-p 강좌를 참고하자.
factorial = func(n, (
sum = 1,
for(i=1, i<=n, i++, sum *= i)
));/* 사용법
factorial(10);
*/
>> g = 10 * 100;
100000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000>> factorial(69);
171122452428141311372468338881272839092270544893520369393648040923257279
754140647424000000000000000>> factorial(70);
119785716699698917960727837216890987364589381425464258575553628646280095
82789845319680000000000000000>> g > factorial(69); // 구골과 69!의 크기 비교
#true>> g < factorial(70); // 구골과 70!의 크기 비교
#true
이진법으로 구골 표현
10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000(2)
이를 2진수로는 다음과 같이 두 가지 방식으로 표현할 수 있다.
2**333 ①식
1 << 333 ②식
①식에서는 2의 333승을 그대로 표현했다면 ②식은 이진수 1을 좌측으로 333번 이동시킨다. ①과 ②식의 값은 같은데, 이해되지 않는다면 디지털과 관련된 기초 이론을 살펴보길 바란다. <리스트 3>처럼 구골의 값이 2**332보다 크고 2**333보다 작음을 data-p 언어로 확인할 수 있다.
2 ** 333 > 2 ** 100
2 ** 332 < 2 ** 100
>> g = 10 ** 100;
1000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000>> t = 2 ** 333;
1749800579826409539498001781694097092282535544714569949140616485127962399
3595007385788105416184430592>> t2 = 2 ** 332;
8749002899132047697490008908470485461412677723572849745703082425639811996
797503692894052708092215296>> t > g; // 2의 333승과 구골의 크기의 비교
#true>> t2 < g; // 2의 332승과 구골의 크기의 비교
#true
구골 계산이 가능한 미래의 CPU
최근 CPU는 32비트와 64비트를 모두 지원하며, 언젠가는 64비트를 넘어 128, 256, 512비트 CPU가 등장할지도 모른다. 그 때가 되면 구골처럼 큰 수도 하드웨어 상에서 즉시 계산할 수 있을 것이다. 물리학 등의 분야에서 수퍼컴퓨터로만 계산이 가능한 것들도 고등학교 수업에서 실습문제로 다루고 지금보다 더 작은 PC에서 이를 계산할지도 모르는 일이다. 예컨대 우주에 퍼진 각 물체들의 이동경로의 수라든지 체스나 바둑에서 돌을 둘 수 있는 경우의 수 등이 그것이다.
구골은 그렇게 큰 수가 아니다
바둑은 두 사람이 돌 하나하나를 각 자리에 채워나간다. 이를 단순화하기 위해서 자신의 돌로 상대의 돌을 빈틈없이 에워싸서 상대의 돌을 없애 사석이 발생한 경우는 제외하면, 첫 돌은 361곳 어디든 둘 수 있고 두 번째 돌은 첫 돌이 위치한 곳을 제외한 360곳 어디든 둘 수 있다. 이를 경우의 수로 표현하면 다음과 같다
. 361 * 360 * 359 * 358 * 357 * … * 3 * 2 * 1
위 경우의 수는 361!과 같은데 구골보다도 더 크다. 그렇다면 바둑판에서 돌을 놓을 수 있는 경우의 수는 구골보다 얼마나 클까 <리스트 1>에서 만든 factorial 함수를 그대로 사용해 이를 계산하면 결과는 <리스트 4>와 같다.
factorial(361) / (10**100)
>> factorial(361); // 바둑의 경우의 수
14379232588848906548323625114998633547549075386447558761272827652992277955
34389618856841908003141196071413794434890585968383968233304321607713808837
05655787966919248618270978003589902110057945010733305079262777172275041226
80867752813688505752654181204350215062346630264344267363262709276464330255
77722695595343233942204301825548143785112222186834487969871267194205609533
30641393571063519720072147337873382698030853510431742036536737798872175655
13450041291061650506154496265581102824241428406627054585562310156375289289
99248573883166476871652120015362189137337137682618614562954409007743375894
90771443991729993713368072845900003449642033706644085333700128428641265439
44950507739545600000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000>> factorial(361) / (10**100); // 바둑의 경우의 수와 구골 크기 비교
35105548312619400752743225378414632684445984830194235257013739387188178601
91380905412211689460793935721225084069557094649374922444590628925082541106
09511201091111446821950629891576909448383654811360608103668889580749612370
13837287142794203497690872080933142242057202793809246492340598819492993788
51862049793318442241709721253779647912871636198326386645193523423353538899
67386214773104296191582390961604938227614388453202495206388520016777772595
54321389870755982681041250648391364316995674820866832484282983780213108618
14571713581949406424931933631255344573576996295455601960337912616560976305
92703720682934554964277521596435555296977621354111536459228829171487464451
78101825536/244140625
>> math.decimal(factorial(361) / (10**100));
14379232588848906548323625114998633547549075386447558761272827652992277955
34389618856841908003141196071413794434890585968383968233304321607713808837
05655787966919248618270978003589902110057945010733305079262777172275041226
80867752813688505752654181204350215062346630264344267363262709276464330255
77722695595343233942204301825548143785112222186834487969871267194205609533
30641393571063519720072147337873382698030853510431742036536737798872175655
13450041291061650506154496265581102824241428406627054585562310156375289289
99248573883166476871652120015362189137337137682618614562954409007743375894
90771443991729993713368072845900003449642033706644085333700128428641265439
449.505077395456
구골플렉스
googolplex = 10googol
위의 구골플렉스를 data-p 언어로 표현하면 다음과 같다.
googolplex = 10**(10**100)
그러나 이 식을 실제로 계산하지는 말자. 왜냐하면 data-p 언어를 포함해 어떤 프로그래밍 언어도 이 크기를 계산할 수 없기 때문이다. 만약 위 식을 계산하려고 시도해도 data-p 인터프리터는 끝없이 계산만 하고 답을 내지 못할 것이다. 그렇다면 구골플렉스는 얼마나 큰 수일까 구골플렉스의 크기는 우주에서 가장 작은 크기 단위인 플랑크 길이(Planck Length)보다 더 많은 자릿수를 갖고 있다. 1플랑크 길이는 1.6162×10-35m이며, 이는 어떠한 측정 장비로도 측정할 수 없을 정도로 작은 크기로 알려져 있으며, 우주의 크기는 현재로서 3×1080m3로 여겨지고 있다. 그렇다면 이 우주에 몇 개의 플랑크 부피가 존재하는지를 계산해보자.
3×1080 / (1.6162×10-35)3
<리스트 6>은 위 식을 data-p 언어로 표현한 것으로, 계산해보면 약 7.1×10184개의 플랑크 부피가 존재한다. 그러나 이 수는 구골플렉스보다도 훨씬 적은 수다.
3*(10**80) / (1.6162*10**-35)**3
>> num = 3*(10**80) / (1.6162*10**-35)**3;
37500000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000/527709995441>> math.decimal(num);
71061758018552907480591054185091463170741468979951786169676892891089717250
91057767884126440248872375157963954340750919708710168372798805426445877355
3026375524904295954290586222756405202.75615644836239079814>> math.float(num);
7.10617580186e+184f
프로그래밍 언어가 다룰 수 있는 수의 범위
그러나 앞서 소개한 바둑을 비롯해 구골, 구골플렉스의 경우만 봐도 32비트나 64비트 기반의 전통적인 프로그래밍 언어로 이를 계산한다는 것은 쉽지 않다. 프로그래밍 언어가 우리의 사고를 바로 표현하지 못한다면 이는 우리에게 제약사항이 될 뿐이다. 이런 이유로 프로그래밍 언어에 존재하는 수의 제약을 없애는 방향으로 프로그래밍 언어는 발전해야 할 것이다.