« Previous : 1 : ... 154 : 155 : 156 : 157 : 158 : 159 : 160 : 161 : 162 : ... 221 : Next »

1. C/C++이 빌드가 느린 이유

베테랑 프로그래머라면 이미 다 알기도 하겠지만, C/C++ (특히 C++)은 강력한 대신 정말 만년 굼벵이 언어가 될 수밖에 없는 요인만 일부러 골고루 가진 채 만들어졌다 해도 과언이 아닌 것 같다.

뭐가 굼벵이냐 하면 두 말할 나위도 없이 빌드 속도 말이다. C#, 자바, 델파이 같은 다른 언어나 툴과 비교하면 안습 그 자체. 이건 컴퓨터의 속도만 빨라진다고 해서 극복 가능한 차원의 차이가 아니라 구조적으로 심한 부담과 비효율 때문이다. 이 점에 대해서는 본인도 예전에 여러 글을 블로그에다 언급한 적이 있다.

  • 일단 C++은 태생이 바이트코드 같은 가벼운 가상 기계가 아니라 철저하게 기계어 네이티브 코드 생성 지향이다. 다른 가벼운(?) 언어들과는 위상부터가 다르며, 이 상태에서 최적화까지 가면 부담은 더욱 커진다. 게다가 이 언어는 설계 철학이 컴파일 시점 때 최대한 많은 걸 미리 결정하는 걸 지향하고 있다. 가령, 자바에 inline이라든가 함수 호출 규약, 레지스터, C++ 수준의 static한 템플릿 메타프로그래밍, 혹은 링크 타임 코드 생성 같은 개념이 있지는 않다.
  • 또한 이 언어는 근본적으로 문법이 상당히 문맥 의존적이고 복잡하여, 구문 분석이 어렵다. 단적인 예로 함수 선언과 객체 선언 A b(c); 변수 선언과 단순 연산식 B*c; 형변환 연산과 단순 연산식 (c)+A 가 c가 무엇인지 문맥에 따라 왔다갔다 하면서 완전히 달라진다. 거기에다 C++의 경우 템플릿, 오버로딩, namespace ADL까지 가면 난이도는 정말 안드로메다로. 다른 언어는 O(n log n) 시간 복잡도만으로도 되는 구문 분석 작업이 C++은 반드시 O(n^2)을 쓰지 않으면 안 되는 과정이 있다고 한다.
  • 빌드를 위해 전처리, 링크 같은 복잡한 계층이 존재하며, 특히 링크는 병렬화도 되지 않아 속도를 더욱 올릴 수가 없는 작업이다. 한 모듈에서 참조하는 함수의 몸체가 다른 어느 번역 단위에 있을지는 전혀 알 수 없다!
    그런데 요즘 C++ 컴파일러의 트렌드는 1에서 잠시 언급했듯이 링크 타임 때의 코드 생성과 최적화(인라이닝 포함)여서 이런 병목 지점에서 더욱 많은 작업량이 부과되고 있다. 이런??

이런 특징은 유독 C/C++ 언어만 개발툴/IDE에서 프로젝트를 만들면 온갖 잡다한 보조 데이터 파일들이 많이 생성되는 이유와도 일맥상통한다. 소스 코드를 잽싸게 분석하여 인텔리센스 같은 똑똑한 IDE 기능을 제공하기가 여타 언어들보다 훨씬 더 어렵기 때문이다.

2. 인클루드의 문제점

그런데, 네이티브 코드 생성, 복잡한 문법 같은 것 이상으로 C/C++의 빌드 시간을 더욱 뻥튀기시키고 빌드 작업을 고달프게 하는 근본적인 요소는 전처리 중에서도 다름아닌 #include 남발이다. C/C++은 남이 만들어 놓은 함수, 클래스, 구조체 같은 프로그래밍 요소를 쓰려면 해당 헤더 파일을 무조건 인클루드해 줘야 한다.

일단 이건 문법적으로는 인위적인 요소가 없이 깔끔해서 좋다. 인클루드되는 헤더는 역시 C/C++ 문법대로 작성된 일반 텍스트 파일이며, 내가 짜는 프로그램이 참조하는 명칭들의 출처가 여기 어딘가에는 반드시 있다고 보장됨을 내 눈으로 확인할 수 있다. 그러나 DB 형태로 최적화된 바이너리 파일이 아니라 파싱이 필요한 텍스트 파일이란 점은 일단 빌드 속도의 저하로 이어진다. 이게 문제점 하나.

본격적인 C++ 프로그램을 하나 만들려면 표준 C/C++ 라이브러리뿐만이 아니라 윈도우 API, MFC, 그리고 다른 3rd-party 라이브러리, 게임 엔진 등 갖가지 라이브러리나 프레임워크가 제공하는 헤더 파일을 참조하게 된다. 이것들을 합하면 한 소스 코드를 컴파일하기 위해 인클루드되는 헤더 파일은 가히 수십, 수백만 줄에 달하게 된다.

게다가 이 인클루드질은 전체 빌드를 통틀어 한 번만 하고 끝인 게 아니라, 이론적으로는 매 번역 단위마다 일일이 새로 해 줘야 한다. 헤더 파일 의존도가 개판이 돼 버리는 바람에 헤더 파일 하나 고칠 때마다 수백 개의 cpp 파일이 재컴파일되는 문제는 차라리 애교 수준이다. 문제점 둘.

보통 헤더 파일에는 중복 인클루드 방지를 위한 guard가 있다.

#ifndef ___HEADER_DEFINED_
#define ___HEADER_DEFINED_

/////

#endif

그런데 #if문 조건을 만족하지 못하는 줄들은 단순히 구문 분석과 파싱만 skip될 뿐이지, 컴파일러는 여전히 중복 인클루드된 헤더 파일도 각 줄을 일일이 읽어서 #else나 #endif가 나올 때까지 들여다보긴 해야 한다.

많은 사람들이 간과하는 사실인데(사실 나도 그랬고), 그때는 컴파일 작업만 잠시 중단됐을 뿐, 전처리기는 전체 소스를 대상으로 여전히 동작하고 있다. 중복 인클루드가 컴파일러의 파일 액세스 트래픽을 얼마나 증가시킬지가 상상이 되는가? guard만 있다고 장땡이 아니며, 이게 근본적으로 얼마나 비효율적인 구조인지를 먼저 알아야 한다. 문제점 셋.

그리고 이 #include의 수행 결과를 컴파일러나 IDE로 하여금 예측이나 최적화를 도무지 할 수가 없게 만드는 치명적인 문제는 극단적인 문맥 의존성이다.
헤더 파일은 그저 static한 함수, 클래스, 변수 선언의 집합체가 아니다. 엄연히 C/C++ 소스 코드의 일부를 구성하며, 동일한 헤더라 해도 어떤 #define 심벌이 정의된 상태에서 인클루드하느냐에 따라서 그 여파가 완전히 달라질  수 있다.

극단적인 예로, 한 소스 파일에서 #define 값만 달리하면서 동일 헤더 파일을 여러 번 인클루드함으로써, 템플릿 비스무리한 걸 만들 수도 있단 말이다. 일례로, 비주얼 C++ 2010의 CRT 소스에서 strcpy_s.c와 wcscpy_s.c를 살펴보기 바란다. 베이스 타입만 #define을 통해 char이나 wchar_t로 달리하여 똑같이 tcscpy_s.inl을 인클루드하는 걸로 구현돼 있음을 알 수 있다...;;

물론 인클루드를 실제로 그렇게 변태적으로 활용하는 예는 극소수이겠지만 인클루드는 여타 언어에 있는 비슷한 기능인 import나 use 따위와는 차원이 다른 개념이며, 캐싱을 못 하고 그 문맥에서 매번 일일이 파싱해서 확인해 보는 수밖에 없다. 문제점 넷이다.

이런 문제 때문에 여타 언어들은 텍스트 파싱을 수반하는 인클루드 대신, 별도의 패키지 import 방식을 쓰고 있으며, Objective C도 #include 대신 #import를 제공하고 헤더 파일은 무조건 중복 인클루드가 되지 않는 구조를 채택하여 셋째와 넷째 문제를 피해 갔다.

비주얼 C++도 #pragma once라 하여 #endif를 찾을 것도 없이 중복 인클루드를 방지하고 파일 읽기를 거기서 딱 중단하는 지시자를 추가했다. 이건 비표준 지시자이긴 하지만 전통적인 #ifdef~#endif guard보다 빌드 속도를 향상시키는 테크닉이기 때문에 프로그래머의 입장에서는 사용이 선택이 아닌 필수이다. 물론, 단순히 중복 선언 에러만 방지하는 게 아니라 특정 헤더 파일의 인클루드 여부를 알려면 재래식 #define도 좀 해 줘야겠지만 말이다.

외부에서 기선언된(predefined) 프로그래밍 요소를 끌어오는데, namespace나 package 같은 언어 계층을 거친 명칭이 아니라 생(raw-_-) 파일명의 지정이 필요한 것부터가 오늘날의 관점에서는 꽤 원시적인 작업이다. 개인적으로는 인클루드 파일의 경로를 찾는 메커니즘도 C/C++은 너무 복잡하다고 생각한다.

""로 싸느냐 <>로 싸느냐부터 시작해서, 인클루드가 또 다른 파일을 중첩으로 인클루드할 때, 다른 인클루드 파일을 자기 디렉터리를 기준으로 찾을지 자신을 인클루드 한 부모 파일의 위치로부터 찾을지, 프로젝트 설정에 명시된 경로에서 찾을지 같은 것 말이다…;; 게다가 인클루드 명칭도 #define에 의한 치환까지 가능하다. #include MY_HEADER처럼. 그게 가능하다는 걸 FreeType 라이브러리의 소스를 보면서 처음으로 알았다.

그런데 그러다가 서로 다른 디렉터리에 있는 동명이인 인클루드 파일이 잘못 인클루드되기라도 했다면.. 더 이상의 자세한 설명은 생략. 내가 무심코 선언한 명칭이 어디엔가 #define 매크로로도 지정되어 있어서 엉뚱하게 자꾸 치환되고 컴파일 에러가 나는 것과 같은 악몽이 발생하게 된다! 문제점 다섯.

이것도 어찌 보면 굉장히 문맥 의존적인 절차이기 때문에, 오죽했으면 비주얼 C++ 2010부터는 인클루드/라이브러리 디렉터리 지정을 global 단위로 하는 게 완전히 없어지고 전적으로 프로젝트 단위로만 하게 바뀌었다는 걸 생각해 보자.

C++ 프로젝트에서 MFC의 클래스나 윈도우 API의 함수를 찍고 '선언으로 가기'를 선택하면 afxwin.h라든가 winbase.h 같은 표준 인클루드 파일에 있는 실제 선언 지점이 나온다. 그 방대한 헤더 파일을 매 빌드 때마다 일일이 파싱할 수가 없으니 인텔리센스 DB 파일 같은 건 정말 크고 아름다워진다.

그에 반해 C# 닷넷 프로젝트에서 Form 같은 클래스의 선언을 보면, 컴파일러가 바이너리 수준에서 내장하고 있는 클래스의 껍데기 정보가 소스 코드의 형태로 생성되어 임시 파일로 뜬다…;; 이게 구시대 언어와 신세대 언어의 시스템 인프라의 차이가 아닌가 하는 생각이 들었다.

그래서 이런 C++ 인클루드 체계의 비효율 문제는 어제오늘 제기되어 온 게 아니기 때문에, 컴파일러 제조사도 좀 더 근본적인 문제 회피책을 간구하게 됐다. 그래서 나온 것이 그 이름도 유명한 precompiled 헤더이다. stdio.h나 stdlib.h 정도라면 모를까, 매 번역 단위마다 windows.h나 afx.h를 일일이 인클루드해서 파싱한다는 건 삽질도 그런 삽질도 없으니 말이다..

3. precompiled header의 도입

일단 프로젝트 내에서 "인클루드 전용" 헤더 파일과 이에 해당하는 번역 단위를 설정한다. 비주얼 C++에서 디폴트로 주는 명칭이 바로 stdafx.cpp와 stdafx.h이다. 모든 번역 단위들이 공용으로 사용하는 방대한 양의 프레임워크, 라이브러리의 헤더를 몰아서 인클루드시킨다. 컴파일러 옵션으로는 Create precompiled header에 해당하는 /Yc "stdafx.h"이다.

그러면 그 헤더 뭉치들은 stdafx.cpp를 컴파일할 때 딱 한 번만 실제로 인클루드와 파싱을 거치며, 이 파일들의 분석 결과물은 빠르게 접근 가능한 바이너리 DB 형태인 프로젝트명.pch 형태로 생성된다.

그 뒤 나머지 모든 소스 파일들은 첫 줄에 #include "stdafx.h"를 반드시 해 준 뒤, Use precompiled header인 /Yu "stdafx.h" 옵션으로 컴파일한다. 그러면 이제 stdafx.h의 인클루드는 실제 이 파일을 열어서 파싱하는 게 아니라, 미리 만들어진 PCH 파일의 심벌을 참고하는 것으로 대체된다! 앞에서 제기한 인클루드의 문제점 중 첫째와 둘째를 극복하는 셈이다.

pch 파일이 생성되던 시점의 문맥과 이 파일이 실제로 인클루드되는 시점의 문맥은 싱크가 서로 반드시 맞아야 한다. 그렇기 때문에 소스 코드에도 문맥상의 제약이 걸린다. PCH를 사용한다고 지정해 놓고 실제로 stdafx.h를 맨 먼저 인클루드하지 않은 소스 파일은 Unexpected end of file이라는 컴파일 에러가 발생하게 된다. PCH 개념을 모르는 프로그래머는 C++ 문법에 아무 하자가 없는 외부 소스 코드가 왜 컴파일되지 않는지 이해를 못 할 것이다.

당연한 말이지만 stdafx.h가 인클루드하는 헤더 파일의 내용이 수정되었다면 PCH 파일은 다시 만들어져야 하며, 이때는 사실상 프로젝트 전체가 리빌드된다. 그러므로 stdafx.h 안에는 거의 수정되지 않는 사실상 read-only인 헤더 파일만 들어가야 한다.

인클루드 파일만 수십, 수백만 줄에 달하는 중· 대형 C++ 프로젝트에서 PCH가 없다는 건 상상조차 할 수 없는 일이다. 얼마 되지도 않는(많게 잡아도 200KB 이내) 소스 코드들이 high-end급 컴에서 그것도 네트워크도 아닌 로컬 환경에서 빌드 중인데 소스 파일 하나당 컴파일에 1초 이상씩 잡아 처먹는다면, 이건 인클루드 삽질 때문일 가능성이 매우 높다. 이 경우, 당장 PCH를 사용하도록 프로젝트 설정을 바꾸고 소스 코드를 리팩터링할 것을 심각하게 고려해야 한다. 이건 작업 생산성과 직결된 문제이기 때문이다.

아놔, 이렇게 글을 길게 쓸 생각은 없었는데 너무 길어졌다.
요컨대 C++ 프로그래머라면 자기의 생업 수단인 언어가 이런 구조적인 비효율을 갖고 있다는 걸 인지하고, 상업용 컴파일러 및 개발툴이 이를 극복하기 위해 어떤 대안을 내놓았는지에 대해 관심을 가질 필요가 있다.

자바, C#, D 등 C++의 후대 언어들은 C++과 문법은 비슷할지언정 이 인클루드 체계만은 어떤 형태로든 제각각 다 손을 보고 개량했음을 알 수 있다. 아까도 언급했듯, 하다못해 Objective C도 중복 인클루드 하나만이라도 자기 식으로 정책을 바꿨지 않던가.

한 가지 생각할 점은, C/C++은 태생이 이식성에 목숨을 걸었고, 언어의 구현을 위해 바이너리 레벨에서 뭔가 이래라 저래라 명시하는 것을 극도로 꺼리는 언어라는 점이다. 그래서 대표적으로 C++ 함수 decoration이 알고리즘이 중구난방인 아주 대표적인 영역이며, 함수 calling convension도 여러 규격이 난립해 있고 모듈/패키지 같은 건 존재하지도 않는다. 그런 차원에서, 비록 비효율적이지만 제일 뒤끝 없는 텍스트 #include가 여전히 선호되어 온 건지도 모르겠다.

4. 여타 언어의 인클루드

여담이다만, 본인은 베이직부터 쓰다가 C/C++로 갈아탄 케이스이기 때문에 인클루드라는 걸 처음으로 접한 건 C/C++이 아니라 퀵베이직을 통해서였다.

'$INCLUDE: 'QB.BI'

바로, 도스 API를 호출하는 인터럽트 함수와 관련 구조체가 그 이름도 유명한 저 헤더 파일에 있었기 때문이다.

C/C++에 전처리기가 있는 반면, 베이직이나 파스칼 계열 언어는 개념적으로 그런 전처리기와 비슷한 위상인 조건부 컴파일이나 컴파일 지시자는 주석 안에 메타커맨드의 형태로 들어있곤 했다. 그러나 여타 프로그래밍 요소를 끌어다 오는 명령은 메타커맨드나 전처리기가 아니라, 엄연히 언어 예약어로 제공하는 게 디자인상 더 바람직할 것이다.

그리고 파워베이직은 퀵베이직 스타일의 인클루드 메타커맨드도 있고, 파스칼 스타일의 패키지 지정 명령도 둘 다 갖추고 있었다.

Posted by 사무엘

2012/09/21 19:25 2012/09/21 19:25
,
Response
No Trackback , 5 Comments
RSS :
http://moogi.new21.org/tc/rss/response/735

요즘 코딩 잡설

1.

<날개셋> 한글 입력기의 개발 작업은 단순히 새로운 기능을 구현하거나 알려진 버그를 수정하는 것 말고도, 멀쩡히 동작하는 기능의 내부 구현 형태를 바꾸는 리팩터링도 무시 못 할 비중을 차지하고 있다.

이미 지금도 문제가 없긴 하지만, 열기-닫기 내지 할당-해제 같은 패턴은 어지간하면 클래스의 생성자와 소멸자가 알아서 하게 바꿔서 리소스 누수(leak)를 컴파일러 차원에서 원천적으로 차단하고 있으며,
최근에는 비주얼 C++ 2010으로 갈아탄 덕분에 지저분한 임시 #define 함수들을 지역 변수 형태의 람다 함수로 교체하는 재미가 쏠쏠하다. 예를 들어 이런 것 말이다.

BEFORE
#define PickNumber(e) ((e)[1] ? wcstol((e), &f, 16): *(e))

AFTER
auto PickNumber = [&f](PCWSTR e) -> int { return e[1] ? wcstol(e, &f, 16): *e; };

별도의 함수로 추가하기에는 너무 지엽적이고 한 함수 안에서만 잠깐 쓰고 마는 반복적인 루틴들은 람다로 싸 주는 게 딱이다. type-safety가 보장되고, scope도 엄격하게 정해지고, 이 루틴을 매번 인라인으로 expand할지 아니면 그냥 함수 호출로 처리해서 코드 크기를 줄일지를 컴파일러가 좀 더 유연하게 판단할 수 있기 때문에 아주 좋다.

예전에는 C++에 대해서 C with classes라고 배웠겠지만, 이제는 C++은 C with classes라고만 정의하기에는 설명에 누락된 요소가 너무 많아졌다.
람다 함수를 전역 변수로 선언하는 건 문법적으로 불가능하지는 않으나, 그럴 바에야 그냥 재래식 형태의 함수를 하나 선언하고 말지 아무런 특별한 의미가 없을 것이다.

2.

그런데, 이렇게 리소스 누수를 막기 위해서 노력하고 있지만 구조체에다 함께 넘어온 핸들이나 메모리 포인터는 그것만 따로 클래스의 소멸자가 자동으로 소멸하게 할 수 없으니 구조적으로 여전히 누수 위험이 존재한다.

예를 들어 CreateProcess 함수는 실행 후 해당 프로세스에 대한 핸들을 PROCESS_INFORMATION 구조체에다가 되돌려 준다. 이 값을 이용해서 프로그램은 자신이 새로 실행한 프로그램이 실행이 끝날 때까지 기다린다거나 할 수 있다. 하지만 실행된 프로세스가 종료되더라도 그 프로세스를 가리키던 핸들은 해제되지 않는다. 호스트 프로그램이 핸들을 닫아 줘야만 완전히 해제된다.

CreateProcess 함수를 자주 쓴다면 핸들 해제까지 모든 작업을 자동화해 주는 클래스를 만들어서 쓰는 게 효과적이다. 사실, 이 함수는 받아들이는 인자가 많고 기능 한번 쓰는 게 번거로운 편이기 때문에 클래스를 쓸 법도 하지만, 어쩌다 한 번 쓰고 마는 특수한 함수를 전부 클래스로 감싸는 건 좀 낭비처럼 보이는 게 사실이다.

<날개셋> 편집기에는 있으나마나한 잉여이긴 하지만 명색이 텍스트 에디터이다 보니 인쇄 기능이 있다.
그런데 한때는 인쇄를 한 뒤에 자신이 사용한 프린터 DC를 해제하지 않아서 GDI 개체 누수가 생기는 버그가 있었다.
물론 이건, 리소스 제한이 있는 윈도우 9x에서 이 프로그램을 한 번 실행한 후, 프린터 드라이버를 이용한 인쇄(화면 인쇄 말고) 명령을 연달아 몇백, 몇천 번쯤 내려야(한 번에 몇백, 몇천 페이지를 인쇄하는 것과는 무관) 여파가 나타날 버그이니, 현실적으로는 아무런 위험이 아닌 것이나 마찬가지이다.

이 문제의 원인은 PrintDlg 함수가 PRINTDLG 구조체에다가 넘겨준 hDC 멤버(프린터 DC)를 해제하지 않아서였다.
그런데 이런 실수가 들어갈 법도 했던 게, MSDN에서 해당 함수나 해당 구조체에 대한 설명 어디에도, 사용이 끝난 DC를 처분하는 것에 대해서는 언급이 없었다.
이거 혹시 해제해야 하는 게 아닌지 미심쩍어서 내가 우연히 잉여질 차원에서 다른 예제 코드를 뒤져 본 뒤에야 DeleteDC로 해제를 해야 한다는 걸 알게 되었고, 예전 코드에 리소스 누수 버그가 있음을 깨달았다.

하긴, 내 기억이 맞다면, COM 오브젝트도 프로그래머가 Release를 제대로 안 해서 개체 누수가 하도 많이 생기다 보니 MS에서도 골머리를 썩을 정도였다고 하더라. 현실은 이상대로 되질 않는가 보다.

3.

윈도우 운영체제의 device context에 대해서 보충 설명을 좀 할 필요를 느낀다.
DC라는 건 그림을 그리는 매체가 (1) 화면, (2) 메모리(대부분은 화면에다 내보낼 비트맵을 보관하는 용도), 아니면 (3) 프린터 이렇게 셋으로 나뉜다. 화면용 DC는 GetDC나 GetWindowDC를 통해 HWND 오브젝트로부터 얻어 오고 해제는 ReleaseDC로 한다.

그러나 나머지 두 DC는 화면 DC와는 달리, DeleteDC로 해제한다는 차이가 있다. 화면용 DC는 운영체제가 통합적으로 관리하는 성격이 강한 반면, 나머지는 전적으로 사용자 프로그램의 재량에 달린 비중이 커서 그런 것 같다.

메모리 DC는 화면 같은 다른 물리적인 매체 DC와 연계를 할 목적으로 만들어지는 가상의 DC이므로, 보통 CreateCompatibleDC를 통해 이미 만들어진 DC를 레퍼런스로 삼아서 생성된다. 레퍼런스 DC가 무엇이냐에 따라서 하다못해 pixel format 같은 거라도 차이가 날 수 있기 때문이다.

그 반면 프린터 DC는 대개 가장 수준이 낮은 CreateDC를 통해 만들어지는데, 응용 프로그램이 특정 디바이스를 지목해서 DC를 하드코딩으로 생성하는 경우는 거의 없고 보통은 사용자에게 인쇄 대화상자를 출력한 뒤에 운영체제의 GUI가 생성해 주는 DC를 그대로 사용하면 된다.

사실, 프린터야 인쇄 전과 인쇄 후에 프린터에다 초기화 명령을 내리고 종이를 빼내는 등 여러 전처리· 후처리 작업이 필요하고 그런 저수준 명령은 프린터 하드웨어의 종류에 따라 다 다르다.
메모리는 프린터만치 하드웨어를 많이 가리지는 않겠지만, 그래도 그래픽을 보관하기 위해 메모리를 할당하고 나중에 해제하는 작업이 필요하다.

그에 반해 단순히 화면에다가 그림을 찍는 건 각 context별로 좌표를 전환하고 클리핑 영역 설정을 바꾸는 것 외에는 별다른 오버헤드가 존재하지 않는다. 도스 시절의 그래픽 라이브러리는 그런 DC 같은 추상화 계층 자체가 아예 존재하지도 않았으니 말이다.
그런 오버헤드의 위상이 ReleaseDC와 DeleteDC의 차이를 만든 것 같다.

Posted by 사무엘

2012/09/19 19:32 2012/09/19 19:32
,
Response
No Trackback , 8 Comments
RSS :
http://moogi.new21.org/tc/rss/response/734

지난 8월 4일에 전쟁 기념관에서 열린 <북한 실상 바로 알기> 특별 교육 프로그램 시리즈 중 하나에서 강의를 들은 내용을 요약하고 나의 의견을 추가하였다.

0. 들어가는 말

- 전반적으로 신앙 간증 집회 분위기 반, 예비군 가서 듣는 안보 강연 같은 분위기 반이었다.
- 탈북자들이 하나같이 중국을 거쳐서 먼 길을 우회한 끝에 한국으로 들어오는 이유는 당연히... 대놓고 휴전선을 넘어서 남하하기란 불가능하기 때문이다. (아니면 전투기 째로 휴전선 넘어서 귀순하든가)

1. 북한 내부 사회 구조

- 북한군은 병이 10년이고 간부는 그보다도 더 긴 어마어마한 의무 복무 기간을 자랑하는데, 군생활 동안 일반 정기 휴가가 없다... 캐안습. (포상 휴가만 있음)
- 북한에도 투표가 있긴 하다. 김 일성· 김 정일 얼굴 액자가 놓여 있는 투표소에 들어가는데, 투표 용지에다 투표자의 이름과 생일을 적고 투표를 해야 한다. ㅋㅋㅋㅋㅋㅋ 익명 비밀 투표 따윈 없다.
- 북한에서는 평양 거주 핵심 계층이 아니면, 통행증 없이는 시· 도도 못 드나든다. 비행기, 열차 같은 교통수단은 사실상 고위 간부 가족이나 외국인 전용이다.
- 김 대중· 노 무현 정권이 퍼 줬던 어마어마한 양의 물자들은 전부 다 핵 실험 자금으로 간 건 아니겠지만, 군대로만 갔지 어쨌든 굶주리는 주민들에게 간 건 절대 아니라고 한다. (북한에는 굶주리는 주민들에게 물자를 시골 구석구석까지 보내 줄 도로 인프라도 없다.)
- 평민들은 총칼과 폭력으로 악랄하게 통제하고, 간부들끼리는 정치 장교를 둬서 서로 밀고와 배신이 가능하게(= 단합을 못 하게) 아주 마귀적인 시스템을 잘 갖춰 놨다고 한다. 북한이 내부 사정이 저렇게 막장인데도 호락호락 혁명이나 봉기가 안 일어나는 이유가 이것 때문임.

2. 북한 사람들의 심리

- 북한 사람들이 김씨 부자를 찬양하거나 애곡하면서 오버액션 하는 건 한 80%는 진심이고, 20%만이 생존하기 위해 마음에 없는 연기를 하는 거라고 한다. 남한이 자기네보다 잘 산다는 정보도 이미 퍼져 있지만, 뼛속까지 세뇌된 거짓 교리의 힘도 만만찮다고 한다.
- 당에서 하도 “미제를 죽입시다 미제는 나의 원쑤”만 세뇌시키니까 한 탈북자가 어렸을 때 자기 어머니에게 “왜 그래요? 미국 사람도 다 나쁘지는 않지 않나요?” 이렇게 진짜 궁금해서 질문을 했는데... 곧바로 귀싸대기가 날아오고 맞아 죽을 뻔 했다고-_-;;. 주체사상 앞에서는 천륜이고 뭐고 없다.
- 그래도 북한도 변화가 아주 없는 건 아니어서 이불 뒤집어쓰고 몰래 한국 가요와 한국 드라마를 접하는 북한 사람도 적지 않다고 한다.
안 그래도 국가가 국민들을 제대로 먹여 살리지도 못하니, 젊은이들을 중심으로 '당보다 나' 생각이 퍼지고 있고, 북한 당국은 주민들이 남한 사정에 대해 잘 알게 되는 것을 무척 불편하게 여긴다.

3. 대학 교육

- 북한의 대학은 고등학교 졸업 후 바로 진학하는 건 한정돼 있고, 먼저 군대나 직장 근무 후에 재교육 차원에서 들어가는 비중이 높다고 한다.
- 아무나 대학에 못 가고 출신 성분과 계급이 중요하지만, 김일성대 리과대학이나 김책 공업 종합 대학 같은 일부 이공계 대학은 오로지 실력만으로 들어갈 수 있다고 한다. 역시 공돌이는 어디서나 필요하니까 말이다. -_-;; 북한에서 핵 무기와 미사일을 연구하는 사람이 누구이겠는가?
- 일단 대학에 가면 개인이 떠안는 등록금 부담은 없지만, 거의 전원 기숙사 생활, 학급제, 모든 수업에 지정 좌석제 때문에 사실상 고등학교 생활의 연장선이다.
- 학생들은 방학 때는 수시로 군사훈련이나 각종 행사에 동원된다. 과거에 우리나라에도 있었던 교련 과목 따위와는 스케일이 넘사벽 급. 매스게임이나 90도 다리 꺾기 제식 훈련을 하는 애들도 군인만 있는 게 아니라 상당수가 학생들이라고.
- 학비 부담 없고 개인 자유도 없는 건 무슨 사관학교 같은 컨셉이다..? -_- 그럼 거기는 진짜 사관학교는 어떤지, 그리고 대학원 진학은 어떻게 하는지가 궁금해졌으나 분위기 상 연사에게 차마 더 물어 보지는 않았다.

4. 결론

- 나라 없는 설움은 겪어 본 사람만이 안다. 그리고 자유의 소중함도 두 말할 나위가 없다. 북한은 정말 말 그대로 자유가 없는 나라이다(집회와 결사, 사상과 종교, 거주지 이동 등). 자유는 공짜가 아니다.
- 국내에서 활개를 치고 있는 '빨갱이' 종북주의자들을 보는 탈북자들의 심기도 편할 리가 없다.
- 연사들은 이런 주제에 관심을 갖고 들으러 찾아온 사람들에게 무척 고마워하면서 관심을 호소했다. 많은 사람들이 이 북한의 현실을 알고 남에게 전해 주고 경각심을 가지면 좋겠다고.
- 참석자 중에는 내가 젊은 나이에도 불구하고 북한에 대해 굉장한 관심을 갖고 질문을 진지하게 하고 오후 강의까지 듣는 것을 대견스럽게 여기는 분이 계셨다.

5. 추가 잡설

- 6· 25뿐만이 아니라, 강화도 조약 이래로 시작된 우리나라의 수난의 근· 현대사에 대해서 다시 생각하는 계기가 되었다. 북한이든 일본이든 맨날 외세를 탓하고 원망만 해서는 아무 발전도 이룰 수 없을 것이다. 그러나 아무 일도 없었다는 듯이 과거사를 존재감 없이 묻어 두고만 살 수도 없는 노릇. 가끔 이렇게 옛날에 있었던 끔찍한 비극에 대해서 자극 충전을 받는 날도 필요하다.
- 그런 의미에서…
6· 25 이전부터 북한이 남한의 건국을 방해하고 좌익 불순분자들을 선동하여 온갖 추악한 난동을 저지른 건 싹 외면하고, 6· 25 때 미군이나 국군이 민간인을 일부 오인해서 죽인 것만 들추면서 역사를 왜곡하는 불순한 부류들이 성경 변개자만큼이나 더욱 싫어진다. ㅡ,.ㅡ;;

Posted by 사무엘

2012/09/16 19:33 2012/09/16 19:33
, , , , ,
Response
No Trackback , 7 Comments
RSS :
http://moogi.new21.org/tc/rss/response/733

1.

<날개셋> 한글 입력기는 제어판에서 불러다가 곧장 쓸 수 있는 20여 개의 다양한 예제 입력 방식들을 덩달아 제공하고 있다.
6.7 이후 다음 버전에서는 예제 데이터에 아래와 같은 여러 변화가 생길 예정이다.

- 6.7에서 잘 알다시피 종성 지향 두벌식을 활용하여 'MS 두벌식'이라는 유형 파일이 추가되었는데.. 여기에다가 한글 자모 외의 숫자와 기호는 글쇠를 먹지 않게 하는 입력 스키마 설정도 추가했다. (지난 6.5에서 추가된 글쇠 인식 customize 기능으로) 어차피 시스템의 영문 글자판과 똑같은 글자는 IME가 입력시키는 게 아니라 아예 글쇠 자체를 가로채지 않고 응용 프로그램으로 넘겨 준다는 뜻.
이것까지 갖춰 주면 진짜 MS IME와 고증이 100% 일치하게 된다. 특히 외부 모듈에서 말이다.

- 네벌식이 글쇠배열 *.key이 아니라 오토마타와 낱자 결합 규칙을 갖춘 유형(*.ist) 파일로 승격되었다.
받침을 입력하려면 모음을 아무 모음이나 써도 되는 게 아니라 타자기 설계 차원에서 받침용으로 의도된 모음을 써야만 하며, 그렇지 않으면 받침은 다음 글자로 튕긴다.

모음의 용도를 구분하는 건 다양한 방법으로 할 수 있다. 비받침용 모음은 0으로 대응하는 가상 받침을 같이 입력되게 하여 여타 받침과의 결합을 차단시킬 수도 있는데, 본인의 경우 두벌식 모음과 세벌식 모음으로 구분하여 오토마타가 O 변수를 써서 구분하도록 하는 방법을 썼다.

이 외에도 네벌식 오토마타는 초+중(+종)과 중+종은 허용하지만, 초에서 바로 종은 허용하지 않게 설계되어 있다. 97 이전의 도스용 아래아한글이 이런 오토마타를 갖추고 있었다. 또한 ㅒ, ㅖ가 바로 입력 가능하지 않다는 특성상 ㅑ+ㅣ, ㅕ+ㅣ로 해당 모음을 입력할 수 있게 했다.

네벌식은 그나마 옛날 타자기 표준이라는 역사적인 의미가 있고, <날개셋> 기능 활용면에서 의미가 있어서 추가했을 뿐, 타자 관점에서 효율적인 입력 방식은 절대로 아니다. 특히 공 병우 세벌식에 비하면 이런 허접하고 불편한 타자기로 한글 입력을 해야 했을 옛날 타자수들을 생각하면 그저 안구에 습기가 찰 뿐이다.

- 일명 '한소프트 세벌식'과, '드보락 호환 두벌식' 글쇠배열은 효용성이 떨어진다고 판단하여 삭제했다.
특별히 '한소프트 세벌식'에 대해 보충 설명을 하자면, 정체가 불분명하고 원문 자료를 제공하던 사이트도 운영이 중단되어 접속이 불통된 지가 이미 수 년이 지난 상태이다. 글쇠배열도 어차피 그리 잘 만들어진 것도 아닌지라 퇴출을 결정했다. 특히 숫자를 저렇게 Shift를 누른 채 양손으로 입력하게 해 놓으면 도대체 어쩌라는 건지? -_-

2.

현재 '세벌식 순아래' 글쇠배열이라는 게 있어서 예제 파일도 아니고 아예 프로그램에 내장되어 있는 배열 중 하나이다.
그러나 이것은 장기적으로는 *.key 급으로 격하될 예정이다. 내장 데이터로 쳐 주기에는 너무 듣보잡화해 있기 때문이다.

공 병우 박사의 이념을 물려받은 권위와 정통성 있는 세벌식 연구 기관에서--한글 문화원이라든가, 한글 문화원이라든가...-- 앞으로 390과 최종을 통합하는 새로운 세벌식 표준안을 제정한다면, 그 새 배열이 지금 순아래가 있던 자리를 대체하게 될 것이다.

그리고 그 통합안은 더 장기적으로는 390을 또 대체하게 될 수도 있다. 과거에 390이 389를 대체했듯이 말이다.
통합안은 기호 문제 때문에 최종보다는 390에 훨씬 더 가깝게 만들어질 것이다.
그 반면 2000년대부터 세벌식을 접한 사람들은 390보다는 최종이 더 많다. 본인도 최종 사용자.
최종은 27개 겹받침 모두 수록이라는 궁극의 아킬레스건이 있기 때문에 상징적인 의미가 크며, 통합안이 나온 뒤에도 별도로 존속할 가능성이 높다.

이런 이유로 인해, 기존 390 사용자들만 통합안으로 갈아타면, 최종과는 달리 390은 존재의 의미를 상실하여 역사 속으로 사라지게 될 것이다. 이것이 나의 짧은 생각이다.

3.

내 프로그램에는 역사적으로나 설계 방식면에서 의미가 있는 세벌식 글쇠배열 몇 개가 key 파일로 제공되고 있다. 세벌식 389는 받침 배열이 390과 최종의 짬뽕 같으면서도 숫자가 노트북 PC의 키패드 배열과 일치한다는 특징이 있으며, '송 영상'(닉: 길동무)이라는 분이 고안한 영상 세벌식은 세벌식계의 떡밥인 왼쪽부터 시작하는 세벌식을 나름 독창적으로 구현한 배열이다.

누가 만들었는지 모를 왼손/오른손 세벌식은 no shift로도 모자라서 진짜 말 그대로 한 손으로 타자를 치는 것에 특화되어 있다. 내가 알기로 영문 드보락 자판에도 이런 왼손/오른손 변종 배열이 있다. 아마 옛날에 도스용 에디터 같은 데서 이것저것 수집한 자료이지 싶다.

이런 것들은 역사적인 의미 외에 실용적으로 쓰일 가능성이 높지 않으며, 오토마타나 낱자 결합 규칙 같은 것도 그냥 일반적인 PC용 한글 입력기의 설정을 그대로 가져와 쓰는 것만으로도 충분하기 때문에, 유형 파일이 아니라 글쇠배열 형태로만 간단히 제공된다.

4.

현재 프로그램이 기본 제공하는 예제 입력 방식이 20여 개가 있다지만, 파일 하나가 겨우 몇백~몇천 바이트밖에 하지 않으니, 다 합쳐도 크기는 3만 바이트가 채 되지 않는다.
본인은 <날개셋> 한글 입력기의 사용자가 만든 UCC..는 아니고 UCI (user-created input methods) 데이터를 받는다.
마음에 드는 건 프로그램의 다음 버전에다 같이 수록도 흔쾌히 해 줄 것이다. 사실은, 이런 데이터만 공유하는 커뮤니티가 좀 있으면 좋겠다.

선정 기준은 다음과 같다. 하나 이상을 잘 만족하면 된다.

- 아이디어가 기술적으로 독창적일 것: 복벌식이나 신세벌식 같은 것. 이런 식으로 <날개셋>의 조건부 수식과 오토마타, 가상 낱자, 더 나아가 특수 글쇠 따위를 잘 활용하여 두벌식과 세벌식 사이를 왔다 갔다 하는 독창적이고 기발한 한글 입력 방식은 얼마든지 웰컴이다. 수록 0순위임. 다만 한 아이디어 당 한 개, 많아야 두 개로 국한임.

- 역사적 가치가 있거나, 인지도· 권위가 있을 것: 역사성이라 함은 앞서 언급했던 여러 legacy 세벌식 글쇠배열 말이다. 아니면 다수가 쓰거나 명목상의 표준이기라도 해야 한다.
북한 국규 표준은 나름 그쪽에서 권위를 가지고 통용되는 입력 방식이니, 통일을 대비해서라도 예전에 key로만 제공되던 것을 최근에 완전한 유형 형태로 격상했다. 아래아한글 97과 맥 OS, MS 두벌식 같은 기존 메이저 소프트웨어가 미묘하게나마 차이가 존재하는--그것도 오토마타 차원에서!-- 독창적인 한글 입력 방식을 제공하는 것도 바람직한 일이다.

휴대전화용 3대 표준 입력 방식(천지인, 이지한글, SKY-II)은 기술적 독창성과 권위를 모두 갖추고 있으니 두 말할 나위도 없이 수록이다. 사실 이것들을 포인팅 장비로 써 볼 수 있는 보조 입력 도구(패드)도 만들어야 하는데, 아직 6.7에서는 숙원을 못 풀었다.

- 타자 행동 관점에서 아주 효율적이거나 독창적일 것: 모바일용 입력 방식은 워낙 기술적인 메커니즘이 많은 반면, PC용 입력 방식은 딱히 그런 trick은 없이 그냥 글쇠배열 논쟁으로 흐르는 경향이 있다.
역사적인 뿌리나 인지도가 없고 그렇다고 기술적인 독창성도 없는 마이너 글쇠배열이 <날개셋>의 예제로 등재되기 위해서는 진짜 타자 효율이라도 압도적으로 좋다는 증거가 있어야 한다. 그게 아니면 순아래/한손 배열처럼 장애인 접근성 분야라도 파든가.

'영상 세벌식'은 타자 능률까지는 모르겠지만 왼쪽에서 오른쪽으로 흐르는 세벌식이라는 점이 독창성을 인정받아 예제 데이터로 수록되어 있다. 앞서 말한 기술적인 독창성 말고, 배열 자체가 독창적이라는 뜻이다.

- 한글 입력과 관련된 실생활에서 유용할 것: <날개셋> 한글 입력기는 기본적으로 한글 입력에 특화되어 있기 때문에 예제 데이터도 한글 입력 방식을 우대함을 원칙으로 한다. 한글이 아닌 문자는 한국 문화권에서 한글과 같이 즐겨 쓰이는 문자들로 국한한다.

가령, 일본어 문자는 아무래도 아랍· 태국-_- 문자보다야 한국에서 더 친숙하며, <날개셋> 고급 입력기의 사용자 정의 조합 기능을 이용해서 간단히 커버 가능한 예이기 때문에 히라가나와 가타카나가 모두 수록되어 있다. 구결도 마찬가로 국어 정보학 분야에서 유용하기 때문에 수록이다.
콜맥 글자판은 한글 입력과 관계가 없는 영문이지만, 드보락 다음으로 나름 인지도가 있는 마이너 배열인지라 영문 배열은 딱 하나만 선택해서 넣었다.

이상으로 내가 예제 입력 데이터를 선별하여 수록하는 대원칙을 공지했다.
저런 조건 중 하나 이상을 만족하고 기존 예제들과도 완전히 다른 입력 방식이 과연 얼마나 있을지는 잘 모르겠지만, 내 프로그램을 통해 여러 창의적인 한글 입력 방식이 많이 만들어지고 쓰이면 좋겠다.

<날개셋> 한글 입력기는 한글 입력과 관련된 그런 지적 재산들을 모두 구현하고 관리할 수 있는 프로그램이니 말이다.
그런 기반을 마련하기 위해 초창기엔 가장 엄밀한 극단이라 할 수 있는 공 병우 세벌식부터 추구한 뒤, 점차 더 generic한 쪽으로 내려오고 있는 중이다.

여담이지만, '한글 로마자 입력 방식'처럼, 그 자체가 한 입력 방식이 아니라 특정 포괄적인 아이디어 하에서 세부적으로 다양한 입력 방식이 파생되어 나올 수 있다면, 그건 유형 파일이 아니라 아예 별도의 '빠른설정'이라는 플러그 인 프로그램이 담당하게 된다.

Posted by 사무엘

2012/09/13 19:18 2012/09/13 19:18
, , ,
Response
No Trackback , 6 Comments
RSS :
http://moogi.new21.org/tc/rss/response/732

우리는 학교에서 산수를 배우면서 덧셈을 가장 먼저 배우고, 그 뒤 이들을 묶은 형태인 곱셈을 배운다. 그리고 나중에는 곱셈을 묶은 거듭제곱이라는 걸 배운다. 그런데 덧셈이나 곱셈과는 달리, 거듭제곱은 같은 수를 곱하기를 반복한다는 직관적인 정의만 적용해서는 정수가 아닌 형태의 거듭제곱을 생각하기가 쉽지 않다.

지수법칙이 있으니 유리수 승까지는 그래도 괜찮다. 정수 승과 정수 제곱근으로 설명이 가능하기 때문이다. 하지만 이를 초월하여 2^sqrt(2)처럼 임의의 실수 승은 어떻게 해야 계산하고 표현할 수 있을까?

거듭제곱을 모든 실수 범위에서 정의함으로써 지수함수라 불리는 연속인 함수의 형태로 영역을 확장하는 데는, '연속'이라는 개념에서 알 수 있듯, 미분의 도입이 큰 기여를 했다. 자연상수 e가 발견되고 로그 함수라는 게 생기면서 지수함수는 로그의 역함수로서 정체성을 확립하게 되었다.

이 글에서 수학적으로 엄밀한 디테일을 다 말할 수는 없지만, e는 임의의 수에다 제곱근을 반복하면서 지수가 0에 가까워지고 원래 수가 1에 한없이 가까워질 때 그 수의 소숫점, 다시 말해 숫자에서 1을 뺀 값이 지수와 어떤 비례 관계가 있는지를 규명하는 과정에서 발견되었다. (1+1/n)^n에서 n의 무한대 극한이라는 원론적인 정의가 바로 거기서 유래되었으며, 사실, (1+x/n)^n라고 해 주면 그냥 exp(x)를 바로 구할 수 있다.

exp(x)는 0인 지점에서 기울기가 1이다. 그리고 미분해도 도함수가 자기 자신과 같다는 매우 중요한 특징이 있다. 즉, y=exp(x)에 있는 점 (x, y)의 기울기는 곧 y라는 뜻. 그럼 이놈의 역함수는 어떻게 될까? 본디 함수와 그 역함수는 y=x에 대해 대칭이므로, 점 (y, x)의 기울기는 곧 1/y여야 한다.

미분하면 1/x가 되는 함수를 찾아보니 다름아닌 ln x이다. 복잡한 거듭제곱을 곱셈으로, 곱셈은 덧셈으로 바꿀 수 있는 놀라운 함수 말이다. 그래서 exp는 로그의 역함수인 고로 그 정체가 e^x인 지수함수라는 결론이 도출되고, 그래서 로그와 지수의 함수 관계가 완성될 수 있었다.

a^b = e^(b ln a)이다. ln a^b는 b ln a이므로 양변에 자연로그를 씌우면 아주 자연스럽게 유도 가능하다.

또한 굳이 밑이 e가 아닌 임의의 a인 로그를 생각하더라도, log[a] b = ln b / ln a이다. 이것은 지수보다는 약간 연상이 쉽지 않을지 모르나, 이 경우를 생각해 보자. 로그의 정의상 당연히 a^(log[a] b) = b이다. 이 식 자체에다가 자연로그를 씌우면 log[a] b * ln a = ln b가 되고, 그 후의 논리 전개는 생략. ㄲㄲ

이건 굉장히 유용한 특징이다. 이 덕분에 exp와 ln만 있으면 우리는 임의의 지수의 값도 구할 수 있고, 임의의 로그의 값도 구할 수 있게 된다.
그럼 이 함수의 값을 실제로 컴퓨터로 어떻게 계산하면 좋을까?

이걸 연구하는 분야는 기호, 순수함, 추상성만을 좋아하는 전통적인 수학에서 벗어나 일면 '지저분한 이단아'처럼 보일 수도 있는 수치해석 쪽으로 가게 된다. 컴퓨터에서 exp, ln, cos, sin 같은 기초적인 초월함수의 값을 조금이라도 더 빠르고 정확하게 구하는 기법은 이미 천재 컴덕후, 수학자, 공학자들이 연구할 대로 다 연구해서 소프트웨어 정도가 아니라 아예 하드웨어에 회로에 다 코딩되어 있을 정도이다.

그러니 내가 거기에 뭔가를 더 기여할 게 있다고 여겨지지는 않는다. 단지 본인은 핵심적인 아이디어만 직접 짜 보고 넘어갈 생각이다.
초월함수들의 근사값을 계산하는 아이디어도 미분에서 유래되었다. 단순히 1차함수 접선을 구하는 것을 넘어서 곡선과 가장 가까운 n차 근사 다항식을 구하는 것으로 생각을 확장하면 '테일러 근사 다항식'이라는 걸 구할 수 있고, 무한히 미분 가능한 함수에 대해서는 무한합인 그 이름도 유명한 테일러 급수라는 걸 유도할 수 있다.

* 이말년 씨리즈와 Taylor series는 서로 느껴지는 포스가 확 다르다. 흠.;;;

exp(x)는 예전에도 글로 썼듯이, 원론적인 정의를 이용해서 값을 구할 리는 절대 없고, 테일러 급수를 쓴다. 아래의 코드는 16항 정도까지 계산했다.

double pseudo_exp(double x)
{
    double v=1.0, p=x,q=1.0;
    for(int i=1; i<=16; i++, v+=p/q, p*=x, q*=i);
    return v;
}

단, 이 급수는 x=0인 지점을 기준으로 구한 것이기 때문에 x가 8~9 정도만 넘어가도 오차가 상당히 커진다. 하지만 컴퓨터 부동소숫점에도 한계가 있으니 항을 한없이 많이 계산할 수도 없는 노릇이고, 큰 수에 대해서는 다른 방법으로 보정이 필요할 듯하다.

한편, 로그는 어떻게 구할까?
자연로그도 다음과 같은 직관적인 형태의 테일러 급수가 있긴 하다.

ln (1+x) = x (+-) x^n/n (n이 짝수일 때는 빼기, 홀수일 때는 더하기)

그런데 이 급수는 x가 -1 초과 1 미만일 때만 유효하고, 따라서 0과 2 사이의 로그값만 구할 수 있다. 나머지 범위는 항을 제아무리 많이 계산해 줘도 아예 원천적으로 원함수와 전혀 일치하지 않게 된다. 테일러 급수가 모든 범위에 대해서 무조건 만능은 아님을 알 수 있다.

하지만 지수함수와는 달리 로그는 ln ab = ln a + ln b라고 큰 숫자를 한없이 쪼개는 마법과 같은 공식이 있다. 그러므로 저것만 있어도 아무 수의 로그라도 구할 수 있다.

즉, ln 2의 값을 미리 갖고 있다가 임의의 수에 대해서 2보다 작아질 때까지 ln 2를 따로 더하면서 계속 2로 나누면 된다. 2는 잘 알다시피 2진법을 쓰는 컴퓨터가 좋아하는 수이기도 하고 말이다. 그래서 주어진 수가 2 이하의 범위에 들어오면 그때 급수를 써서 최종적으로 구한 로그값을 또 더하면 된다.

double pseudo_ln(double x)
{
    #define LN_2  0.693147180559945
    double v=0;
    while(x>2.0) x/=2.0, v+=LN_2;

    double x_min1 = x-1, xm = x_min1;
    for(int i=1; i<=16; i++, xm*=x_min1)
    if(i&1) v+=xm/i; else v-=xm/i;
    return v;
}

단, 이 급수의 아쉬운 점은 x가 0이나 2라는 양 극단에 가까워질 때 정확도가 꽤 크게 떨어진다는 점이다. 이는 계산하는 항의 수를 충분히 크게 잡아도 쉽게 극복되지 않는다.

그래서 성능면에서 실용적인 가치는 별로-_- 없지만, ln이 exp의 역함수라는 점을 이용하여, 기존 exp 함수로부터 방정식 근 찾기 기법을 이용하여 로그를 구하는 방법도 이 기회에 실습하게 되었다. 그게 없으면 무엇보다도 초기에 정확하게 값이 구해진 채 공급되어야 하는 LN_2 내장값은 또 어떻게 구하겠는가?

일변수 방정식의 근을 찾는 기법은 수치해석 교재에서 가장 먼저 다뤄지는 기초 주제이다.
exp(x)는 기복이 없으며 그래프 모양이 워낙 예쁘고 원천적이기-_- 때문에, 근이 존재하는 초기 구간만 잡아 주면, 어떤 근 찾기 알고리즘을 쓰더라도 근을 구할 수는 있다. 단지 얼마나 빨리 수렴하여 구해 내느냐가 문제일 뿐이다. 애초에 지수 함수 정도면 범용적인 방정식 근 찾기 알고리즘이 과분하게 느껴질 정도로 특징이 너무 분명하기도 하고 말이다.

가장 먼저 나오는 것은 이분법(bisect)이다. 이게 자료구조에서는 이분법이라고 하면 이분 검색처럼 log n 시간 만에 문제를 푸는 효율적인 알고리즘이라고 불리는 반면, 수치해석에서는 정수 개의 discrete한 데이터가 아니라 사실상 연속인 구간을 다룬다. 그렇기 때문에 통상적인 이분법조차도 수렴이 느린 비효율적인 방법으로 간주된다.

double solve_bisect( double (*pfn)(double), double v )
{
    double f=-10.0, t=10.0; int nt=0;
    while(1) {
        double d = (f+t)/2.0;
        double p = pfn(d) - v;
        if(fabs(p) < 0.000001) break;
        if(p > 0) t=d; else f=d; nt++;
    }
    return f; //nt는 계산 횟수 counter
}

double pseudo_ln2(double x)
{
    return solve_bisect(pseudo_exp, x);
}

근 찾기 알고리즘 중에서는 뉴턴-랩슨(혹은 그냥 뉴턴) 법이 수렴이 매우 빠른 알고리즘으로 여겨지고 있다. 이 방법은 이분법과는 달리 시작점과 끝점이라는 구간을 잡고 시작하는 게 아니라 시작점에서 해당 방정식의 접선을 그은 뒤, 접선과 x축이 만나는(y=0) 지점을 다음 점으로 잡는다. 이 작업을 방정식의 값이 근인 0과 충분히 가까워질 때까지 반복한다.

사용자 삽입 이미지


방정식 f(x) 위의 점 (x_0, f(x_0))을 지나는 접선의 방정식은 기울기가 f'(x_0)일 테니 y=f'(x_0)*x + f(x_0) -f'(x_0)*x_0이 된다. 그래야 x에다가 x_0을 집어넣었을 때 f'(x_0) 나부랭이는 소거되고 함수값으로  f(x_0)만 남기 때문이다.
이 접선이 y=0을 만족시키는 다음 점 x_1을 방정식으로 풀면 x_1=x_0 - f(x_0)/f'(x_0)이라는 생각보다 깔끔한 식이 나온다. 이를 코딩하면,

double solve_newton( double (*pfn)(double), double (*pfn_prime)(double), double v )
{
    double d = 0.0; int nt=0;
    while(1) {
        double p = pfn(d) - v;
        if(fabs(p) < 0.000001) break;
        d = d - p / pfn_prime(d); nt++;
    }
    return d;
}

double pseudo_ln3(double x)
{
    return solve_newton(pseudo_exp, pseudo_exp, x);
}

뉴턴 법 함수는 도함수의 포인터를 별도로 받는데, exp는 어차피 도함수가 자신과 동일하므로 자신을 한번 더 넘겨주면 된다는 점도 특징이다.

프로그램을 실제로 돌려 보면 알겠지만, 동일 오차 범위를 줬을 때 뉴턴 법은 이분법보다 통상 2~5배나 더 빨리 수렴하는 걸 볼 수 있다. 마치 퀵 정렬이 pivot을 기준으로 자료가 그럭저럭 이미 정렬돼 있을수록 더욱 빨리 동작하고 자료의 상태에 민감하듯, 뉴턴 법은 접선과 가까운 형태의 부드러운 곡선일수록 수렴이 더욱 빨라진다.

자, 지금까지 공대 학부 수준의 아주 허접한 수학 덕질을 감각 유지 차원에서 잠시 복습해 보았다. 각종 공식들이 유도되는 원리를 좀 더 깊이 생각해 보고 싶으나 시간과 여유가 부족하다.

아, 수학에서는 거듭제곱뿐만이 아니라 팩토리얼까지도 자연수가 아닌 실수, 그리고 복소수 범위에까지 정의하고 그 증가폭을 측정하는 방법에 대해 연구가 진행돼 있다. 그 일환으로 ln n!이 n log n - n과 얼추 비슷하다는 스털링의 공식이 있고, 그보다 더 괴랄한 감마 함수라는 것도 있어서 z! = Γ(z+1)이다. 머리 좋은 똘똘이들의 수학 덕질의 끝은 도대체 어디까지인지를 다시 생각하게 된다.

Posted by 사무엘

2012/09/10 19:32 2012/09/10 19:32
, , , , ,
Response
No Trackback , 2 Comments
RSS :
http://moogi.new21.org/tc/rss/response/731

※ 셸 프로그램

명령 프롬프트 하나만 달랑 떠 있는 게 아니라 최소한의 GUI를 갖춘 컴퓨터 운영체제에는 셸이라는 게 존재하며, 그 셸을 구동하는 역할을 하는 프로그램이 있다. 그것이 맥 OS는 Finder이고, 윈도우는 95 버전 이래로 Explorer(탐색기)가 셸 역할을 하고 있다.
리눅스는 저 두 상업용 OS만치 셸과 커널이 일심동체인 형태가 아니기 때문에, 딱 떨어지는 단일 셸 브랜드가 없다.

95 이전 3.x 시절에 윈도우 운영체제의 셸은 도스 계열과 NT 계열 모두 그 이름도 유명한 '프로그램 관리자'(ProgMan.exe)라는 MDI 프로그램이었다. 알록달록한 32*32 크기의 16색 프로그램 아이콘들은 초등학생이던 본인에게 굉장히 아름다운 기억으로 남아 있다.

하지만 잘 알다시피 프로그램 관리자는 운영체제의 셸로서는 그리 잘 만들어진 프로그램이 아니었다. 기능이 무척 빈약하고 이것 자체도 여러 프로그램들 중 하나일 뿐, 운영체제 전체를 아우른다는 느낌을 사용자에게 못 줬다. 그룹 안에 다단계 그룹도 못 만들었고..-_-;;
또한 범용적인 파일 관리 유틸리티 기능이 전무했기 때문에 이건 또 '파일 관리자'라는 별도의 프로그램을 통해서 해야만 했다.

게다가 윈도우는 win.ini라는 환경 설정 파일에서 [boot] 섹션에 있는 shell=progman.exe라는 문장을 다른 것으로 고치면, 전통적인 프로그램 관리자 대신에 다른 것으로 셸 프로그램을 손쉽게 대체할 수 있었다.

그래서 윈도우 3.x는 프로그램 관리자를 대체하는 별도의 셸 유틸리티가 존재하기도 했다. 시작 메뉴, 내 컴퓨터, 탐색기 등을 통해 운영체제의 셸로서 explorer.exe의 지위가 확고해진 오늘날에는 이것은 꽤나 상상하기 힘든 모습이다.

당장 떠오르는 건 20여 년 전에 명성을 떨쳤던 Norton Desktop이라는 프로그램이다. 그 당시 도스용 노턴 유틸리티는 버전이 6~7 사이였고 노턴 커맨더라는 도스용 셸도 현역이었는데, 그 회사에서는 한편으로 윈도우용으로도 그런 걸출한 프로그램을 만들었다.

노턴 데스크탑은 화면 보호기도 자체적으로 운영하고 모든 프로그램들의 시스템 메뉴에다 특수한 기능을 추가하기도 했으며, 독자적인 바탕 화면을 구동하면서 윈도우 3.x를 전반적으로 매킨토시와 비슷한 형태로 만들어 줬다. 16비트 윈도우는 오늘날의 운영체제보다는 한 프로그램이 시스템 전체에 영향을 끼치가 훨씬 더 쉽기도 했으니 말이다.

※ 한컴 셸과 윈도우용 아래아한글 초창기 버전

국내에서는 1990년대 중반에 한컴에서 '한컴 셸'이라는 프로그램을 개발한 적이 있다. 화면의 한쪽 귀퉁이에 여러 프로그램들의 아이콘이 나열되는 게 마치 오늘날 맥 OS의 Dock과 비슷했다. 이것으로 기존 프로그램 그룹/폴더에 접근이 가능하고 제어판이나 탐색기도 띄우고, 운영체제를 종료할 수도 있었기 때문에 이것만 있으면 다른 셸 프로그램이 필요하지 않았다.

사용자 삽입 이미지

사진은 아래아한글 3.0b 기준이지만, 내 기억으로 아래아한글 97에도 한컴 셸이 있었다. 윈도우 95/NT4의 셸에 더 친화적인 기능들이 추가되고 버튼들도 90년대 말의 유행이던 flat 스타일로 바뀌었다. (마우스 포인터가 가리키고 있는 버튼에만 3D 테두리가 얇게 생기는 그 형태)

그런데 이 역시 97 초기판에만 있었고, 8· 15 특별판(1998)이나 국제판/기능 강화판(1999)에서는 사라졌다. 윈도우 9x 이래로 탐색기 셸 자체가 기능이 굉장히 강력해졌기 때문에 그때부터는 별도의 셸 유틸리티에 대한 수요와 의미가 없어졌기 때문일 것이다. 특히 IE4와 통합을 이루면서 윈도우 운영체제의 셸은 완전히 환골탈태를 했으니 말이다.

아마 아래아한글 3.0b나 기껏해야 96까지만 해당일 것이다.
그 당시 이 프로그램에는 한컴 셸 동반용으로 추정되는 나침반, 시계, 계산기처럼 워드 프로세서와 직접적인 관계가 없는 액세서리 프로그램도 포함돼 있었다. 지금의 운영체제에서는 제대로 실행이 안 되는 듯한데, 예전에 분명히 돌려 봤던 기억이 난다.

시간이 흐르면서 그런 것들은 거의 다 역사 속으로 사라졌다. 그나마 21세기에까지 장수한 보조 유틸리티는 아래아한글 97과 함께 도입된 '한컴 쪽지'가 유일하다. 그것도 윈도우 7부터는 스티커 메모라는 대체 프로그램이 운영체제 차원에서 생겼으니 필요가 없어진 상태.

옛날에 윈도우용 아래아한글 3.0은 Windows에서도 도도하게 완전 독자적인 GUI와 독자적인 GUI 글꼴, 독자적인 문자 입출력 체계를 쓴 데다, 기술적으로도 Win32s + 별도의 메모리 서버까지 요구하는 등 군계일학 유아독존 포스가 압권이었다.

도스용 아래아한글만 만들던 개발팀이 단기간에 프로그래밍 공부를 얼마나 해야 윈도우 운영체제의 구조를 완전히 마스터하여 방대한 도스용 프로그램을 윈도우용으로 그것도 그런 기술 수준으로 포팅할 수 있었을까? 혹시 공밀레?

이때는 한컴이 금방이라도 독자적인 운영체제를 새로 만들기라도 할 것처럼 보였다. 사실, 비슷한 타이밍 때 나왔던 큰사람의 이야기 7.0 도스용도 도움말을 잘 뒤져 보면 개발팀이 한국형 32비트 운영체제를 자체 개발하겠다는 포부를 밝힌 대목이 있었다. 지금 생각하면 그때 사람들이 참 순진/순수했던 것 같다.. ^^

물론, 윈도우용이 처음 나왔던 3.0, 그리고 에디팅 엔진을 다 갈아엎었던 워디안 때 아래아한글이 버그 때문에 정말 욕을 많이 얻어먹은 건 사실이다. 까일 건 까여야 마땅하지만 그 첫 삽을 뜨기가 얼마나 힘들고 어려웠을지 본인은 프로그래머로서 이해는 한다.

아, 아래아한글 3.0x가 사용했던 그 특유의 GUI 디자인은 이미 아시는 분도 있겠지만 NeXTSTEP에서 따 온 것이다. 아이폰이 나오기 훨씬 전부터 아래아한글이 나름 스티브 잡스 진영에서 만든 디자인을 수용한 적이 있다는 뜻 되겠다. 다만, 메뉴에 카테고리를 구분하는 separator가 없던 것은 좋은 디자인이 아닌 것 같다.

사용자 삽입 이미지사용자 삽입 이미지

그리고 대화상자의 GUI 컨트롤 중엔, 콤보 상자와 용도가 비슷하지만 콤보 상자보다 더 static하면서 개수가 그리 많지 않은 컨텐츠 중 하나를 선택할 수 있는 '콤보 버튼'이 있다. 예를 들어 글꼴 리스트는 사용자의 컴퓨터에 설치된 글꼴이 무엇이냐에 따라서 dynamic하게 바뀔 수 있지만, 워드 프로세서가 제공하는 문단 정렬 방식 '왼쪽, 중앙, 오른쪽, 혼합' 같은 것은 수가 그리 많지 않으면서 내용이 절대 고정불변이지 않은가. 그런 것을 선택할 수 있다.

또한 스크롤 막대의 좌우, 상하 버튼이 한데 붙어 있는 것도 이 GUI의 특징 중 하나이다.

사용자 삽입 이미지

※ 여담

하긴, 도스 시절에도 셸 유틸리티가 당연히 있었다. 이때의 셸은 윈도우처럼 초보자들을 위한 GUI 기능을 강화한 놈, 아니면 파일 관리 유틸리티에 더 특화된 놈으로 나뉘었다. 후자에 속하는 것이 바로 노턴 커맨더나 MDIR 같은 유명한 프로그램임.

도스 시절에는 아무래도 컴에 대한 접근성이 지금보다는 다소 떨어졌으며, 그래픽 셸을 찾아 쓸 정도의 사람이라면 이미 그래픽 셸이 필요치 않은 파워 유저였다. 그렇기 때문에 도스용 셸 유틸은 GUI보다는 아무래도 매니악한 파일 관리 기능 특화로 더 가는 경향이 있었다.

사실, MS-DOS 자체도 한 4.0부턴가 5.0부터 도스 셸이라는 잉여에 가까운 파일 관리 유틸리티가 있었다. 그냥 밋밋한 UI에 기능도 평범한 편이지만 나름 드래그 드롭 기능이 있었으며, 그리고 하드디스크에 존재하는 모든 파일들을 한 리스트로 뽑아 주는 기능은 윈도우 파일 관리자에도 없고 이놈만의 전매특허였다. 물론, 이건 하드디스크 전체에 존재하는 파일 수가 수천~수만 정도에 불과했던 옛날이니까 가능했던 일이다.

이런 맥락을 이어받아 오늘날의 GUI 시대에도, 비록 운영체제의 기본 셸을 대체하려는 프로그램은 맥이 끊어졌지만, 전문 파일 관리 유틸리티는 건재하다. 토탈 커맨더라든가 넥서스 파일 같은 프로그램이 있다. 여러 단축키를 통해 기본 셸 프로그램보다 원하는 프로그램이나 파일, 폴더에 훨씬 더 빨리 접근할 수 있고, 한 프로그램 안에서 압축 파일도 쉽게 다루고 FTP 연계도 되는 편리한 기능에 대한 수요가 없지 않기 때문이다.

끝으로, 옛날 글들을 보면 알 수 있듯, 난 한동안은 shell을 '쉘'이라고 표기해 왔다. 도스 시절부터 프로그램이나 PC 잡지들이 다 그렇게 표기했기 때문이다. 그때 쉘 대신 셸을 쓴 프로그램은 한글 MS-DOS가 제공하던 '도스 셸'밖에 없었다. 진짜 그거 딱 하나밖에 못 봤다.
그랬는데, 외래어 표기법상 '셸'이 맞다고 하니 이 글부터 시작해서 앞으로는 셸을 쓰도록 하겠다. 틀렸으면 고치면 되지. ㅎㅎ

Posted by 사무엘

2012/09/08 08:21 2012/09/08 08:21
, ,
Response
No Trackback , 5 Comments
RSS :
http://moogi.new21.org/tc/rss/response/730

지난 8월말에 잘 알다시피 <날개셋> 한글 입력기 6.7이 완성되고 공개됐다. 내가 만들었지만 나 자신도 잘 쓰고 있다. 의미심장한 중요한 기능들이 많이 추가되어 아주 만족스럽다.

프로그램의 한 버전이 완성된 후, 조금 시간이 흐르면 버그 수정이나 새로운 아이디어 구현, 기능 추가를 위해서 결국 프로그램 소스를 또 건드리게 되고, 내가 쓰는 개발 중간 버전과 직전 완성 버전 사이에는 차이가 생기게 된다. 그 첫 차이가 생기기까지 걸리는 시간은 생각보다 길지 않다.

이번 6.7도 그 점에서는 예외가 아니다. 벌써 다음 버전 작업이 시작되었다. 프로그램 내부의 버그가 발견되었거나 새로운 기능이 떠오른 건 아니고, 단지 운영체제의 특성과 관련된 enhancement가 불가피하게 생기게 됐다. 그 내역은 다음과 같다.

1. 테마가 적용된 옅은 파랑 선택막대

<날개셋> 한글 입력기의 외부 모듈에서 한자 선택 UI를 꺼내면 외형이 윈도우 7 기준으로 지금까지(up to 6.7)는 왼쪽과 같았다. 그렇던 것을 다음 버전부터는 오른쪽처럼 나오게 수정했다.

사용자 삽입 이미지

highlight 색상이 너무 옅었던 것을 좀 더 진하게 하고, 아이템의 크기를 약간 더 키웠다. 예전보다 보기가 훨씬 더 좋아졌다. 크기를 약간 키웠는데도 MS IME의 목록이 <날개셋>의 그것보다 여전히 더 크다.

잘 알다시피 MS에서는 소프트웨어의 GUI에서 highlight된 항목을 표시하는 방법을 슬금슬금 교체해 오고 있다.
전통적인 방법은 파란 바탕 solid color에다가 하양 글씨였다. 그 이름도 유명한 GetSysColor(COLOR_HIGHLIGHT) 말이다. 아니면, 컨텐츠 자체에 여러 색깔이 서식 형태로 들어갈 수 있는 워드 프로세서 같은 곳에서 블록 같은 걸 표시하는 방법은 흰 바탕을 검정으로 바꾸는 XOR 반전색이 통용되어 왔다.

그러나 요즘 MS에서 밀고 있는 방법은 배경에다 그냥 옅은 파랑을 씌우는 것이다. 이 기법의 원조는 사실 MS 오피스 2000의 '엑셀'로 생각보다 오래 됐지만, 워드에서까지 블록이 전통적인 반전색 대신 옅은 파랑으로  표시되기 시작한 건 오피스 2007부터이다.

윈도우 XP부터는 리스트 컨트롤에서 드래그 사각형을 점선 사각형 대신 옅은 파랑으로 대체하는 LVS_EX_DOUBLEBUFFER 스타일을 도입하였으며, 비스타부터는 메뉴와 운영체제의 공용 컨트롤(리스트 뷰, 트리)에서 선택 막대까지 반전색 대신 알록달록 옅은 파랑 그러데이션이 도입되었다.

그리고 이 테마 색상은 운영체제의 시스템 색상의 영향을 받지 않는다.
Aero를 사용 중일 때에는 잘 알다시피 GPU가 합성해 내는 glass 프레임의 색깔만 바꿀 수 있지, 기존 시스템 색상은 바뀌지 않는다. 어찌 보면 시스템 색상도 점점 과거의 유물처럼 돼 간다는 뜻 되겠다.

그런데 본인은 그 옅은 파랑이 윈도우 비스타나 7이나 동일한 줄로 지금까지 알고 있었는데, 그렇지 않다. 똑같은 Aero 기반이지만 비스타가 약~간 더 옥색에 가까웠고 7이 좀 더 파래졌다.

또한 그 색상도 알고 보면 짙고 옅은 구분이 존재한다. 7은 옅은 색과 짙은 색의 차이가 비스타 시절보다 더 커졌다(위 그림에서 왼쪽의 상하 한 쌍이 비스타 것,, 오른쪽의 한 쌍은 7 것). 그래서 이를 조정함으로써 이제는 비스타와 7에서 모두 보기 좋은 색상이 나오게 되었다. 지금까지 사용하던 채색 방법은 비스타에서는 어차피 별 차이가 없던 반면, 7에서는 너무 옅게 나온다는 문제가 있었다.

2. 윈도우 8 지원

시기가 시기인 만큼 <날개셋> 한글 입력기의 다음 버전은 여건이 허락하는 한 윈도우 8의 지원 강화가 계획되어 있다.
<날개셋>은 지금까지 윈도우 2000에서 발생하는 특수한 문제 해결(아직 윈98이 대세이던 시절), 외부 모듈 첫 개발, 64비트 지원 등 외부적인 큰 환경 변화를 몇 차례 대면했었는데, 윈도우 8 지원도 상당히 도전적인 과업이 될 것 같다.

우선, 윈도우 8을 접한 소감부터 좀 말하자면, 이제 얘들은 XP, 비스타 같은 이름을 일일이 짓기가 귀찮아졌는지, 연도도 아니고 숫자를 버전과 아무 관계 없는 브랜드명으로 쓰기로 작정을 한 모양이다. 윈8의 내부 버전은 6.2이다. (비스타가 6.0, 7은 6.1)

GUI가 동글동글하던 것이 전반적으로 다시 각진 컨셉으로 바뀌고, 그러데이션이 단색(solid color)으로 바뀌는 등, 좀 더 검소해지고 단순해졌다(simplify). 의외이다.

컴덕후라면 이미 익히 알듯이 데스크톱 모드에 이어 메트로 모드라는 게 생겼으며, 메트로 모드는 확실히 과거와의 호환성을 버리고 좀 더 '새끈하고' 스마트폰 앱과 더 친화적인 응용 프로그램 환경을 추구한 듯하다.
근데 데스크톱 모드에 도대체 시작 버튼을 무슨 생각으로 없애 버렸는지는 잘 모르겠다.

윈8에서는 문자 입력기 쪽 인터페이스가 완전히 바뀌는 바람에 기존 한글 IME들은 메트로 모드에서는 동작하지 않으며, 데스크톱 모드에서도 기존 IME 도구모음줄(language bar)가 누락된 채 거의 반쪽짜리 상태로 동작한다. 특히 메트로 모드에서 동작하려면 IME 프로그램이 반드시 디지털 서명이 돼 있어야 한다고 그런다.

무엇보다 심각한 문제는, 기존 API로는 운영체제에 설치되어 있는 IME 프로그램들이 전혀 조회가 되지 않는다는 점이다. 또한 상태 표시 아이콘 쪽도 알다시피 크게 바뀌었기 때문에 이에 대한 대처를 하려면 적지 않은 시간과 수고가 필요할 것 같다.

세벌식 파워업은 수동으로 두벌/세벌 전환을 한번 해 준 뒤에 돌리면 자동 글자판 전환이 다행히 잘 된다. 그러나 IME 설정 대화상자를 꺼내기가 굉장히 불편해졌는데(일일이 제어판으로 들어가야 함. 예전처럼 우클릭만으로 되지 않는다) IME 설정 대화상자를 곧바로 꺼내는 기능이 동작하지 않기 때문에 이에 대한 패치는 해야겠다.

이렇듯, 프로그램 자체의 기능과는 전혀 무관하게 프로그램을 또 고쳐야 할 부분이 몇 군데 생겼다. 그러나 이번 6.7은 그것만 빼면 현재까지는 여전히 버그가 발견된 게 없고 최고의 완성도로 만들어져 있다..

참고로 윈8은 명령 프롬프트에서 '다다.' 글자가 덧나는 버그는 고쳐져 있었다. 그리고 모든 프로세스에서 사용 중인 IME의 종류와 상태가 한데 공유된다! IME가 각 프로세스의 스레드별로 따로 기어들어가는 게 아니라, 별도의 전용 프로세스를 통해 IPC를 써서 응용 프로그램들과 소통하는 것 같다!

※ 여담

- 난 내 컴퓨터로 서식이 없는 글을 쓸 때 무슨 프로그램을 써서 할지가 고민된다.
일단 윈도우에서는 내가 만든 <날개셋> 편집기가 심리적으로 마치 우리집 안방에 있는 것 같은 편안함과 가벼움을 선사한다. 정다운(?) 비트맵 글꼴과 화려하기 그지없는 고급 입력 기능들을 그대로 쓸 수 있으니 이것도 좋다.

한편, 맥 OS의 텍스트 편집기는 비록 한글 입력기의 자유도는 뒤쳐지는 반면, 찍히는 글꼴의 품질이 윈도우와는 넘사벽급으로 차이가 나고 너무 우수하니 이 또한 글 쓰는 즐거움을 선사하는 요인이다.
두 장점을 하나로 합치려면 결국 <날개셋> 한글 입력기가 맥용으로도 나와야 할 텐데 말이다.;;

- 요즘 모바일용 입력 방식 중에는 그냥 버튼을 눌렀다 떼는 게 아니라 특정 제스처를 취했을 때 초성과 중성이 동시에 입력되게 되어 있는 한글 입력 방식이 있다. 이런 로직을 <날개셋> 한글 입력기로 구현하는 건 일도 아니다. 날개셋문자는 애초에 여러 낱자를 한꺼번에 배당을 할 수 있는 구조이기 때문이다. 그걸 글쇠 수가 충분한 편인 PC 키보드에서는 잘 활용을 안 할 뿐.

'가'를 ㄱ+ㅏ로 입력했을 때와 한꺼번에 입력했을 때 종성의 조합 여부를 달리 지정하는 것도 가능하다. 오토마타가 통상 A ? 1: B ? .. 같은 식으로 지정되어 있는 것을 A && B ? 라고 하여 동시 입력 여부에 대한 상태 분기도 직접 지정하면 되기 때문이다. 어지간한 변칙적인 한글 입력 방식에 대한 대비는 <날개셋>이 다 해 놓고 있다.

그렇기 때문에 본인은 어떤 새로운 한글 입력 방식이 있으면 그게 손이 편하냐, 빨리 칠 수 있냐 하는 것보다는 그 입력 방식을 구성하는 기본 동작과 로직이 어떠한지를 보는 편이다. 그게 나의 연구 주제이기 때문이다.

- <날개셋> 한글 입력기의 다음 버전은 6.x대의 마지막 버전이 될 것이다. 이 글에서 언급된 이슈 말고 또 무슨 변화가 생길지는 아직 미지수이다.

그런데 개인적으로 난 윈8은 너무 급격한 변화들 때문에 비스타 꼴 날 것 같은 생각이 든다. -_-;; 왜 자꾸 익숙한 UI를 쓸데없이 바꾸고, 게다가 보안을 빌미로 응용 프로그램 실행엔 번거로운 제약만 자꾸 추가하는지 모르겠다. 2000/ME와 비스타가 망하고 XP와 7이 무진장 장수했는데, 8은 아무래도 오른쪽보다는 왼쪽 계열로 갈 것 같다.

Posted by 사무엘

2012/09/05 19:35 2012/09/05 19:35
,
Response
No Trackback , 15 Comments
RSS :
http://moogi.new21.org/tc/rss/response/729

학위 수여식 (2012/8/31)

사용자 삽입 이미지
학부를 졸업한 지 어언 7년이 지난 뒤에야 후드가 걸쳐진 졸업 가운이라는 걸 입게 됐다. 주황색은 공학을 뜻한다. (학사용 졸업 가운은 후드가 없음.)

학사는 성적이 중요하니 최우등/우등 졸업이라는 게 있다. 박사는 시험 점수 따위를 초월하여 개개인이 이제 자기 분야에서 프로 연구자이니, 졸업자들이 모두 호명되고 학위 논문의 제목까지 유인물에 다 기재된다.
그 반면, 석사는 둘 중 어느 것에도 속하지 않는 콩라인이다.

태풍 직후, 날씨가 최강 좋았다. 맑고 파란 하늘 덕분에 사진 찍기는 최고의 날씨였다.
괜히 Y대 아니랄까봐, 학위수여식은 찬송가 제창과 성경 봉독으로 시작해서 축도로 끝났다.
혼자 예상한 것보다 좀 더 오버하듯이 씨익~ 웃어야 사진이 더 밝고 명랑한 표정으로 나온다는 걸 느꼈다.

내가 전형적인 내 학부 학교 출신들이 가지 않는 학교와 과로 대학원 진학을 하고, 남들은 박사까지 다 마칠 나이에 이제 겨우 석사를 마친 건 정말 어쩔 수 없는 귀결이다. 남들이 전혀 관심을 갖지 않는 분야에 없는 진로를 만들면서 가고 있어서..;;

Posted by 사무엘

2012/09/03 19:20 2012/09/03 19:20
, , ,
Response
No Trackback , 11 Comments
RSS :
http://moogi.new21.org/tc/rss/response/728

사용자 삽입 이미지

- (1) 부대내의 박물관 관람 → (2) 천안함 잔해 구경 → (3) 초청자가 현재 근무하고 있는 군함 구경 → (4) 초청자의 관사에서 식사 대접 받으며 교제 순의 코스였다. 옆에 같이 간 사람들은 모두 교회 사람들. 단순 안보 관광인 (1), (2)를 넘어 (3), (4)는 군 관계자 인맥이 없으면 경험하기 쉽지 않을 것이다.

- 나의 “천하의 개쌍놈 북한” 관념이 이 견학을 계기로 더욱 투철해졌다. 정정당당한 교전으로는 남한을 이길 수 없어지니 치밀하게 비열한 복수극을 계획한 나쁜 놈들. 늘 민족 동족 운운하면서 뒤로는 일본 이상으로 나쁜짓을 해 온 녀석들이다.

- 제2 연평해전 당시에 교전 수칙 때문에 대통령이 많이 까였었다. 그런데 그것보다도 내가 더 이해를 할 수 없는 건 당시 제1 연평해전을 승리로 이끈 지휘관인 박 정선 제독을 나라에서는 (사실상) 좌천 발령시키고 이내 전역시켜버렸다는 사실. 100번 까여야 마땅하다. 어디에서 주장하는 것처럼 이건 북한의 요구대로 한 게 정말 사실인가?

- 제2 연평해전 전사자 영결식이던가 그때 대통령이 안 온 것에 대해서, 기지 견학을 시켜 준 해군 관계자는 아직까지도 꽤 유감스러워하는 표정이었다.

- 제주 해군 기지 건설에도 배후에 그렇게 깊은 뜻이 있는 줄 처음 알았다.

- 육군은 닥치고 쪽수이고, 공군은 1인 1비행기인 전투기 파일럿만 빼면 대부분이 비전투 병과인 반면, 해군은 배가 생활 공간 겸 그대로 전장이다 보니 그 중간에 속하는 군대 문화를 갖추고 있다. 대한민국은 수출에 목숨 걸어야 하고 바다 없이는 못 사는 나라인 주제에, 해군에 대한 지원이 너무 열악하다고 한다.

- 군함에는 내연기관과 제트엔진이 모두 달려 있다고 한다. 이것도 자동차와 비행기의 중간인 셈인데, 제트엔진을 가동하면 무척 빨리 움직일 수 있지만 극심한 소음과 연료 소모를 감수해야 한다고. 그런데 둘은 사용하는 연료부터가 서로 다르지 않나? (중유 vs 등유)

- 평택 시내의 경부 고속선 고가를 달리는 KTX를 보니 정말 감격스러웠다.

- 우리나라 철도를 공부하면서 단련된 나의 우리나라 역사, 지리, 안보 지식은 군 관계자와 얘기를 나누면서도 유감없이 발휘되었다. 철도님, 사랑합니다.

- 이런 곳에 신실한 KJV 빌리버 크리스천이 계셔서 성경 교제와 안보 관광을 동시에 하고 올 줄이야. 친절하게 군 시설을 안내하고 융숭한 대접을 해 주신 해군 관계자들께 감사드린다.

Posted by 사무엘

2012/09/01 19:34 2012/09/01 19:34
, , , ,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/727

1. conime가 conhost로

윈도우 NT 계열 운영체제에는 전통적으로 시스템 디렉터리에 conime.exe라는 자그마한 프로세스가 있었다.
이 프로그램의 타이틀은 Console IME로, 말 그대로 명령 프롬프트(콘솔이라고 불리는)라는 특수한 환경에서 한글이나 일본어의 입력을 지원하기 위해 운영체제와 명령 프롬프트 사이의 통신을 담당하는 듯하다.

conime는 명령 프롬프트를 여러 개 연다고 여러 인스턴스가 중복 실행되지는 않는다. 하지만 한번 실행되고 나면 나중에 명령 프롬프트를 모두 닫아도 종료되지 않고 남아 있는다. 그래서 명령 프롬프트에서 <날개셋> 한글 입력기를 사용하다가 나중에 <날개셋>을 버전업/제거한다거나 하면 conime 프로세스를 강제 종료시켜야 한다고 설치 프로그램이 징징대는 걸 볼 수 있다.

뭐, 작업 관리자로 이 프로세스를 강제 종료시키더라도 운영체제에 악영향은 (전혀) 없다. 나중에 명령 프롬프트를 열면 운영체제가 그걸 알아서 또 실행해 준다.

그런데 윈도우 7에서는 시스템 프로세스 중에 conime.exe가 사라졌다는 걸 본인은 아주 뒤늦게 확인했다. 명령 프롬프트에다 IME 기반 문자 입력을 제공하는 계층이 다른 걸로 바뀌었다는 뜻인데, 어쩌면 이런 변화 때문에 콘솔에서 조합 중인 한글이 덧나는 버그('다다.' 같은)도 덩달아 들어간 게 아닌가 하는 추측도 할 수 있을 것 같다.

관찰해 보니, 윈도우 7에서 콘솔과 관련하여 대신 등장한 프로세스는 conhost.exe이다. 콘솔에서 <날개셋> 한글 입력기를 사용하고 있는 채로 해당 프로그램을 제거하거나 변경하려고 시도하면 conhost 때문에 안 된다는 경고가 뜬다.

그럼 conhost는 cmd.exe 자체와 일대일 대응하는 자매 프로세스냐 하면 꼭 그렇지는 않다.
명령 프롬프트에서 또 cmd라고 치면 그 동일한 창 안에서 명령 프롬프트가 또 구동되는데(exit를 치면 종료 가능한), 이때는 conhost가 또 생기지는 않는다. start cmd라고 쳐서 독립된 콘솔 창이 생성되어야 conhost도 중첩 생성된다. 관계가 이해되시겠는가?

conime와는 달리, 이놈은 명령 프롬프트 창의 인스턴스와 일대일 대응하고, 창이 닫히면 이 프로세스도 종료되어서 IME 프로그램 파일에 걸렸던 lock이 풀린다. 예전에는 콘솔 디버깅 후에는 conime를 강제로 죽여 줘야 했는데 윈7에서는 그럴 필요가 없어진 건 편해진 점이다.

2. 윈도우 7의 kernel32.dll 리모델링

이뿐만이 아니라, 윈도우 운영체제의 시스템 프로그래밍 내지 파일 해킹에 관심이 많은 분이라면 윈도우 7의 under the hood에서 일어난 흥미로운 변화를 하나 알고 있을 것이다.
운영체제의 근간을 이루는 시스템 DLL 중 하나인 kernel32.dll이 내부적으로 여러 분야로 리모델링을 거치기 시작했다는 점이다.

시스템 디렉터리에 가 보면 api-ms-win-core-*.dll이라는 수십여 개의 DLL들이 보일 것이다.
이것들은 kernel32.dll이 제공하는 1000개가 넘는 윈도우 API를 스레드, 힙 메모리, 동기화 오브젝트, 파이프 등으로 세부 분류한 껍데기들이다.

전통적으로 kernel32.dll은 윈도우 9x 계열의 것은 100% 순수 자체 코드로만 이뤄져서 그런지 외부 DLL에 의존하는 게 아무것도 없었다.
NT 계열의 것은 운영체제 커널보다 먼저 로딩되는 ntdll.dll에만 의존도가 있었다. 그리고 그 ntdll이 외부 DLL에 전혀 의존하지 않는 원초 프로그램이었다.

영원무궁토록 변하지 않을 것 같은 kernel32.dll의 내부 구조가 윈도우 7에서 이렇게 바뀐 걸 처음 봤을 땐 무척 흥미로움을 느꼈다.
지금은 그냥 뭔가 더 큰 변화를 위한 준비 수준일 뿐인 것 같은데, 윈도우 8에서는 변화가 얼마나 더 진행될지가 궁금하다.

3. 콘솔의 시각 테마 적용

윈도우 7로 넘어가면서 콘솔에 미묘하게 생긴 재미있는 변화가 또 있다.
전통적으로 명령 프롬프트 창은 윈도우 XP에서부터 도입된 '시각 스타일', 혹은 시각 테마가 적용되지 않는 딱딱한 창으로 처리되었다.

물론, 공용 컨트롤 6.0 매니페스트가 명시되어 있지 않은 구형 프로그램은 각종 컨트롤이나 child window의 테두리가 구닥다리 고전 테마로 나오긴 했지만, 그래도 프로그램의 제목 표시줄 같은 non-client 영역은 모서리가 둥글게 다듬어지기도 하고 최소한의 시각 테마가 자동으로 적용되었다.

그런데 명령 프롬프트는 그런 게 전혀 없이 완전 사각형 모양에 제목도 여전히 윈도우 98/2000식의 그러데이션이고 100% 고전 테마 스타일로 나왔다.
이렇게 100% 구닥다리로 뜨는 프로그램은 (1) 명령 프롬프트, (2) ntvdm 밑에서 돌아가는 16비트 윈도우 프로그램, 그리고 (3) 사용자가 호환성 옵션에서 '시각 테마 사용 안 함' 옵션을 명시한 프로그램 이렇게 세 종류로 한정되곤 했다.

윈도우 비스타/7의 Aero를 사용하면 100% 구닥다리 프로그램도 제목 표시줄이나 창 프레임 자체는 다른 창과 똑같은 형태로 나오기 때문에 이를 구분하기가 쉽지 않다. 고전 테마 말고 Basic 테마를 고르면 한눈에 구분이 가능해진다. 이게 과거의 윈도우 XP Luna와 기술 수준이 동일한 테마이기 때문이다.

그랬는데 윈도우 7부터는 (1) 명령 프롬프트 창도 시각 테마가 적용되는 창으로 바뀌었다. (2)에 해당하는 16비트 윈도우 프로그램은 64비트 운영체제에서는 아예 존재하지도 않으니, 남은 건 이제 (3)뿐이다.

윈도우 비스타/7이 제공하는 한국어/일본어 입력기는 그렇게 시각 테마 열외 프로그램 밑에서 동작하면 가/A, 漢 같은 아이콘이 흰색이 아닌 검은색으로 표시된다. 고전 테마가 아니라 Basic이나 Aero 같은 일반 테마에서 동작할 때 말이다.
본인은 한글 IME의 개발자로서 그 차이를 눈여겨보고 있었고, 그냥 얘네들이 명령 프롬프트에서 동작할 때만 아이콘 글자색을 검게 처리하는가 보다 하고 넘어갔었다.

그랬는데 윈도우 7에서는 명령 프롬프트에서도 글자색이 변하지 않았고, 이에 의문을 느껴 좀 더 관찰을 해 보니 차이를 만드는 요인은 '시각 테마'의 적용 여부라는 사실을 발견하게 되었다.
왜 일부러 그런 차이를 만들었는지는 나로서는 알 길이 없다. 문자 입력기가 응용 프로그램의 시각 테마 적용 여부에 따라 달리 동작해야 할 요인이 있을 리도 없을 텐데 말이다.

자, 다음 그림은 Basic 테마일 때 윈도우 비스타의 명령 프롬프트 화면과 7의 명령 프롬프트 화면이다. 창 프레임의 모양과 입력기 도구모음줄 아이콘의 색깔에 차이를 주목하시길. 내가 지금까지 설명한 것들이 이해가 될 것이다.

사용자 삽입 이미지사용자 삽입 이미지

4. 도스에서 명령 프롬프트로의 변화

윈도우 9x 계열이야 전용 명령 프롬프트 터미널이라는 게 없이 도스창이 명령 프롬프트의 역할도 겸해 왔다. 그리고 거기서는 아예 도스용 한글 바이오스 프로그램이 따로 쓰이니 conime 같은 컴포넌트는 필요하지 않다.

사실, 16비트 윈도우 시절에 운영체제가 쓰던 전용 실행 파일 포맷(New Executable)은 GUI 환경 전용이었지, 콘솔용은 있지도 않았다. 어차피 똑같은 16비트 기반이고 윈도우 운영체제 자체가 파일 접근 같은 요청은 여전히 도스에다 요청을 해서 처리를 하고 있었으니, 콘솔용 실행 파일을 따로 만드는 건 아무 의미가 없고 필요하지도 않았다.

사실, 매킨토시와는 달리 윈도우 계열 OS에만 존재하는 독특한 ANSI/OEM 인코딩, 코드 페이지 같은 개념은 그 기원을 도스의 명령 프롬프트에서 찾을 수 있을 것이다. 걔네들은 원래 철저하게 1바이트 기반 인코딩을 썼었기 때문이다. 그에 반해 매킨토시는 시작부터가 명령 프롬프트가 전혀 없는 GUI였으니 그런 잔재가 없는 셈일 테고.

5. 윈도우 운영체제의 문자 입력 관련 보조 프로세스

처음에 얘기가 나왔던 conime.exe처럼, Windows에서 문자 입력 프로그램과 관계가 있는 시스템 프로세스를 더 나열하자면...
과거에 윈도우 95~2000/ME까지는 internat.exe라는 프로그램이 있었다. 시스템 트레이에다 현재 선택되어 있는 입력기의 언어와 종류를 띄워 주는 역할을 했다.

그러다가 2001년에 윈도우 XP와 함께 COM 인터페이스 기반의 고급 텍스트 서비스(TSF)가 도입되면서 그 역할은 ctfmon.exe가 대체하게 되었고 그게 오늘날의 비스타/7까지 변함없이 내려오는 중이다. internat이나 ctfmon은 언제나 상주해 있으며, 운영체제를 업데이트하지 않는 한 사용자가 강제 종료할 일도 없는 프로그램이다.

하지만 TSF의 도입 초기이던 오피스/윈도우 XP 시절에는 그게 운영체제의 안정성을 떨어뜨리기도 했기 때문에, 딱히 고급 문자 입력 기능에 관심이 없던 사용자 사이에는 운영체제의 버그를 고친답시고 TSF 기능을 완전히 끄고, 심지어 ctfmon 프로그램을 죽여서 문제를 해결하는 방법이 운영체제 팁으로 공유될 정도였다.

6. MS IME가 등록해 놓는 정체 불명의 유틸리티

MS가 제공하는 한중일 IME는 시작 프로그램에다가 정체를 알 수 없는 이상한 migration 유틸리티 같은 걸 등록하여, 운영체제가 시작될 때 매번 그게 실행되게 해 놓곤 했다. HKLM\Software\Microsoft\Windows\CurrentVersion\Run 아래에 말이다.

사용자 삽입 이미지

일본어나 중국어도 아니고 한국어 IME는 무슨 사용자 데이터를 관리하는 것도 아닌데 도대체 이게 하는 일이 무엇이며 왜 이런 과정이 필요한지는 본인으로서는 알 길이 없다. 그냥 일본어 IME 따라 관례적으로 이런 것도 따라 한 것이기라도 할까?

Posted by 사무엘

2012/08/30 08:37 2012/08/30 08:37
,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/726

« Previous : 1 : ... 154 : 155 : 156 : 157 : 158 : 159 : 160 : 161 : 162 : ... 221 : Next »

블로그 이미지

그런즉 이제 애호박, 단호박, 늙은호박 이 셋은 항상 있으나, 그 중에 제일은 늙은호박이니라.

- 사무엘

Archives

Authors

  1. 사무엘

Calendar

«   2025/01   »
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31  

Site Stats

Total hits:
3073309
Today:
767
Yesterday:
1618