영어사전에서 영어단어 검색 속도 (3)

rgbi3307의 이미지

저는 앞글에서 우리가 일상에서 사용하는 문장의 개수를 다음과 같이 계산했습니다.

(1) 사전에 등재되어 있는 단어(어휘)의 개수 --> 30만개
(2) 문장 개수 --> 단어의 조합 순열 --> 30만!(팩토리얼)

30만!(팩토리얼)은 엄청나게 큰 천문학적인 수입니다.
일단, 간단하게 30!(팩토리얼)을 아래와 같이 C언어로 코딩하여 실행해 봤습니다.

main()
{
	unsigned int nfact = 1;
	for (i = 1; i <= 30; i++) nfact *= i;
	printf ("nfact=%u", nfact);
}

결과는 nfact=1,409,286,144 (14억..)입니다.
32비트로 표현할 수 있는 수의 크기가 42억 정도 됩니다. 30!(팩토리얼)이 14억 이니까
30만!(팩토리얼)은 아마 현존하는 컴퓨터로는 표현할 수 없는 엄청난 크기의 수입니다.

그럼 우리는 30만!(팩토리얼)이나 되는 문장들을 어떻게 표현하는 걸까요?
우리의 두뇌 세포속에 30만!(팩토리얼)의 문장들이 모두 저장되어 있는 걸까요?
저는 언어학자도 아니고 언어에 대해서 깊이 있는 지식은 없습니다만,
우리가 문장들을 표현하는 것을 쉬운 방식으로 생각해 보기로 했습니다.
아래와 같이 크게 2가지로 분류해 봤습니다.

(1) 오감(시각, 청각, 후각, 미각, 촉각)에 의한 언어(문장) 표현
(2) 논리적인 생각에 의한 언어(문장) 표현

한번 더 언급하지만, 저는 언어학자가 아니기 때문에 위의 2가지 분류를 언어학적으로
생각한 것은 아닙니다.
단지, 컴퓨터를 전공한 공학도의 입장에서 우리가 사용하는 문장을
컴퓨터로 번역하기 위해서는 어떠한 자료구조와 알고리즘을 사용하는 것이 적절한가를
고민해서 도출해낸 분류입니다.

위의 2가지 분류를 다시 생각해 보면,

(1) 오감에 의한 문장표현 --> 경험에 의해 축적된 어휘를 순간적으로 표현
(2) 논리적인 문장표현 --> 학습에 의해 축적된 어휘를 논리적인 문법 체계에 맞도록 조합하여 표현

(1) 오감에 의한 문장표현 --> 속도가 빠르다
(2) 논리적인 문장표현 --> 속도가 다소 느리다

**오늘은 할일이 많이 밀려있어, 나머지는 다음에 또 정리하여 올려 보겠습니다.
**즐거운 통신시간 되세요(^^)

from. 알지비(rgbi3307(at)nate.com) on the www.kernel.bz

pastime의 이미지

overflow를 고려하지 않으셨군요..;;

32비트로는 13!도 저장할 수 없으며 64비트로도 20! 정도밖에 저장할 수 없습니다.

rgbi3307의 이미지

overflow가 났었군요. 그래서 리눅스에서 데이터 타입을 double(64비트, 8바이트)형으로
아래 코드를 작성하여 실행해 봤습니다.

main ()
{
        int i;
        double nfact = 1;  //64비트(8바이트)
 
        for (i = 1; i <= 30; i++) nfact *= i;
        printf ("nfact=%f\n", nfact);
 
        nfact = 1;
        for (i = 1; i <= 100; i++) nfact *= i;
        printf ("nfact=%f\n", nfact);
}

30팩토리얼: nfact=265252859812191032188804700045312.000000
100팩토리얼: nfact=93326215443944102188325606108575267240944254854960571509166910400407995064242937148632694030450512898042989296944474898258737204311236641477561877016501813248.000000

100 팩토리얼 까지는 계산하는것 같습니다.

From:
*알지비 (메일: rgbi3307(at)nate.com)
*커널연구회(http://www.kernel.bz/) 내용물들을 만들고 있음.
*((공부해서 남을 주려면 남보다 더많이 연구해야함.))

pastime의 이미지

double도 마찬가지로 유효숫자의 범위를 넘어서는 수에 대해서는 overflow가 발생합니다.
이런 큰 숫자를 올바로 다루려면 gmp와 같은 라이브러리를 이용해야 할 것입니다.

(아래 코드는 출력 과정에서 memory leak이 있습니다.. ;;)

#include <stdio.h>
#include <gmp.h>
 
int main(void)
{
	unsigned long i;
	mpz_t nfact;
 
	mpz_init_set_ui(nfact, 1);
	for (i = 1; i <= 30; i++)
		mpz_mul_ui(nfact, nfact, i);
	printf("nfact=%s\n", mpz_get_str(NULL, 10, nfact));
 
	mpz_set_ui(nfact, 1);
	for (i = 1; i <= 100; i++)
		mpz_mul_ui(nfact, nfact, i);
	printf("nfact=%s\n", mpz_get_str(NULL, 10, nfact));
 
	mpz_clear(nfact);
	return 0;
}

nfact=265252859812191058636308480000000
nfact=93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000

kaeri17의 이미지

30만!의 자리수는

import std.stdio;
import std.math;
int main()
{
    double a = 0;
    for(int i=1;i<30_0000;i++)
    {
        a += log10(i);
    }
    writeln(a);
    return 0;
}

로 구해보니 1.51285e+06 이네요. 즉, 151만자리 입니다.
yielding의 이미지

솔직히 이 글타래는 30!을 구하는게 재밋네요.

직접 구해서 저장한 파일의 크기가 1,512,854 byte 입니다. 코드는 루비로 단순 무식하게

def fact(n)
res = 1; 1.upto(n) {|i| res *= i }
res
end

Life rushes on, we are distracted

kaeri17의 이미지

간단합니다. 글쓴분 말씀대로 생각하면 C언어에서도 가능한 모든 literal의 조합을 컴퓨터가 다 가지고 있다고 해야 할 것 같네요. 근데 컴파일러는 그것을 알맞는 syntax tree와 symantic 해석을 통해 컴파일 하게 됩니다. 언어학에서도 언어의 분석을 똑같이 syntax tree를 통해 하게 됩니다. 다만 일반언어는 문법의 모호성으로 인해 syntax tree가 여러가지가 있고 어느 것을 선택할지가 문맥에 의존해야 하는 언어이기 때문에 컴파일러와는 달리 분석이 힘든겁니다. 이 작업을 한게 컴퓨터언어학에서도 유명한 언어학자 촘스키입니다.

일반 언어 번역기도 컴파일러와 비슷한 과정을 가집니다. 주어진 언어에 맞는 syntax tree를 그리고 symactic을 알아내어 같은 뜻을 다른 언어로 변역하는 과정이죠. 한번 알아 보시면 좋을 것 같습니다.

실제로 사람이 어떻게 언어를 인식하는 지는 아직 미지의 분야이고 몇년전까지만 해도 인지과학이라는 분야 자체가 없었기 때문에 과학이라기 보다는 철학에 가까웠습니다. 아직도 밝혀진게 별로 없는것은 마찬가지인것 같습니다.

나그네나그네의 이미지

'사람의 문장 인지 과정을 흉내내어 NLP를 구현하면 어떨까'는 이쪽 분야 대학원생이라면 적어도 한번은 생각해 보았을 주제라고 봅니다.
물론 언어학 쪽이 아닌 전산학 쪽 대학원생들 말이죠.

진심으로 NLP에 관심이 있으시다면

지금까지 똑똑한 사람들이 컴퓨터가 말귀를 알아먹도록 하기 위해 해왔던 것이 무엇인지를 먼저 알아보시는 것이 좋을듯 합니다..

수박 겉핥기면 죽도 밥도 안됩니다.