« Previous : 1 : 2 : 3 : 4 : 5 : Next »

1. 자동차 배터리와 컴퓨터 스택 메모리

자동차의 배터리 방전과 컴퓨터 프로그램의 스택 오버플로는 서로 완전히 다른 분야이긴 하지만 공돌이의 심상 면에서 공통점이 느껴지는 것도 좀 있는 것 같다.
지난 수십 년 동안 자동차는 엔진 효율이 크게 향상됐고 컴퓨터의 메모리도 동적 힙(heap)이야 넘사벽 급으로 용량이 뻥튀기 됐지만, 저것들은 용량이 획기적으로 크게 올라간 적이 없다. (특별히 그럴 필요가 없어서..)

그리고 저 둘은 남은 용량이나 고갈 징후를 미리 알려 주는 메커니즘도 딱히 존재하지 않는다.
자동차의 황산-납 배터리는 스마트폰이나 노트북의 리튬이온 배터리처럼 용량이 몇 % 남았다고 알려주는 기능이 없다. 블랙박스도 배터리의 전력 용량이 감소하면서 전압도 같이 감소하는 걸 감지해서 간접적으로 꺼진다거나 할 뿐이다.

컴퓨터 프로그램의 스택 메모리도 지역변수의 주소를 이용해서 남은 용량을 아주 간접적으로 유추할 수 있고, 시스템 exception을 이용해서 일이 벌어졌을 때 스택 overflow를 감지할 수도 있다. 하지만 이식성 있는 일반적인 방법은 존재하지 않는다. 그걸 일일이 체크하는 건 아주 비효율적이다. 이런 식으로 유사점이 있다.

2. TLS 슬롯

메모리와 관련하여 이렇게 아기자기하게 제약이 될 수 있는 게 본인이 보기엔 TLS 슬롯 공간이다.
사실, 한 사람이 만드는 프로그램이 수십~수백 종류의 코드가 동시에 실행되는 프로그램을 만들 일은 극히 드물겠지만, 문제는 내가 만들지 않은 프로그램(특히 DLL)들이 한 프로세스에 왕창 붙어서 실행될 때이다. 이런 코드들이 전부 TLS 슬롯을 하나씩만 요청하더라도 TLS 공간은 수십~수백 개씩 소모될 수 있다.

Windows 95 내지 NT 3.x시절에는 현실적으로 필요한 양과 그 당시 컴퓨터들의 평균적인 사양을 감안해서 스레드마다 TLS 슬롯이 64개씩 배당되었다. 이게 바로 TLS_MINIMUM_AVAILABLE라는 상수값의 의미이다. 역대 win32 환경 중에 TLS 슬롯이 제일 적었던 구현체가 제공했던 최소 개수가 64라는 뜻이다.

세월이 흐를수록 기본 제공되는 TLS 슬롯 수는 점차 늘어나서 Windows XP/2000부터는 64에다가 1024가 더해진 1088개라고 한다. 후대의 운영체제에서 슬롯 수가 이것보다 더 늘어났다는 얘기는 본인은 들어 보지 못했다. 힙 메모리처럼 엿가락처럼 한없이 더 늘어나야 할 필요는 없는 물건이기 때문이다.

스레드 단위로 전역적으로 공유돼야 하는 데이터가 많이 있거나 그 데이터의 길이가 들쭉날쭉 변한다면 별도의 heap 메모리를 할당하고 TLS 슬롯에다가는 포인터만 저장해야 한다. 즉, 응용 프로그램은 언제나 고정된 개수만의 슬롯을 사용하고, 슬롯 사용량을 최소화해야 한다.

내가 보기에 TLS가 꼭 필요한 때 중 하나는 사용하는 라이브러리가 너무 구닥다리여서 콜백 함수에 context 데이터를 넘겨주는 게 없어서 context 정보를 오로지 전역변수에 의지해야 할 때(+ 그런데 thread-safety가 보장돼야 할 때) 정도이다.
한 프로그램이 스레드 10개로 동작하건 100개로 동작하건 그건 소모되는 TLS 슬롯 개수와는 전혀 무관하다. 이건 그냥 실행되는 코드의 종류하고만 관계가 있다.

3. 복합 스레드 동기화

조금 부끄러운 얘기를 하자면.. 본인은 오래 전 학교의 컴공 운영체제 시간에 졸았는지, 아니면 다른 변고가 있었는지는 모르겠지만 나만의 스레드 동기화 오브젝트를 새로 만든다는 개념 내지 필요성을 지금까지 별로 이해하지 못했다. 그냥 운영체제가 제공하는 critical section이나 뮤텍스, 세마포어만 쓰면 끝이지 않은가..?? 그랬는데 회사 코드를 들여다보면서 뒤늦게야 '아...!!' 현타 비스무리한 걸 경험하게 됐다.

평범한 데이터 컨테이너가 멀티스레드 동작에 대비하여 곳곳에 뮤텍스 기반의 lock이 걸려 있는데.. 데이터를 건드리는 set쪽뿐만 아니라 단순히 read만 하는 get 메소드들까지도 내부가 전부 동일한 lock이 일일이 걸려 있었다. 흠, 이건 read일 뿐인데 여러 스레드가 동시에 접근해도 상관없지 않나? 저건 불필요한 삽질 오버헤드 아닌가? 이 lock은 빼 버려도 되겠는데?

그런데 알고 보니 그 생각은 절반만 맞았다. reader만 있을 때는 여러 스레드들이 동시에 접근해도 괜찮지만, 한 스레드라도 write를 할 때는 다른 writer는 물론이고 reader들도 다 줄 서서 기다려야 하기 때문이다. 그러니 get 함수도 lock이 전혀 없어서는 안 된다.

하지만 이렇게 정말 간단하고 범용적인 원리대로 lock의 종류를 구분하는 것이 운영체제 API로는 의외로 직통 구현돼 있지 않았다. 기존 동기화 오브젝트를 조합해서 사용자가 직접 구현해도 되며, 이런 복합 동기화는 읽기/쓰기 중 한쪽으로만 CPU가 너무 쏠리고 있을 때 분배를 어떻게 할지 같은 정책이 일방적으로 획일화 가능하지 않기 때문이다.

그래도 C++ 라이브러리의 스레드/동기화 클래스 중에는 이런 "다수 reader/단일 writer" 동기화를 구현한 놈이 혹시 있는지 모르겠다. 이런 클래스는 그냥 lock와 unlock만 있는 게 아니라 lock이 lockForRead와 lockForWrite로 세분화된다.

이렇게 custom 동기화 오브젝트를 만들면 기존 운영체제 API만으로는 바로 구현 가능하지 않은 복합 동기화를 시전할 수 있다. reader와 writer가 여러 놈이 동시에 경합할 때, 그리고 read와 write의 소요 시간이 차이가 많이 날 때 어떤 원칙으로 CPU를 배분할지 같은 세부 원칙도 손수 정할 수 있다.

그리고 디버그 빌드에서는 각종 참고 정보를 알려주고 오류를 검출하는 기능도 넣을 수 있다. 현재 포커스를 잡은 스레드, 또는 대기 중인 스레드들을 얻어 온다거나..
lock을 건 스레드가 아직 실행 중인데 그 동기화 오브젝트가 소멸되는 건 잘못된 상황이므로 곧장 예외나 assertion failure를 날린다.

(이 글을 쓰고 나서 나중에 알게 된 사실: Windows Vista에서부터 Slim Reader/Writer (SRW) Lock이라는 게 도입됐다. 크리티컬 섹션처럼 동일 프로세스 안에서만 사용 가능한 대신.. reader lock과 writer lock을 구분해서 요청 가능한 작고 가벼운 동기화 오브젝트이다. 역시 범용성이 있으니 2000년대 이후에야 도입됐구나 싶다.)

그리고 디버깅에 제일 도움이 되는 정보는.. 아무래도 deadlock 감지일 것이다.
응답이 멎은 프로그램을 강제로 break시킨 뒤, 스레드들의 스택 상태를 추적하다 보면 memory leak보다는 쉽게 찾을 수 있겠지만 크고 복잡하고 스레드를 왕창 많이 만드는 프로그램에서 이런 걸 프로그램이 디버그 정보를 통해 자동으로 찾아주면 디버깅에 큰 도움이 될 것이다. 물론 이 경우, 동기화 오브젝트가 락에 진입한 스레드들의 실행 정보를 일일이 관리하고 있어야 할 것이다.

Posted by 사무엘

2024/01/24 08:35 2024/01/24 08:35
,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/2256

1. 자연어 처리

우리나라 헌법 전문은 무진장 길고 복잡한 만연체인데, 결국 핵심은 "대한국민은 헌법을 개정한다"이다. ㄲㄲㄲㄲㄲㄲ
자, 문장 구조를 파악하기 위해 프로그램 코드처럼 들여쓰기를 적용해 주면 얼추 다음과 같다.

. 유구한 역사와 전통에 빛나는
우리 대한국민은
. . . . . 3·1운동으로 건립된
. . . . 대한민국임시정부의 법통과
. . . . . 불의에 항거한
. . . . 4·19민주이념을 계승하고,
. . . . . 조국의 민주개혁과 평화적 통일의 사명에 입각하여
. . . . . 정의·인도와 동포애로써
. . . . 민족의 단결을 공고히 하고,
. . . . 모든 사회적 폐습과 불의를 타파하며,
. . . . . 자율과 조화를 바탕으로
. . . . 자유민주적 기본질서를 더욱 확고히 하여
. . . . . 정치·경제·사회·문화의 모든 영역에 있어서
. . . . 각인의 기회를 균등히 하고,
. . . . 능력을 최고도로 발휘하게 하며,
. . . . . **자유와 권리에 따르는
. . . . 책임과 의무를 완수하게 하여**,
. . . . **안으로는
. . . 국민생활의 균등한 향상을 기하고
. . . . 밖으로는 항구적인
. . . 세계평화와 인류공영에 이바지함으로써**

. . . 우리들과 우리들의 자손의
. . 안전과 자유와 행복을 영원히 확보할 것을 다짐하면서
. 1948년 7월 12일에 제정되고 8차에 걸쳐 개정된
헌법을
. 이제 국회의 의결을 거쳐
. 국민투표에 의하여
개정한다.

안팎드립을 비롯해 몇몇 좋은 훈계조 문구들은 국민 교육 헌장에서 모티브를 딴 것 같다~!

"... 안으로 자주독립의 자세를 확립하고, 밖으로 인류 공영에 이바지할 때다."
"... 자유와 권리에 따르는 책임과 의무를 다하며 ..."


다만, 이런 요지의 문장 자체는 제헌헌법 시절부터 있었다고 한다. 따지고 보면 국민 교육 헌장이 기존 헌법 전문으로부터 영향을 받은 것이다.

2. AI

AI가 앞으로 의료나 법조계 직업을 많이 빼앗을 거라고 흔히들 예측한다. 특히 사법 불신이 팽배하다 보니 법 쪽은 "대체될 것이다"가 아니라 "당장 대체돼야 된다"라고 강하게 주장하는 사람도 있다.
하지만 세상 돌아가는 양상을 보면 그런 분들의 바람은 가까운 미래에 호락호락 이뤄질 것 같지 않다.

AI 기술의 침투가 제일 소극적이고 더디고 분야, 제일 신중하고 보수적으로 행해지는 분야가 바로.. 사람의 돈이나 인생, 목숨이 왔다갔다 하고 법적 책임이 부과되는 크리티컬한 분야이기 때문이다. 의· 법이 권위 있는 직종인 이유도 바로 이 때문이다.
10살짜리 초딩이 무슨 미적분 할아버지 문제를 풀고 자동차 내부 구조를 달달 외운다 해도, 걔한테 대형 트럭 운전 면허증을 주지는 않는 것과 비슷한 이치이다. 고졸 일자무식이어도 법적 책임 능력이 있는 성인이 그런 차를 몰지.

기계 및 기계 관리자를 전적으로 믿을 수 없어서 자율주행이나 전자투표도 호락호락 정착하지 못하고 있는데, 진료나 판결을 AI가 덜컥 한다..???
솔직히 AI가 수많은 판례들을 학습해서 일관성 있는 합리적인 판결을 내릴 기술적 역량은 이미 갖춰져 있다. 허나 AI라고 해서 흉악범을 몽땅 속 시원하게 사형 때리지도 않을 뿐더러, 그와 별개로 그 분야에서의 AI 대체는 정서상 절대로 금방 되지 않을 것이다. 그런 분야에서 AI의 개입은 기껏해야 "참고만 할 것. 아니면 말고" 수준인 법률 자문, 조언, 보조 수준에서 그칠 것이다.

저런 분야 말고 상상화를 너무 기괴하게 그렸다고, 바둑 게임에서 상대편에게 졌다고, 애한테 조금 허언증스러운 잘못된 정보를 가르쳤다고 해서 당장 사람이 죽고 탈 나지는 않는다. 그런 분야는 AI가 이미 넘치도록 활개를 치고 있다.

3. 정보 보안

입구에 '신천지 OUT 출입금지' 딱지가 붙어 있는 교회를 보면.. 참 웃픈 생각이 든다.
작정하고 기존 교회 신자들을 빼 가려고 침투하는 신천지 공작원(?)이 그걸 보곤 참 잘도 겁 먹고 꽁무니를 빼겠다.

울나라 군사분계선 근처에다가 '북한군 접근 금지'라고 딱지 붙여 보지 그래..?
그런 곳에다가는 보통은 북한군이 아니라 '허가받지 않은 민간인은 접근 금지'라고 써 붙이는 게 자연스럽다. 둘의 차이가 뭔지 모르는 분은 없으리라 믿는다. 암튼..

내가 출처를 직접 확인해 보지는 못했지만.. 마틴 루터가 "이단은 무력이 아니라 설교로 퇴치해야 된다"라는 말을 남겼다고 한다. "펜은 칼보다 강하다"와 같지는 않지만 비슷한 관점에서 참으로 옳은 말이다.

이단들이 물리적으로 꽹과리 치고 흉기 휘두르면서 타 교회 예배를 방해하고 집기를 파손하고 신자들을 해친다면야.. 그럼 당연히 경찰에 신고해야 되고 공권력에 호소하며 도움을 요청할 수 있다. 세상 법정에다 손해배상 소송 걸어서 깽값 받아낼 수도 있다. (받아내야 한다.. 가 아니라 그럴 수도 있다고)

그러나 그러나~~ 계시록 14만 4천 명이 누군지, 동방의 의인이 누군지.. 새 하늘과 새 땅이 뭔지, 열두 지파 정체가 뭔지.. 그딴 거 해석하고 판단하는 일을 세상 경찰이나 법원에다 맡길 참인가? 그런 걸 자기와 다르게 생각하는 이교도 이단들을 과태료 물리거나 민형사 책임을 물어서 처벌이라도 할 생각인가?

교리를 똑바로 가르쳐서 자기 성도들이 신천지 추수꾼들한테 홀딱 속지 않게 해야 하지, 그러지도 않으면서 무책임하게 '신천지 출입금지' 이러는 건 교회가 자기 할 바를 다하지 않고 세상 공권력에다가 이단 퇴치를 다 떠넘기는 것처럼 보인다. 무슨 웹사이트들 하단에 관행적으로 쓰여 있는 "이메일 주소 무단수집 거부"도 아니고 참..;;

신천지라든가 공산주의나 동성애 따위가 아무리 나쁘다고 해서 그걸 무슨 세상 공권력이나 타 종교하고까지 손잡아서 물리적으로 박멸하는 것은 기독교회가 해야 할 '하나님의 일'이 아니다. 당장은 그게 편해 보여도 세상 공권력은 언제든지 기독교를 박해하는 역공 비수가 되어 교회로 되돌아올 수 있다~!

그건 그렇고.. 컴퓨터 정보 보호 보안의 관점에서도 이거랑 아주 비슷하게 느껴지는 원칙이 있다.
암호 보안은 '암호화 알고리즘'이라는 코드가 아니라, '거기에다 준 암호화 키'만으로 완벽하게 보장돼야 한다는 거.

"이 데이터는 우리 회사만의 기가 막힌 블랙박스 알고리즘으로 암호화돼 있습니다. 보안을 위해 구체적인 알고리즘은 공개할 수 없습니다" 이건 저런 "신천지 출입금지" 딱지를 거는 것과 비슷한 수준 낮은 보안이다. -_-;;; 지난 2009년, 코드소프트 암호 크랙 공모전 흑역사처럼 말이다.

다시 말하지만 암호화 알고리즘은 무슨 요리 비법마냥 장인의 손맛이 담긴 비기 같은 존재가 절대 아니다~!! ㄲㄲㄲㄲㄲ
실제 정보 보호 업계가 돌아가는 방식은 이와 전혀 다르다. 모든 암호화 알고리즘들이 소스째로 다 투명하게 버젓이 풀려 있다. 아무라도 그 코드를 돌려서 임의의 데이터를 임의의 키로 암호화 복호화한 결과를 볼 수 있다.

이 데이터는 무슨 알고리즘으로 암호화됐는지 알려져 있고, 그 알고리즘 코드도 이미 다 있다.
그럼에도 불구하고 무슨 키로 암호화됐는지를 모르면.. 일일이 모든 키로 다 해독해 보는 brute force 외의 방법으로는 원래 데이터를 절대로 복원할 수 없다.

이게 "이단은 설교만으로 퇴치해야 된다"와 같은 급의 보안인 것이다. 암호화 키가 무슨 교리 같은 존재인 듯.. ^^
히틀러인지 누군지 아무튼 어느 나치 독일 간부가 남긴 명언(?) 중에 "힘은 방어가 아니라 공격에 있다"가 있었던 것 같은데.. 그 말을 응용해 보면 "보안은 알고리즘이 아니라 키에 있다" 정도가 될 것이다.

여담:
여기까지 글을 썼더니 현업에서 목회를 하시는 분들께서 글 주제와 관련하여 여러 조언 첨언을 본인에게 해 주셨다.

  • 그냥 자기가 소속된 교단에서 딱지 붙이라고 반강제 강권해서 붙이는 편이라고 한다. 오키. 거기까지는 이해가 되는데..
  • 심지어 신천지 교회들이 '위장'을 위해서 자기 예배당 입구에다가 "신천지 OUT" 딱지를 붙이는 경우도 있다고 한다. 미친~~ ㄷㄷㄷㄷㄷㄷ
  • 신천지에서는 기존 교회들에다가 스팸성 우편물도 끈질기게 왕창 보낸다고 한다. 흐미~ 도대체 뭔 재정으로 저럴 여력이 있는지 모르겠다.

Posted by 사무엘

2023/10/30 19:35 2023/10/30 19:35
,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/2225

컴퓨터의 정보 기억장치는 다음과 같은 속성에 따라 분류 가능하다.

(1) 배열처럼 아무 지점이나 O(1) 시간 복잡도로 즉시 접근 가능한가? 아니면 링크드 리스트처럼 순차적으로만 접근 가능한가?
Random Access memory라는 건.. 아무렇게나 읽고 쓰기가 가능하다는 뜻이 아니라, 임의 지점 접근이 가능하다는 뜻이다.
물론 오늘날은 테이프 같은 극단적인 물건 말고는 RAM이 당연시되고 있다. 테이프는 임의 접근이 안 되니 번거로운 감기 기능이 필요했지만.. CD는 아무 트랙이나 바로 갈 수 있다.

(2) 읽고 쓰기 가능한가, 아니면 읽기 전용인가?
ROM이라고 불리는 물건들은 RAM의 속성을 지니면서 동시에 ROM인 셈이다. ROM은 RAM의 엄밀한 반의어가 아니니 유의할 것.
CD 같은 광학 디스크는 요즘 기술로 '쓰기' 자체는 가능하다. 하지만 아무 부작용이나 부담 없이 자유자재로 아무렇게나 쓸 수 있는 건 아니다.

(3) 휘발성인가, 비휘발성인가
아주 중요한 속성이다. 전원이 끊어지면 내용이 싹 다 날아가느냐, 아니면 그 뒤에도 내용이 남아 있느냐? 읽기 전용 메모리는 당연히 비휘발성이어야 할 테니 이건 읽쓰 겸용 메모리가 대상이다.
반도체 기반의 주메모리는 속도가 빠른 대신 전자이고, 나머지 보조 기억장치들은 느린 대신 용량 많고 후자의 속성을 지닌다.

(4) 매체와 reader/writer가 쉽게 분리 가능한가? 아니면 붙박이인가?
이거 무슨 철도 차량으로 치면 기관차-객차 vs 동차 같은 차이점 같다.

(5) 그리고.. 어떤 기술 배경에 따라 만들어졌는가?
다음과 같이 세 계열로 나뉜다.

1. 자기장: 테이프, 디스켓 // 디스크, 드럼.

매체 분리형에서는 테이프만이 무슨 방송국이나 데이터센터 급의 백업/아카이빙 용도로 쓰이고 있고 나머지는 도태했다. 디스켓이고 zip드라이브고 뭐고 다 망했으니까. 붙박이형은 디스크만이 '하드'의 형태로 남고 다 도태했다.
1950년대에 슈퍼컴퓨터 용으로 무려 5MB짜리 하드디스크를 지게차에다 조심스럽게 실어 나르던 시절을 보면 참 격세지감의 극치가 따로 없다.

사용자 삽입 이미지

여기는 전통적인 트랙이니 섹터니 하는 구조 구분과 '포맷'이라는 게 통용되는 기억장치이다. 하드디스크는 실린더라는 것도 있었고 말이다.
똑같은 디스켓이라도 운영체제에서 소프트웨어적으로 공간 구획을 구분하고 인식하는 방법이 다르다. 과거에는 플랫폼과 운영체제에 따라 이런 파편화가 더 심했기 때문에 디스켓들이 포맷되지 않은 채로 판매되곤 했다. 물론 IBM PC와 MS-DOS가 천하를 평정한 뒤부터는 디스켓들이 다 미리 포맷되어서 나오기 시작했다.

하드디스크는 전원이 끊어질 때 안전을 위해 파킹이라는-_- 마무리 동작도 권장되곤 했다. 물론 훗날 자동 파킹이 지원되면서 별도의 파킹 유틸리티는 화면 보호기만큼이나 별 필요 없는 눈요기 잉여로 전락했다.

2. 반도체: USB 스틱, SD카드 // SSD

메모리 반도체는 100% 전자식으로만 동작하는 물건이다. 빠른 대신에 비싸고, 무엇보다도 그 특성상 전기가 끊어지면 내용도 다 날아가는 '휘발성 메모리' 전용이었는데.. 기술의 발달로 보조 기억장치 역할도 가능한 메모리 반도체가 등장했다.
얘 덕분에 기존의 테이프나 디스켓이 완전히 전멸해 버렸다. 그리고 SSD도 가격 내려가고 용량 올라가면서 기존 기계식 하드디스크의 입지를 상당수 위협하고 있다.

SSD는 조각 모음이 필요하지 않으며, 동작하는 특성이 기존 디스크와는 많이 다르다.
USB 스틱은 매체와 구동부가 일체형인 반면, SD카드는 매체와 구동부가 분리돼 있다. (별도의 reader가 필요)
옛날 8비트 시절에 게임용으로 쓰였던 롬팩 카트리지도 1번이 아니라 2번 반도체 기반이었던 거지..??

전자기기에서 캐퍼시터(축전기)와 본격적인 화학 전지의 관계가 반도체 메모리와 타 보조 기억장치의 관계하고 비슷해 보인다~!!
전자는 충전· 방전이 아주 빠르고 용량이 아주 작으니까. 그리고 캐퍼시터를 용량을 왕창 키워서 배터리처럼 사용하려는 연구가 진행 중이기도 하다.

3. 광학(레이저)

얄팍하고 비까번쩍 빛나고 뭔가 하이테크스럽게 생긴 원반이다. 1990년대에 첫 등장했을 때는 얼마나 간지 뽀대 났겠는가.

사용자 삽입 이미지

얘는 그 특성상 붙박이라는 게 존재하지 않고 드라이버와 매체가 분리돼 있다. 기억장치들 중 디지털 방식의 음반· 영상매체와 가장 친화적이라는 특징도 있다. (그 반면, 테이프는 '아날로그' 방식의 매체..)
얘는 '쓰기'와는 그렇게 친화적이지 않다. 디스크에다가 작정하고 새로 기록 추가만 가능하며, 한번 새겨 버린 내용을 자유자재로 덮어쓸 수 없다. 평범한 디스크 저장이 아니라 종이에다 인쇄하는 것과 얼추 비슷하다고 생각해야 한다.

디스크의 영어 스펠링은 disk와 disc가 혼용되는 듯한데.. disc는 특별히 대놓고 원반 모양인 광학 매체에 한정되어 쓰이는 것 같다. 가령, 하드는 hard disk이지만, CD는 compact disc이다.
그리고 CD(+ DVD, 블루레이)는 지름이 12cm인 반면, 과거에 있었던 레이저 디스크는 지름이 12인치였다는 아주 흥미로운 차이점이 있다. 뭐, 거기에다 미니CD라고 지름 8cm짜리 규격도 있긴 하고 말이다.

한때 광학 기억장치는 용량이 방대하다는 장점이 있었지만 오늘날은 빛 바랜 장점이다. 이제는 컴퓨터에서 광학 드라이브 자체가 거의 퇴출되었고, 운영체제 설치도 그냥 네트워크나 USB로 다 되는 세상이 됐다.
그래서 DVD의 다음 규격인 블루레이는 용량이 더 방대함에도 불구하고 오늘날 존재감이 매우 미미하다. 블루레이에다가 수십 GB짜리 패키지 게임을 담아서 판매하는 시대도 아니니 말이다.

옛날에는 뭔가 레이저를 사용하는 컴퓨터 주변기기는 가격이 억소리 나게 비쌌던 걸로 악명 높았다. 레이저 프린터, 그리고 씨디 라이터.. 그게 어쩌다가 가격이 확 떨어지고 개인용 컴퓨터에 씨디를 굽는 기능까지 내장되어 들어갔는지.. 경이롭기 그지없다.
기껏 들어갔던 기능이 이제는 필요 없어져서 퇴출되는 지경이고..

※ 여담 1: 옛날 추억 더

  • 1990년대에 VGA 이후로 SVGA 그래픽 카드들이 표준 규격 없이 난립했던 것처럼.. 확장 디스켓도 표준 규격 없이 너무 난립했던 것 같다. 더구나 USB니 plug & play니 없던 시절에는 하드나 디스크 드라이브를 하나 더 장착하는 것도 엄청나게 어렵고 컴퓨터 하드웨어 지식이 많이 필요하던 과업이었다. 그러니 그런 싸제 물건들이 성공적으로 보급되기가 어려웠다.

  • 그나저나 이 바닥은 자동차 브레이크 말고도 '디스크와 드럼'을 쌍으로 구경할 수 있는 또 다른 분야인 게 신기하다. '자기 드럼'은 어떤 형태로 동작하는 물건이었을까..?? 개인적으로 무척 궁금하다.

  • 옛날에는 테이프나 디스크에 물리적인 쓰기 방지 탭이나 딱지 같은 게 붙어 있기도 했지만.. 요즘은 그런 관행을 찾을 수 없다. (운영체제 셸이 그런 데다가도 메타데이터나 썸네일 캐시 같은 걸 임의로 써 넣곤 함)

  • 옛날에는 광자기 디스크라는 것도 있었던 것 같은데.. 뭐지? 1번과 3번의 하이브리드인가 싶다.

카세트 테이프(자기장)나 롬 카트리지(반도체)는 8비트의 산물이다. 16비트 IBM 호환 PC급에서 저런 것들을 취급하는 사례는 내가 아는 한 없다.
그 대신 디스켓 FDD는 컴퓨터 붙박이 형태로 16비트 이후 시대를 풍미했다가 64비트 시대에는 사실상 전멸했다.
CD-ROM은 16비트 도스 시절에도 존재하긴 했지만 mscdex니 뭐니 하는 굉장히 무거운 드라이브를 실행해야 사용 가능했다. 그리고 386, 486급 이상 PC의 전유물이었다.
그 뒤로 USB 메모리는 도스와의 유의미한 접점이 없다. ^^

아무리 생각해도 1990년대 중후반에 plug & play와 USB는.. 2000년대 중후반의 64비트와 멀티코어하고 굉장히 비슷한 관계인 것 같다.
서로 담당하는 분야는 다르지만 결국 비슷하고 관련 있는 성격의 기술이었다는 점에서 말이다.

※ 여담 2: 정보 저장이라는 관점에서 성경 본문 고찰

성경에는 뭔가 정보 기록 매체를 암시하는 얘기가 있다. 가령, 요한복음의 21장 25절 제일 마지막 구절은 이렇다.
"예수님께서 행하신 다른 일들도 많으므로 만일 그것들을 낱낱이 기록한다면 심지어 이 세상이라도 기록된 책들을 담지 못할 줄로 나는 생각하노라."

"그 크신 하나님의 사랑"이라는 찬송가의 3절 가사는 이렇다.
"하늘을 두루마리 삼고 바다를 먹물 삼아도 한없는 하나님의 사랑 다 기록할 수 없겠네"

흠, 책이 아니라 SD카드라면 어떨까? 자기 테이프라면 어떨까..??
혹시 생명책이 실제로는 책이 아니라 무슨 SQL 서버가 돌아가는 IBM 메인프레임인 건 아닐까?

Posted by 사무엘

2023/10/05 08:35 2023/10/05 08:35
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/2215

컴퓨터 알고리즘 문제 중에는.. "N개의 원소로 구성된 목록에서 majority.. 과반/다수파라는 게 존재하는가? 존재한다면 무엇인가?"를 구하는 문제가 있다.
목록에서 과반의 원소가 다 같은 값이면 그게 바로 majority라고 정의된다. 원소들은 꼭 대소 관계가 성립할 필요가 없고 그냥 동등성 판단만 가능하면 된다. 그러니 꼭 정수가 아니어도 된다.

또한, 반반이 아니라 과반이라는 특성상, majority는 존재하지 않거나, 유일하게 존재.. 언제나 둘 중 하나이다. 공동 1위 같은 것도 고려할 필요가 없다.

이 문제는 뭐랄까.. 단순하면서도 참 므흣하다.
일단, "목록에서 가장 자주 등장하는 원소--등장 빈도수가 가장 큰 원소를 구하시오"라고 접근하지 않는 게 핵심이다.
각 원소들의 빈도수를 일일이 관리하자면 알고리즘의 시간 복잡도가 기본이 O(n^2)에서 시작할 것이고, 균형 잡는 tree 기반의 컨테이너를 사용한다 하더라도 O(n log n)이 한계이다.

그러나 이 문제를 풀기 위해서는 일을 그렇게 크게 벌일 필요가 없다.
각 원소의 빈도수가 아니라.. "이 목록은 과반의 원소가 그냥 동일한 값인가?"라고 접근하는 게 좋다.

수학인지 논리학인지 거기에는 "비둘기집의 원리"라는 게 있다. N+1개의 물건을 N개의 상자에다 다 집어넣는다면, 적어도 한 상자에는 그 물건이 2개 이상 들어가 있다. 뭔가 미적분에서 말하는 중간값 정리처럼.. 너무 당연한 말 같은데 말이다.
그것처럼 어떤 목록에 같은 원소가 "과반"이라면 그 목록은 다음 둘 중 한 특성을 반드시 갖게 된다.

  • 과반의 원소가 아무리 고르게 분산되어 분포한다 하더라도, 그 원소가 연달아 두 번 이상 등장하는 구간이 반드시 하나 이상 존재한다~! 1 1 2 1 특히 원소의 전체 개수가 짝수라면 이건 뭐.. 무조건 빼박이다.
  • 만약 그게 아니라면.. 그냥 맨 마지막 원소가 다수파이다.

어, 정말 저렇게 단정할 수 있나 의아할 텐데.. 이런 과감한 주장은 다수파의 정의가 절반의 '초과', '과반'이기 때문에 성립 가능하다.
절반을 포함하는 '이상'이기만 해도 위의 조건들은 당연히 성립하지 못하게 된다. "1 2 1 2" 같은 것만 생각해 봐도 알 수 있다.

이렇듯, 다수파가 존재할 때 가질 수밖에 없는 목록 전체의 특성을 생각하면.. 다수파를 굉장히 단순한 절차만으로도 정확하게 구할 수 있다.

  • 최초엔 맨 첫째 원소가 다수파라고 가정하고 후보로 지정한다. 연속 등장 횟수(이하 점수)도 1을 부여한다.
  • 그 다음 원소가 후보 원소와 동일하면 점수를 1 증가시킨다. 그렇지 않으면 점수를 1 감소시킨다.
  • 단, 이미 현재 점수가 0이 된 상태여서 더 감소시킬 것이 없으면 후보 자체를 지금의 새 원소로 교체한다. 그리고 점수를 1로 다시 부여한다.
  • 이 과정을 모든 원소들에 대해 수행한 뒤, 현재 지정되어 있는 후보를 결과값으로 되돌린다.

사용자 삽입 이미지

위키백과에는 이 과정을 다음과 같이 시각적으로 잘 묘사한 그림이 있더라.
정말 허무할 정도로 단순하다. 이 알고리즘은 고안자의 이름을 따서 Boyer-Moore majority vote algorithm이라고 명명되어 있다. 1981년에 학계에 처음으로 발표됐다고 하는데.. 동작하는 방식을 보니 후보, vote 이란 워딩이 적절해 보인다.

Boyer-Moore 이거 혹시 "문자열 검색 알고리즘에도 나오는 이름이 아닌가?"라는 생각이 들 텐데.. 정확하다. 동일한 명칭이다. ㄲㄲㄲㄲ

단, 위의 알고리즘은 목록에 다수파라는 게 실제로 존재하지 않더라도 언제나 후보를 갖고 있다가 되돌린다. 그러니 목록에 다수파가 존재한다면 정확한 답을 되돌리지만, 애초에 다수파가 존재하지 않는다면 뭔가 임의의 엉뚱한 후보를 되돌린다.

그렇기 때문에 이 알고리즘에는 2nd-pass, 즉 후처리라는 게 필요하다. 앞의 1st-pass를 통해 구해진 후보가 진짜로 다수파가 맞는지, 얘만 개수를 처음부터 다시 세어 보는 것이다.
1st-pass 때 쓰였던 점수 변수는 증가했다가 감소하기를 반복했기 때문에 정확한 개수가 담겨 있지 않다.
이거 무슨 분수· 무리방정식을 풀고 나서 검산을 해서 무연근을 제거하는 것과 비슷한 느낌이다.

자, 두 pass 모두 시간 복잡도는 O(n)이고, 공간 복잡도는 지역변수 꼴랑 한두 개.. O(1)에 지나지 않는다. 정말 놀랍지 않은가?
얘는 알고리즘 자체는 쉽게 이해할 수 있지만, 정말 이렇게만 해도 언제나 문제에 대한 정확한 답이 구해지는지 correctness를 이해하는 게 좀 빡셀 수 있는 문제이다.

알고리즘이라 하면 복잡한 기법을 동원해서 무식하게 풀었을 때 O(n^2)짜리인 것을 O(n log n)으로 낮춘다거나, 팩토리얼/지수함수 급인 것을 O(n^2)나 O(n^3)으로 낮추는 형태인 게 많다.
그러나 최적화를 통해서 이렇게 O(n)을 만들 수 있는 문제는 흔치 않아 보인다.

이 다수파 구하기와 성격이 아주 비슷한 문제는 N개의 숫자 목록 내부에서 "합이 가장 큰 연속된 구간을 찾기"인 것 같다. 당연히 양수와 음수가 뒤죽박죽 섞여 있는 목록에서 말이다.

정답이 (x~y) 구간은 그야말로 1<=x<=y<=N 아무렇게나 가능하기 때문에 이것도 언뜻 보기에는 시간 복잡도가 O(n^2)이나 최하 O(n log n)이 될 것 같다. 그러나 얘도 아주 간단한 검사만 하면서 시간 복잡도 O(n)과 공간 복잡도 O(1) 만으로 아주 빠르게 풀 수 있다.

  • 정답 구간이 맨 첫 원소에서 시작된다고 가정하고 각 원소들을 쭉쭉 더해 본다. 그 합이 지금까지 구한 max보다 더 크면 최대값을 갱신하고 정답 구간도 업데이트 한다.
  • 그런데 그러다가 합이 음수가 돼 버리면... 그러면 지금까지 살펴봤던 구간은 "더 살펴볼 필요가 없고" 그냥 통째로, 아무 미련 없이 버리면 된다. 그 다음에 양수가 나오는 구간부터 시작점을 새로 설정하고 동일한 과정을 반복한다.

더 살펴볼 필요가 없기 때문에 시간 복잡도 O(n)이 가능한 것이다. 이게 아까 다수파 문제에서 점수가 음수가 돼 버린 시점에서 후보를 깔끔하게 바꿔 버리는 것과 비슷하다. 왜 이렇게 해도 되는지를 생각하는 게 이 문제의 관건이다.

Posted by 사무엘

2023/07/29 08:35 2023/07/29 08:35
, , , ,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/2188

1.
고층 건물에는 엘리베이터가 있다.
그런데 건물이 왕창 크고 층이 수십 개 이상으로 많고, 이용하는 사람도 왕창 많으면.. 엘리베이터도 한 대만으로는 감당이 안 되니 여러 대를 설치하게 된다.

그런데 이게 설치만 한다고 장땡이 아니다. 엘리베이터는 에스컬레이터나 다른 정규 노선 대중교통과 달리, 승객의 수요예 따라 그때 그때 이동하는 물건이다. 이 점에서는 버스보다는 택시에 더 가까운데, 그래도 중간 합승이 허용된다는 차이가 있을 뿐이다.
이런 특성상, 엘리베이터는 승객과 차량을 똑똑하게 분배하는 운영 시스템이 필요하다. 무식하게 운용하면 차량이 많아도 승객들은 엄청 오래 기다려야 하고, 탄 뒤에도 층마다 서면서 엄청난 비효율이 발생하기 십상이다.

그래서 엘리베이터를 똑똑하게 분배하는 시스템이 없던 과거부터 현재까지 제일 보편적으로 쓰이고 있는 단순한 방법은 (1) 각 차량의 용도를 그냥 층별로 물리적으로 분할하는 것이다. 저층부/고층부, 그리고 홀/짝 이렇게 말이다.
이건.. 모든 엘리베이터들이 바쁠 때야 그럭저럭 괜찮은 방법이다. 그러나 서로 다른 구간끼리 오가는 사람은 불편하게 환승을 하거나 인접층으로 이동해야 한다. 그리고 엘리베이터들이 전혀 바쁘지 않은데도 나와 더 가까이 있는 엘리베이터를 이용하지 못하고 먼 쪽의 엘리베이터를 강제로 이용해야 하는 비효율이 발생한다.

얘보다 약간 더 발전된 엘리베이터는.. 버튼을 누르면 그 층의 모든 엘리베이터의 버튼에 불이 켜진다. 그리고 (2) 지금 층에서 가장 가까이 있는 엘리베이터를 중앙 시스템이 알아서 골라서 보내 준다.
고급 호텔 같은 곳의 엘리베이터가 이런 형태인 경우가 있다. 각 엘리베이터들이 현재 몇 층에 있는지 표시도 해 주지 않는다. 그리고 더 신기한 건.. 밖에서 상행이나 하행 중 한 버튼을 누르는 게 아니라, 처음부터 가고 싶은 층을 찍게 돼 있는 것도 있다.

요런 엘리베이터는 어느 엘리베이터의 문이 열릴지 알 수 없어서 승객이 처음에 약간 헤맬 수 있지만, 그래도 물리적인 층 분담보다는 더 똑똑하고 효율적으로 동작할 가능성이 있다.
하지만 약간 아쉬운 점은.. 중앙 시스템이 찜한 엘리베이터가 승객의 층으로 오는 도중에 다른 승객 때문에 많이 지체되고 있을 때, 그냥 다른 엘리베이터를 대신 지정하는 게 안 될 확률이 높다는 것이다. AI가 그런 것까지 고려해서 만들어지지는 않기 때문이다.

이건 절대적인 정답이 없는 문제이다. (1) 엘리베이터를 이미 탄 승객, (2) 밖에서 기다리는 승객, 그리고 (3) 엘리베이터 자체의 주행 거리 총량(소모 전력) 사이의 trade-off 제로썸 게임이기 때문이다.

그래도 최적해에 근접하는 가장 효율적인 전략은.. (1) 엘베들이 바쁘지 않을 때는 층수 구분 따위 불문하고 가장 가까이 있는 차량을 보내 주고, (2) 도중 정차도 일단은 아무 요청이나 들어 주되, 이 방향으로 가는 동안 2번, 3번 이상 이미 정차를 했다면 그때부터는 요청을 서서히 안 들어 주고 다른 차량을 대신 보내는 식으로 유도리를 발휘하는 게 좋을 것 같다.
횟수 제한, 또는 앞으로 최소한 n층 정도는 무정차로 진행.. 이런 식으로 정차를 제한할 수 있다.

물론 대체 차량이 너무 멀리 떨어져 있다거나 하면 전략이 달라지게 된다.
그리고 처음에 찜했던 차량이 너무 오랫동안 '열림'으로 붙잡혀서 못 가고 있을 때도 가까이 있는 다른 차량을 대신 보내 줘야 한다.

이 정도면 거의 AI 기술까지 접목해도 되지 않나 싶다.;;
AI가 진짜 똑똑하게 동작하려면 승객을 목적지 층별로 분할하는 것까지 알아서 처리할 필요가 있다. 차량들을 강제로 홀/짝, 고/저로 구분하지 않더라도 말이다. 모든 차량에 모든 층 승객이 고르게 뒤섞여 있으면 AI 할아버지라 해도 효율이 떨어지는 걸 피하기 어렵기 때문이다.

그리고 그렇게 하기 위해서는 엘리베이터를 기다릴 때 가고 싶은 층을 미리 지정할 필요가 있다. 그러면 이 AI가 상황을 대충 파악하고는 "3층, 7층, 12층 가실 승객은 지금 오는 엘리베이터 B차량을 타십시오. 4층, 10층, 15층에 가실 승객은 1분쯤 뒤에 도착 예상되는 저쪽 A차량을 타십시오" 이렇게 구간을 적절하게 나눠서 교통정리를 할 수 있다.
물론, 다음 엘리베이터의 도착이 너무 늦어지고 있으면 한 엘리베이터가 좀 더 촘촘하게 정차하게 된다. 이걸 유동적으로 결정하는 것도 AI의 몫이다.

이렇듯, 엘리베이터 분배도 깊고 어렵게 생각하면 끝이 없는 문제라는 걸 알 수 있다.;; 실용성도 아주 높고 말이다. 오죽했으면 엘베 관제는 1989년 제1회 국제 정보 올림피아드의 문제로 나오기도 했다.
층수가 20? 30? 정도 넘어가면 주행 속도도 굉장히 빨라져서 도착하기 수 층 전부터 감속하는 게 느껴지는 고속 엘리베이터가 투입되는 듯한데.. 이런 건 본인도 태어나서 지금까지 경험한 게 극소수이다. 엘베가 다 같은 엘베가 아닌 듯하다.
딱 층에 맞게 정차하는 건 지하철 전동차가 역의 정차 위치에 정확하게 맞춰서 정지하는 것과 비슷한 테크닉이라 하겠다.

2.
고층 건물에서 다수의 엘리베이터를 분배하는 알고리즘은 자동차를 통제하는 신호 알고리즘과도 비슷한 구석이 있다.
특히, 도로 상황을 전혀 고려하지 않고 그냥 무조건 일정 간격으로 적록 신호를 주는 게 엘베로 치면 무식하게 홀/짝, 고/저를 나눈 것과 비슷하다.

모든 방향에서 차들이 엄청 많이 다닐 때는 묻지도 따지지도 말고 그렇게만 해도 충분히 공평하다. 그러나 차량 통행이 아주 적을 때도 그렇게 하면 쓸데없는 대기 시간이 길어져서 비효율적이고 불편하다.
그래서 작은 도로에서는 평소에는 적록 신호이다가 심야에는 황색 점멸로 신호가 바뀌어서 일말의 스마트함을 추구하기는 하는데.. 신호 종류가 바뀌는 기준은 그냥 밤 11시에서 아침 6시 사이처럼 미리 지정된, '하드코딩'된 시간대일 뿐인 게 좀 아쉽다.

그러니 미래에는 신호라는 것도 더 스마트하게 바뀌어야 하리라 생각된다. 아까 그 엘리베이터 분배 알고리즘에서 하던 고민이 그대로 적용된다. 트래픽이 많을 때와 적을 때의 전략이 서로 크게 달라지는데, 그 경계 판단을 잘 해야 한다.
그래서 운전자가 시험 든다거나 분노해서 신호를 위반하려는 충동을 느끼지 않게 해야 한다. (1) 다니는 차가 아무도 없는데 빨간불이어서 쓸데없이 멀뚱멀뚱 서 있는 것, 그리고 (2) "왜 나만 갖고 그래~ 왜 교차로마다 계속 신호에 걸리는 거야..?? 이런 걸 아주 없애지는 못하더라도 최소화해야 할 것이다.

좌회전을 위해서 비보호나 점멸 대신 감응 신호가 더 늘어나고, 교차로 건너편이 계속 막히고 있으면 애초에 파란불이 되지 않게 신호등이 더 똑똑해져야 할 것이다.
비보호를 대체하는 좌회전 감응 신호는 좌회전 차량이 요청하자마자 무작정 맞은편 방향을 틀어막는 게 아니다. 처음 20~30초 정도 동안은 맞은편에 차가 없어서 충분히 안전할 때만 파란불 신호를 준다. 그렇지 않고 너무 오랫동안 좌회전을 못 하고 있으면 그때에야 불가피하게 맞은편 방향을 막고 파란불 신호를 준다.

이전글에서 언급했던 것처럼 교차로 건너편에 차가 들어갈 자리가 없으면 우리 신호가 돌아왔더라도 파란불 신호를 주지 않는 것도 덤.. 꼬리물기도 원천 차단된다.
이런 스마트 신호 체계 하에서는 교통법규 위반 건수가 줄어들고 교통사고도 자연히 더 줄어들 것이다.

Posted by 사무엘

2023/04/03 08:35 2023/04/03 08:35
, , ,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/2144

1. 성능과 알고리즘

(1) 현실의 퀵 정렬 알고리즘 구현체는 구간의 크기가 일정 기준 이하로 작아지면 그냥 O(n^2) 복잡도의 단순한 삽입 정렬로 대체하곤 한다. 그게 더 효율적이기 때문이다.

(2) 균형 잡힌 트리는 삽입, 탐색, 삭제가 모두 O(log n)의 복잡도로 되는 매우 유용한 자료구조이다. 그렇기 때문에 단순히 메모리 레벨의 set이나 map 컨테이너뿐만 아니라 파일 시스템이나 DB 같은 디스크 레벨에서도 쓰인다.
요즘 아무렇게나 DIR을 해도 파일 목록이 언제나 ABC 순으로 정렬되어 출력되는 이유는.. NTFS 파일 시스템이 내부적으로 이런 트리 구조를 사용하기 때문이다. (반면, 과거의 재래식 FAT는 연결 리스트 기반이어서 파일 목록의 정렬이 보장되지 않음)

단, 디스크 레벨에서는 단순한 이진 나무가 아니라, 이를 변형하여 한 노드에 딸린 자식이 좀 더 많은 B+ 같은 트리 구조가 쓰인다. 왜냐하면 디스크는 메모리보다 입출력 속도가 훨씬 더 느리며 랜덤 지점 탐색에 취약하기 때문이다.
그래서 한 노드 안에서 선형 검색을 좀 더 하더라도, 노드 하나를 탐색하고 읽는 횟수를 줄이는 게 더 이득이다. 다만, 이런 이념도 재래식 하드디스크가 아니라 플래시 메모리에서는 유효하지 않을 수 있다.

(3) 한 번에 한 스레드만 접근 가능해야 하는 코드가 있다면 보통 그 구간을 critical section이나 뮤텍스 따위로 둘러싼다.
그런데 이것도 "어? 다른 스레드가 이미 들어가 있네? 그럼 우리는 닥치고 바로 대기".. 이렇게 단순무식하게 하는 것보다,
loop을 돌면서 busy waiting, polling, spin lock을 n번만 더 시도해 보고 "그래도 여전히 다른 스레드가 나가지 않았으면 그때 대기 타자" 이런 유도리 전략이 좀 더 효율적일 때가 있다.

왜? 대기를 탔다가 깨어나는 작업 자체가 사용자 모드에서 커널 모드로 들어갔다가 나오는 것이며, 수천 사이클에 달하는 CPU 오버헤드를 요구하기 때문이다. 대기하고 있는 스레드는 CPU를 먹지 않지만, 대기 상태로 들어가거나 깨어나는 출입 과정은 공짜가 아닌 것이다.

더구나 요즘 컴퓨터는 코어가 여럿 있기 때문에 한 스레드에서 아주 잠깐 무식한 busy waiting을 하더라도 그게 타 스레드의 실행 성능에 영향을 주지 않는다. 그럴수록 대기 진입을 한 템포 늦춰서 신중하게 하는 게 가성비가 더 커진다.

일상 생활에다 비유하자면, 여러 잡다한 물건을 들고 있어서 무거운 채로 엘리베이터나 버스를 기다리는 것과 비슷하다. 이걸 바닥에 완전히 내려놓아 버렸다면 팔이 힘들지는 않지만, 그걸 다시 집어드는 것도 굉장히 번거로운 일이 된다. 그러니 버스나 엘리베이터가 수 초 안으로 금방 온다면 그냥 그 물건들을 들고 기다리고 있는 게 더 낫다.

이렇듯, 컴퓨터에서는 성능을 최대화하기 위해 한 방법만으로 만족하지 않고, 상황에 따라.. 특히 아주 제한된 문맥에서는 통상적으로 비효율적이라고 알려진 무식한 방법까지도 동원한다는 걸 알 수 있다. 스타로 치면 여러 유닛을 조합하는 것과 같다.

2. 자원의 회수

식물은 죽어서 말라 비틀어진 잎· 줄기나 썩은 열매 따위의 처리가 아주 간편한 축에 든다. 땅에 파묻기만 하면 거름이 되고 도로 자연으로 돌아가고 구성 물질이 회수된다.
뭐, 동물도 궁극적으로 그렇게 되기는 한다. 하지만 사체가 분해되는 과정이 식물보다 훨씬 더 더럽고 끔찍하고 더 오래 걸리는 편이다.

이런 물질의 순환은 뭔가.. 가상 머신에서 GC에 의해 자동 관리되는 메모리 같다는 생각이 들지 않는지?
본격적으로 물질의 메모리 누수가 문제되기 시작한 건 인류가 자연이 제대로 감당하지 못하는 플라스틱 같은 고분자 화합물을 만들어서 쓰기 시작하고부터이다. 그리고 반감기가 끔찍하게 긴 방사능 물질도 이런 범주에 든다고 볼 수 있겠다.

뭐, 썩지 않는 물질이 다 문제이고 골칫거리는 아니다. 수도관 같은 건 절대로 부식되거나 썩지 않는 재료로 만들어서 수백, 수천 년은 써야 할 테니 말이다.

3. 코드

(1) 우리나라의 모든 법조문들이 몽땅 github에 올라오고, 전체 개정 이력을 Show log 명령을 통해서 조회하고 싶다는 생각이 든다. 전철 노선도 같은 물건도 마찬가지이다.

(2) 대학교 컴터공학과 학부에서 시스템 프로그래밍 시간에 MIPS 어셈블리어 갖고 깨작깨작 실습하는 건.. 육사에서 승마나 백병전 총검술 잠깐 맛보기 하는 것과 정확하게 대응하지 싶다~ ㅋㅋㅋ
학교에서 뭔가 C/C++, Java, Python 같은 실용적인(?) 언어 말고 뭔가 비현실적인 언어를 다뤄 보는 게 이렇게 어셈블리어 같은 레거시 계열, 아니면 엄청나게 순수한 이론 이상을 추구하는 함수형 언어 계열.. 이렇게 둘로 나뉘는 듯하다.

(3) 자동차 취급설명서는 소스 코드 곳곳에 들어서 있는 조건부 컴파일의 완벽한 예시로 보인다. * 표시가 돼 있는 각종 선택사양들.. 그리고 악보의 음표 위에 붙은 각종 나타냄말? 스타카토, 스타카티시모 이런 건 매크로의 예시이다.
악보는 각종 반복과 분기가 복잡하게 꼬이면 흐름이 진짜로 어지간한 프로그램 코드처럼 바뀌기도 한다.

(4) 성경에서 '주의 책', '(어린양의) 생명책' 같은 상상 속의 거대한 책이 언급된 걸 보면.. 예수 믿는 컴터쟁이들은 하늘나라에 있는 거대한 데이터베이스와 DB 서버 정도는 떠올릴 수 있을 것 같다.
물론 인간이 만든 컴퓨터는 신의 주요 성품 중 하나인 '무한, 영원'이라는 걸 절대로 구현하지 못하는 물건이다. 그러니 DB 드립은 마치 "김 성모 스타일의 성경 이야기"만큼이나 그냥 웃자고 늘어놓는 말일 뿐이다.

(5) 요한복음의 마지막 구절인 "이 세상이라도 예수님의 행적을 기록한 책들을 다 담지 못할 것이다"는 정보량과 관련된 언급이다. 그리고 삼손의 수수께끼 놀이는 정보 보호· 보안과 관련된 통찰을 주는 이야기이다.

4. 자동과 수동

요즘 수동 변속기 차량을 몰 줄 아는 사람이 갈수록 드물어지듯, 컴터 업계도 C/C++처럼 메모리를 수동으로 관리하는 저급 언어를 제대로 다룰 줄 아는 사람이 갈수록 드물어지는 것 같다.
직장에서 부사수로 들어온 어린 신입 개발자에게 사수가 메모리 leak이라는 개념을 알려주는 게 굉장히 뜻밖이고 놀라워 보였다.

하긴, 공대 1학년의 기초 필수 프로그래밍 과목에서 가르치는 언어도 초창기엔 C/파스칼이다가 나중에 Java를 거쳐 지금은 파이썬이지 않은가. 프로그래밍을 위한 전산학적인 소양하고, C나 컴퓨터 특유의 지저분한 감각이랄까, 이 둘이 영역이 완전히 일치하지는 않기 때문이다.

고깃집의 경우, 직원이 알아서 고기를 다 썰고 구워 주는 곳은 자동 변속기-_- 같고, 손님이 직접 고기를 얹고 굽고 자르고 뒤집어야 하는 곳은 수동=_=;;에 해당된다. 후자보다는 전자가 아무래도 마음 편하게 고기를 먹을 수 있지만.. 인건비가 추가되어 고기값이 더 비쌀 것이다.

5. 전체 리셋

컴퓨터 시스템을 날리는 방법으로 sudo rm -rf 라든가=_= Windows의 레지스트리 날리기, 시스템 디렉터리 날리기 같은 게 있다.
운영체제가 아닌 DB에서는 delete * 내지 drop table 같은 파괴적인 쿼리가 있다. 손가락 까딱 잘못 건드려서 회사 재산과 관련된 DB를 날렸다간 짤리는 정도를 넘어 손해 배상 소송을 당할 수도 있을 것이다.

그런데 국가로 치면.. 헌법 제1조가 바뀌거나 날아가는 게 그런 급의 파괴적인 사건일 것이다. 헌정 체제가 쿠데타로 인해 싹 뒤집히거나, 아니면 전쟁에서 지기라도 해서 외적이 자국 행정부를 완전히 접수했을 때에나 있을 수 있는 일이다.

우리나라의 경우, 옛날에는 "대한민국은 민주공화국이다" 같은 몇몇 조항은 개헌조차 아예 영원히 불가능한 조항으로 못 박으려는 시도가 있었다. 컴퓨터로 치면 운영체제의 작동과 직접적인 관련이 있는 일부 시스템 파일을 절대 변조· 삭제할 수 없게 특수하게 보호하는 것과 비슷하다고 하겠다(업데이트 받을 때만 빼고).

하지만 법리적으로 볼 때 그렇게까지 할 필요는 없기 때문에 개헌 불가 조항 같은 건 과거의 해프닝으로 끝났다. 그리고 지금 6공화국 헌법은 그렇잖아도 개헌이 너무 어려운 형태가 된 감이 좀 있다.;; 과거에 널뛰기 하듯이 수시로 개헌하던 관행을 없애고 싶었던 심정은 이해가 가지만 지금은 그것 때문에 미래까지 발목이 잡힌 것 같다.

6. C++ export와 우주왕복선

2000년대 초에.. EDG 같은 일부 C++ 컴파일러 개발사에서는 희대의 흑역사 표준 기능이던 export를 구현하느라 상상을 초월하는 삽질을 했던 거랑,
NASA에서 2003년의 컬럼비아 우주왕복선 사고 이후에 이제는 우주왕복선을 띄울 때마다 옆에 구조용 예비 기체까지 같이 대기시키면서 정말 눈물겨운 삽질을 잠시 했던 것..
둘이 시기도 비슷하고 심상이 뭔가 묘하게 비슷하게 느껴진다.

전자는 지금까지 C++ 표준에 새로 추가되었던 복잡한 기능들과는 구현 난이도가 차원이 달랐다. 기존 언어 구조의 근간을 다 뒤엎어야 하는 헬 수준이었는데, 그렇다고 템플릿의 모듈화를 제대로 실현해 주는 것도 아니었다. 이건 정말 백해무익에 가까운 미친 짓이었다. 결국 export는 2010년대 C++11에서는 완전히 삭제되었다.

우주왕복선에다가 구조 미션까지 추가한 것 역시.. 셔틀 한 대에다가 사람을 11명이나 태우는 것(기존 승무원 7 + 구조 요원 4), 안 그래도 3대밖에 없는 셔틀을 매번 2대나 세팅해야 하는 것, 묘기에 가까운 어렵고 위험한 기동으로 조난 당한 셔틀에 접근해서 사람을 구조하는 것..
살인적인 비용 대비 사람을 살릴 가능성도 별로 없는 미친 짓이었다. 다행히 이 미션이 실전에서 쓰인 적은 없었으며, 우주왕복선 역시 C++11과 비슷한 시기인 2011년에 완전히 퇴역했다.

7. 나머지

(1) 생물은 번식할 때 동물과 식물을 막론하고 가까운 혈통끼리 교배하지 말고, 최대한 먼 촌수끼리 다양하게 섞여서 교배해야 유전병 없이 건강한 후세가 태어나고 안전하다고 여겨진다. 유전적 다양성이란 게 중요하다.
이런 걸 뭔가 숫자의 특성으로 표현하면 해시값의 충돌이 안 나는 것, 셸 정렬이 빠르게 수행되는 간격 수열을 구하는 것(무식하게 2^n에서 절반씩 줄이는 건 최악), 퀵 정렬의 pivot 중간값을 적절하게 잘 고르는 것에 대응하는 것 같다.

(2) 자동차나 자전거 운전하다가 상대방과 부딪칠 것 같아서 한쪽으로 피하는데..
골때리게도 상대방도 내가 피하는 방향과 같은 방향으로 피하고, 이 상황을 탈피하지 못해서 결국 부딪히는 경우가 있을 수 있다.
이런 게 머신러닝이나 방정식 근 찾기에다 비유하자면 처음에 시작점을 잘못 잡고 학습을 잘못 시켜서 최적해로 수렴을 못 하고 삼천포로 빠진 것과 비슷해 보이는 상황이다. 아니면 데드락을 극복하지 못했거나.;;.

(3) 옛날, 1955년쯤에 중공의 마오 주석께서는 하늘을 향해 삿대질을 하며 "저 새는 해로운 새.." 아니, "참새는 해로운 새"라고 교시하시였다는데..
1968년쯤에 네덜란드의 전산학자 다익스트라는 ACM 저널을 통해 "GOTO Considered Harmful".. 즉, 스파게티 코딩이 해롭다고 저격했었다. 오늘날은 저 두 말투가 모두 밈..처럼 쓰이고 있다. ㅋㅋㅋ

Posted by 사무엘

2022/07/11 08:35 2022/07/11 08:35
,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/2041

1. 숫자를 표현하는 방식

20세기 중반에 컴퓨터가 아직 진공관 기반으로 만들어지던 시절에는 전기식이 아닌 전자식으로 바뀐 것뿐만 아니라 10진법 대신 순수 2진법을 사용하기 시작한 게 큰 전환점으로 여겨진다. 그게 더 기계 지향적이고 직관적인 설계이기 때문이다.

이건 사람으로 치면 별도의 교육을 통해 암산 때 머릿속에서 아라비아 숫자 대신 주판알을 떠올리는 것과 비슷하지 않을까 싶다. 아라비아 숫자는 문자로서 실용적인 기능도 겸하려다 보니, 숫자의 본질과 연산에 직관적으로 대응하는 체계가 아니기 때문이다.
심지어 주판법에는 선주법과 후주법이 모두 존재한다. 이건 컴퓨터에서 big/little endianness와 거의 동일한 개념인 것 같다.

2. 색공간과 실제 공간

우리가 사는 현실의 공간은 길이· 너비· 높이라는 xyz 세 축, 즉 3차원이라고 여겨진다.
그런데 우리에게 시각을 인지시켜 주는 색이라는 것도 어떤 형태로 축을 나누든.. RGB건 HSL이건 CMY건 결국 3개의 축으로 이뤄진다는 게 시사하는 바가 커 보인다.
가령, 색에서 hue라고 불리는 빨주노초~파남보 요소는 가시광선 파장의 차이라는 1차원 축으로 변별된다. 하지만 채도(S)와 명도(L)는 또 다른 차원의 변수라는 것이다.

컴퓨터의 그래픽 카드에서는 RGB 각 축에 대해 8비트의 정보량을 부여해서 총 2^24, 1600여 만 가지 색상을 제공하곤 하는데, 정작 1픽셀의 크기는 3바이트 24비트가 아니다. 컴퓨터가 처리하기 편한 단위인 4바이트 32비트 단위를 사용하며, 나머지 남는 8비트에다가는 픽셀의 알파 채널 정보를 넣곤 한다. 이건 여러 이미지를 부드럽게 합칠 때 활용된다.

알파 채널은 색깔을 나타내는 축 자체는 아니지만 색의 표현과 관계 있는 정보이다. 이걸 포함한 pixel format을 RGBA 구조라고 한다. 하지만 Windows의 GDI API는 1980년대에 개발되었으며, 픽셀에서 상위 8비트를 팔레트 등 독자적인 다른 용도로 이미 사용하다 보니 훗날 알파 채널을 제대로 지원하지 못하는 촌극이 벌어졌다. 그 역할은 GDI+ 등 후대의 API가 계승하게 됐다.

RGBA라는 개념은 물리학에서 XYZ 공간 세 축에다가 시간을 더한 XYZT 4차원과 뭔가 비슷하게 느껴진다.;; 그것도 기하학적 의미에서 정확한 4차원을 말하는 건 아니니 말이다. 하긴, 생각해 보니 3차원 컴퓨터그래픽에서는 픽셀마다 알파 채널이 아니라 Z buffer 값이 부가 정보로 들어가기도 한다.

3. 구 그리기

중고교 미술 시간에는 4B 연필 한 자루 들고 스케치북에다가 구를 그리는 데생(?) 실습을 해 보고.. 이과 나와서 컴공 전산을 전공한다면, 구 렌더링 정도는 C 코딩으로 저수준부터 뚝딱뚝딱 짜 봤으면 싶다.
둘이 매우 훌륭한 대조가 되리라 생각된다~! 후자의 경우, 구를 렌더링 하라고 openGL 셰이더 명령 한 줄 던져주고 끗~~이 아니라, 저 모든 픽셀의 RGB 값을 직접 계산해서 구하는 것을 말한다.

사용자 삽입 이미지

(본인이 직접 그리거나 생성한 그림이 아니니 오해하지 말 것! ㄲㄲㄲ)

이 픽셀이 구의 영역에 포함돼 있는지, 있다면 거리가 얼마나 되는지를 구의 방정식으로부터 구하고, 광원으로부터는 거리가 얼마나 되고 빛과 면이 접하는 각도가 어찌 되는지.. 최종적으로 밝기가 얼마가 돼야 하는지를 직접 공식 집어넣어서 계산으로 구한다는 뜻이다.

그림자까지 생각하면 일이 너무 어려워질지 모르니 필수가 아닌 옵션으로 남긴다만, 구 자체만이라도..;;
그럼 이 엄청난 계산을 실시간 애니메이션 수준으로 해내는 오늘날 PC와 폰의 그래픽 카드들이 얼마나 대단한 물건인지도 알 수 있을 것이다.

이런 이론 공부 잉여질 체험을 회사 취업한 뒤에 직장에서 할 수는 없을 것이고, 취업 목적 코딩 학원에서 할 수도 없을 것이다. 그러니 아직 학생일 때 학교에서 해야지...!!

4. AI

요즘 아시다시피 AI니 머신러닝이니 하는 분야가 아주 각광받고 있다. 현실에서의 문제의 목표와 input/output을 머신러닝 라이브러리가 이해하고 해결할 수 있는 형태로 변환하고, 데이터를 학습시키고 결과물을 얻는 건 확실히 학교에서 맛보기로나마 가르칠 필요가 있어 보인다.

자연어 처리라든가 영상에서 뭔가를 인식하기, ‘관련 추천 아이템 제시’ 같은 분야에서 요즘 AI들은 정말 눈부시게 똑똑해지고 기술이 발달해 있다.
개인적으로 좀 개발됐으면 하는 AI는 “문자열을 보고 폰트 종류 판별하기”, 그리고 “넓은 군중 사진을 보고는 여기에 사람이 몇 명이나 있나 추산하기”이다.

요즘은 AI를 통해 없는 정보를 유추해 내서 흑백 사진도 컬러로 얼추 복원하고, 흐릿한 영상을 선명하게 바꾸기도 한다. 그런 계산 능력이면 폰트 종류 유추는 말할 것도 없고, 이런 획이 요런 모양이었으니 다른 글자는 요런 모양이어야 하겠다는 것까지 유추를 못 할 이유가 없다. 그러면 한글이나 한자 같은 폰트를 만드는 일이 노가다가 줄어들고 한결 수월해질 것이다.

군중 사진에서 머릿수 카운트도.. 쉬울 것 같으면서도 은근히 어려울 수 있어 보인다. 하지만 기술적으로 불가능한 일은 절대 아닐 것이다. 이를 응용하면 사진에 찍힌 쌀알이나 콩알 개수를 세게 할 수도 있다.

지금 Google 검색은 영어는 정말 사람 말을 알아듣고 인간의 두뇌 활동을 어느 정도 흉내 내는 경지에 도달해 있다. 경악스럽게 그지없다. 유튜브 동영상에서 영어 자막을 자동 생성하는 걸 보면.. 어지간한 음성은 다 정확하게 알아듣는다.

여주인공이 격투를 벌이는 어느 첩보 영화의 제목을 까맣게 잊어버려서 “2017 female spy movie”라고만 쳤는데.. 우와, 저것만 토대로 Atomic Blonde라는 영화를 딱 정확하게 알아 맞히려면 도대체 저 영화의 특성을 어디까지 다 파악하고 있어야 되는 걸까..?
정말 외계인을 고문하는 기업이 아닐 수 없다.

꼭 인텔처럼 컴퓨터의 하드웨어 근간인 반도체의 본좌가 아니어도, 마소처럼 소프트웨어의 근간인 운영체제를 꽉 독점하고 있지 않아도 된다. 그 위에서 돌아가는 소프트웨어 내지 웹 서비스 중에서도 억 소리 나는 기술을 개발할 것들이 저렇게 넘쳐난다.;;

5. 암호 해독과 번역

난해한 수수께끼 암호를 풀기 위해 과거에는 언어학자가 동원되었다. 뭐, 보이니치 문서라든가 롱고롱고 문자, 로제타석처럼 인간이 만든 난해 정보를 해독할 때야 당연히 해당 지역의 고대 언어를 아는 것이 도움이 될 것이다.
하지만 현재의 군사 내지 보안 암호는 인간이 아닌 기계가 생성하다 보니 언어적인 요소가 전혀 동원되지 않으며, 오로지 수학자의 직관만이 필요하다. 2차 세계 대전 때 앨런 튜링이 독일군 에니그마 암호를 풀 때 딱히 독일어 지식이 쓰이지는 않은 것과 같은 이치이다.

기계번역도 이와 비슷한 맥락의 변화를 겪고 있다. 기계번역 시스템을 개발하는 데 입력 언어나 출력 언어의 전문가 내지 언어학자가 동원되지 않는다. 그냥 전산학자, 데이터 과학자, 머신 러닝 전문가가 동원된다.
취급하는 언어의 고유한 특성은 기계번역 시스템의 동작에 영향을 주지 않는다는 것이 한편으로는 굉장히 섬뜩한 점이다. 기계가 자연어든 암호문이든 언어 데이터를 취급하는 방식 자체가 근본적으로 바뀐 것이다.

6. 다중 상속

객체지향 패러다임에서 다중 상속이라는 걸 생각해 보자. 클래스가 기반 클래스를 하나만 두는 게 평범하고 일반적이고 권장되는 반면, 얘는 좀 특수한 상황에서 "논란과 무리수를 감수하고라도 둘 이상 갖는 것"이라는 특성이 있다.

이걸 인생에다가 투영해 보면 좀 뜬금없는 얘기지만 일부다처...;; 내지 복수 국적과 비슷한 것 같다.
C++에서 다중 상속을 지원해 봤는데.. 이건 좀 아니다 싶었는지 후대의 객체지향 언어들은 생짜 다중 상속은 금지하고, 데이터 멤버가 없는 인터페이스에 대해서만 복수 구현을 허용했다. class A extends B implements C,D,E처럼 말인데.. 이건 일부일처다첩-_-;;;처럼 들린다.

우리나라는 조선은 말할 것도 없고 일제 시대와 대한민국 초기에 이르기까지 오랫동안.. 일부다처체는 아니지만 첩이라는 게 관행적으로 있었다.
그러다가 1960년대, 박 정희 때 사회 구조를 대대적으로 뜯어고치면서 공무원들부터 첩을 두는 게 금지되었고(있으면 직장에서 징계=_=), 완전한 일부일처제가 자리잡았다.

이게 대놓고 불륜을 조장한다기보다는.. 전근대 시절엔 지금처럼 미혼 여성이 혼자 돈 벌고 사회 생활을 하는 게 도저히 가능하거나 용납되지 않았기 때문이다. 서로 필요하기 때문에 작은 마누라라는 게 존재했었다.

이런 결혼 말고 복수 국적도.. 나라마다 허용되는 정도가 케바케이고 우리나라는 징병제 병역 때문에 더 민감한 측면이 있다. 자기 원래 국적을 유지한 채로 외국의 영주권을 취득할 수는 있지만 완전히 시민권, 국적을 취득하는 건 또 별개의 문제가 된다.
우리나라의 경우, 이 대한민국 땅에 있을 때만은 한국 국적만 행사해야 한다는 각서를 쓴 뒤에 외국인의 복수 국적 취득을 허용한다.

국적 말고 이중학적, 이중인격 이런 건 명백하게 비정상일 것이다. =_=;;

Posted by 사무엘

2022/04/18 08:33 2022/04/18 08:33
, ,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/2010

우리는 컴퓨터라는 건 20세기 중후반에 “(1) 진공관 → (2) 트랜지스터  (3) IC 회로  (4) 그 이후 LSI/VLSI 집적회로”의 순으로 내부 부품이 고도화· 첨단화돼 왔다고 배웠다. 집적회로 안에 트랜지스터가 몇천, 몇만 개씩 들어있고 0의 개수가 뻥튀기됐다고 말이다.
이 덕분에 컴퓨터는 메모리도 기하급수적으로 증가하고 속도도 기하급수적으로 빨라지면서 시공간이 워프 됐다. 그러면서 정작 자기 자신의 크기는 놀라울 정도로 작아져서 드디어 개인용 컴퓨터(PC)라는 것까지 존재할 수 있게 됐다.

더 세부적인 역사를 살펴보자면, 컴퓨터는 아직 1세대 시절에 “(1) 전동식이던 것이 완전 전자식으로 변모, (2) 10진법 대신 순수 2진법 기반, (3) 튜링 완전, (4) 프로그램 내장형”이라는 큰 격변을 거쳤다. 이에 대해서는 본인은 수 년 전에 글을 쓴 적이 있다.
특히 (3)을 통해 컴퓨터는 동적 메모리 접근과 능동적인 로직 구현, 즉 프로그래밍이란 게 가능해졌다. 그리고 (4)를 통해 메모리에 코드와 데이터가 모두 적재되고 소프트웨어라는 것이 존재할 수 있게 됐다.

그 다음으로 후대의 전자식 개인용 컴퓨터의 역사를 논할 때 적용할 수 있는 잣대는 바로.. CPU가 한 번에 취급하는 정보량의 단위 크기이다. 이것도 8, 16, 32, 64비트라는 네 단계로 구분할 수 있는데, 각 단계별로 정말 유의미한 변화가 있었다.
이 내역을 살펴보면 다음과 같다. “라떼는 말이야 컴퓨터가.. 그땐 그랬지!” 소리가 절로 나올 것이다.

1. 8비트 (1980년대 초)

  • 기종간 파편화가 엄청 심했다.
  • 보통 모니터+본체, 또는 본체+키보드 일체형.
  • 아무것도 안 꽂고 켜면 롬 베이식이 들어있곤 했다.

8비트 컴은 화면 해상도가 너무 낮아서 한글 한자 표현이 난감했다. 한 화면 전체의 정보량이 겨우 64KB에 머물러 있었을 뿐만 아니라, 이 등급의 컴퓨터는 메모리로나 처리 속도로나 8*8 256자짜리 라틴 알파벳 외의 다른 문자를 취급하는 건 영 메롱이었다.
(일본이 1980년대에 다른 분야가 아니라 게임에서 온갖 창의적인 작품을 내놓으며 펄펄 날았던 이유 중 하나도.. 짐작 가능하다시피 업무용이 아니니 자국 문자 처리를 별로 신경 쓸 필요가 없는 분야이었기 때문일 것이다. ㅡ,.ㅡ;; )

그리고 이때는 C 컴파일러조차 사치품이었다. 제품 가격으로나, 구동 요구 조건으로나, 생성된 코드의 성능으로나..
그러니 본격적인 프로그래밍을 위해서는 어셈블리어가 필수였다. 물론 이 시절 컴퓨터의 어셈블리어는 요즘 컴퓨터의 어셈블리어보다는 훨~~씬 더 단순하긴 했다.

8비트는 임베디드가 아니라 사람이 직접 다루는 개인용 컴터의 최소 마지노 선이나 다름없다고 하겠다.
그나마 얘는 1바이트의 정보량을 오늘날처럼 1옥텟과 동일한 8비트로 고정했다는 의의가 있었다. 더 옛날 컴퓨터들은 1바이트의 크기가 이보다 더 작고 들쭉날쭉이기도 했다~!

2. 16비트 (1980년대 말)

  • 뭔가 현대적인 컴퓨터 외형이 이때 갖춰졌다. 바이오스와 운영체제가 더 분명하게 분리됐다.
  • 모니터, 본체, 키보드가 모두 분리됐다. 그리고 테이프나 롬팩 대신 디스켓, 하드디스크.
  • 재귀적인 디렉터리 구조가 존재하는 파일 시스템.
  • IBM 호환 PC, 교육용 PC 등등 표준화 규격도 정착

과거 MS-DOS 2.0이 바로 CP/M에서 비롯됐던 8비트 잔재를 16비트로 확장한 것에 가까웠다. COM 대신 EXE, 재귀적인 디렉터리 구조 같은 것 말이다.

8비트에서 16비트로 넘어가고부터 모니터에 찍히는 글자의 크기부터가 확 작아지고 화면이 큼직해졌다. 640*480급의 고(?)해상도에서 14~16픽셀 크기의 글꼴이 지원되기 시작했기 때문이다. 저해상도에서는 256색 이상 색깔을 더 많이 표현할 수 있게 됐고.. 물론 이를 실제로 구경하려면 그에 상응하는 비싼 그래픽 카드와 컬러 모니터도 필요했다.

3. 32비트 (1990년대 초중반)

주소 공간이 그럭저럭 꽤 넓어진 덕분에.. 이제야 현대적인 컴퓨터의 내부 구조를 좀 제대로 실현할 수 있게 됐다. 가상 메모리, 보호 모드, 선점형 멀티태스킹/멀티스레딩.. 그리고 80386은 가상 메모리 구현을 위한 메모리 주소 매핑을 CPU 차원에서 바로 지원하기 시작했다.
각종 메모리에서 지긋지긋한 64KB 제약이 없어지고, 이 제약을 우회하려는 온갖 지저분한 꼼수 기법들을 익힐 필요가 없어졌다. (메모리 모델, EMS, XMS 등등)

32비트는 아키텍처가 오랫동안 안정되어서 굉장히 장수한 시기이다. 80386 이후로 486, 펜티엄 시리즈 등의 여러 CPU들이 등장했지만 얘들은 전부 32비트였다.
80486부터 캐시 메모리가 첫 등장했으며, 부동소수점 보조 프로세서가 CPU에 내장되기 시작했지만, 이런 건 소프트웨어의 호환성에 영향을 주는 변화가 아니다. 286에서 동작하지 않는 386 32비트 전용 프로그램은 엄청 많지만, 486에서만 동작하고 386에서는 동작하지 않는 프로그램은..?? 거의 없다는 것이다.

이제 PC와 워크스테이션이라는 체급 구분이 서서히 없어졌다. 3D 그래픽 렌더링도 Windows나 mac에서 바로..

4. 64비트 (2000년대 중후반)

64비트는 그냥 4GB 제약이 없어진 32비트의 연장선에 가깝다. 이전의 32비트에서 컴퓨터의 근간이 다 완성된 거나 마찬가지이기 때문이다.
PC에서 64비트는 멀티코어 패러다임과 비슷한 시기에 등장하고 보편화됐다. (인텔 Core2 Duo CPU) 그래서 32비트 전용 멀티코어나 64비트 싱글코어 CPU는 거의 존재감 없다.

이제는 슈퍼컴퓨터 전용 아키텍처라는 것도 없어졌다.
그런데.. 메인프레임은 Cray도 아니고 x86도 아니고.. 몇 비트짜리에 무슨 아키텍처와 어떤 특성을 가진 컴퓨터인지?? 난 잘 모르겠다.

옛날에는 억대의 슈퍼컴퓨터나 64비트 CPU를 썼지만, 지금은 주머니에 넣고 다니는 스마트폰의 CPU조차 다 64비트이다. 작다고 해서 16비트/32비트 따위를 쓰지는 않음. 요즘은 경전철이라고 구닥다리 협궤를 쓰지는 않는 것과 비슷한 이치이다(철차륜).
이제 모바일은 모바일이지, 임베디드와는 영역이 많이 달라졌음을 뜻한다. 전광판이나 자판기 같은 것에 들어가는 8비트 임베디드 MCU는 철도에다 비유하면 탄광 안에다 부설한 미니 협궤에 대응할 것이다. 채굴한 광물을 실어 나르는 용도이지, 여객용이 아니다.

※ 여담

(1) 8비트 시절에 화면 해상도가 얼마나 낮았는지를 실감해 보자.. 터미널 콘솔 하나 얹기도 버거워 보이는 환경에서도 무려 GUI를 만든 용자가 있긴 했다. ㄷㄷㄷㄷ

사용자 삽입 이미지

사용자 삽입 이미지
사용자 삽입 이미지
COMMODORE 64에서 64란, CPU가 64비트...는 개뿔, 메모리가 64KB라는 뜻이었다. ㄷㄷㄷㄷㄷ

(2) 옛날에 펜티엄 CPU가 등장했을 때는 이게 64비트라고 말이 많았다. 하지만, 펜티엄이 64비트로 확장한 건 주메모리와 CPU 사이의 데이터 버스의 대역폭뿐이다. 명령 집합, 레지스터 같은 내부 구조와 실질적인 동작이 64비트 단위로 돌아가는 건 당연히 아니다. 반대로 옛날에 386 SX는 원가를 낮추기 위해 CPU만 32비트이고 데이터 버스는 16비트였다.

(3) Windows NT의 구버전은 DEC Alpha 같은 64비트 CPU를 지원했던 적이 있다. 하지만 운영체제 자체는 여전히 32비트 기준으로만 동작했기 때문에 64비트 성능을 제대로 발휘하지 못했다. 마치 동시대의 Windows 3.x가 386/486에서도 16비트 코드 기준으로 동작했던 것과 비슷하게 말이다. (일부 멀티태스킹 기능을 제공할 때만 386 CPU 기능을 사용)

Posted by 사무엘

2022/01/29 08:34 2022/01/29 08:34
,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/1980

컴퓨터 소프트웨어계에는 이미 작성되어 있는 프로그램을 실제로 돌려 보지 않고(샌드박스 가상 머신 안에서..) 형태만 들여다보고는 버퍼 오버런이나 메모리 누출 같은 잠재적 위험성 및 논리 결함을 어느 정도 찾아 주는 '정적 분석'이라는 기술이 존재한다. 그 프로그램이 기계어 바이너리 형태이건, 고급 언어 소스 코드이건 형태는 무엇이건 상관없다.

그런데 정적 분석 툴은 그 누가 만든 것이라도 원천적으로 이론적으로 근본적으로 100% 정확하게 작동하지는 못한다.
이에 대해서 "아니 소스 코드가 무슨 자유 의지를 지닌 생명체도 아닌데 그 뻔한 로직을 분석해서 결과를 사전 예측하는 게 그렇게 어려운가? 단순히 소모하는 메모리와 계산량만 많아서 어려운 거라면 컴퓨터의 성능빨로 극복 가능하지 않은가? AI 기술을 접목하면 되지 않는가?" 처럼 생각하기 쉽다.

하지만 그렇지 않다. 그 말은 저런 차원이 아니다.
그런 함수는 단순히 현실적으로 구현하기가 어려운 정도가 아니라 논리 차원에서 모순에 빠지며 존재 불가능하기 때문이다. "모든 창을 막는 방패와 모든 방패를 뚫는 창 세트"와 동급으로 존재 불가능하다~! 창이나 방패의 제조 기술과는 무관하게 말이다.

가장~~ 원초적인 정적 분석 프로그램을 생각해 보기로 한다.
분석할 대상인 프로그램 코드, 그리고 그 프로그램에다가 넘겨줄 입력 데이터.
이 둘을 인자로 받아서 이 프로그램의 시시콜콜한 무슨 메모리 문제 따위를 진단하는 게 아니라..
이 프로그램이 무한 루프에 빠지지 않고 실행이 종료되기는 할지를 정확하게 판단해 주는 bool DoesThisProgramReturn(func, argument) 라는 가상의 함수 프로그램을 생각해 보자.

argument는 현실의 프로그램으로 치자면 명령 인자뿐만 아니라 프로그램이 파일이나 네트워크 형태로 읽어들이는 방대한 입력 데이터까지 모두 포함하는 개념이다. "일괄 처리 형태가 아니라 입출력이 실시간으로 들어오는 프로그램은요?" 이건 이 시점에서 그리 중요한 문제가 아니니 논외로 한다.
func는 뭐.. C/C++로 치면 기계어 코드를 가리키는 함수 포인터 정도로 생각하면 이해하기 편하겠다.

당연한 말이지만 저 함수 자체는 절대로 무한 루프에 빠지지 않고 언제나 유한 시간 안에 답이 나오는 게 보장된다. 무한 루프에 빠지는 프로그램을 의뢰했더라도 말이다. 그러므로 DoesThisProgramReturn(DoesThisProgramReturn, xxx)는 xxx로 무엇을 넘겨주건 그 정의상 리턴값이 언제나 true가 된다.

그럼.. 저 가상의 함수는 어떤 식으로 동작할지를 생각해 보자.
func가 가리키는 코드를 읽으면서 while(true); 같은 패턴을 발견한다거나,
더 구체적으로는 예전에 한번 거쳤던 state와 동일한 state로 이미 지났던 지점을 또 지나는 게 감지되면.. 이 프로그램은 실행이 끝나지 않는다는 결론을 내릴 수 있을 것이다.

이거 만델브로트(망델브로) 집합을 그릴 때 주어진 복소수의 발산 여부를 판별하는 것과 비슷하게 느껴진다.
배배 꼬인 복잡한 프로그램에서는 좀 어렵겠지만 그래도 도저히 불가능한 문제는 아니어 보이는데..??

하지만 튜링 기계는 우리가 흔히 생각하는 것보다 자유도가 더 높은 계산 모델이다.
메모리에 저장된 주소값에 해당하는 다른 메모리의 값을 마음대로 읽고 쓸 수 있을 뿐만 아니라(= 포인터) 거기 저장된 데이터를 코드로 간주해서 실행할 수도 있다(= 함수 포인터).

재귀 호출도 되고.. 또 앞서 살펴보았듯이 DoesThisProgramReturn 자신조차도 튜링 기계에서 실행되는 함수이기 때문에 DoesThisProgramReturn의 인자로 전달할 수 있다. 그리고 분석 대상인 타 함수가 얘를 또 호출할 수도 있다.
이런 상황까지 다 허용 가능해야 한다면 DoesThisProgramReturn의 존재 가능성은 굉장히 난감해진다.

아래와 같이.. DoesThisProgramReturn가 true라고 판정한(= 실행이 끝난다) func에 대해서는 "반대로" 자신이 무한 루프로 가 버리고, 실행이 끝나지 않는 함수에 대해서는 실행을 끝내는 HangIfReturns이라는 함수를 정의해 보자.

bool HangIfReturns(func) {
    if (DoesThisProgramReturn(func, func)) while(true);
    return true;
}

그러니 HangIfReturns(DoesThisProgramReturn)을 하면.. 얘는 무한 루프에 빠지게 된다.
DoesThisProgramReturn은 자기 자신에 대해서는 앞서 정의한 바와 같이 언제나 true를 되돌리고(= 늘 깔끔하게 실행 종료) if문을 만족하기 때문이다. 여기까지는 쉽다.

하지만 반대로 HangIfReturns가 DoesThisProgramReturn의 인자로 들어가면 어떤 일이 벌어질까? DoesThisProgramReturn(HangIfReturns, HangIfReturns)는 리턴값이 무엇이 되는 게 이치에 맞을까? 이제 좀 머리가 복잡해질 것이다.

DoesThisProgramReturn(HangIfReturns, HangIfReturns)가 true라면.. HangIfReturns 안의 if문은 true가 되므로 HangIfReturns은 무한 루프에 빠진다. 그러면 저 함수의 리턴값은 원래 false가 되어야 하게 된다.
반대로 저 리턴값이 false라면.. 역시 이제 HangIfReturns는 실행이 깔끔하게 종료되므로 저 함수의 리턴값을 정면으로 부정하는 결과가 나온다.

요컨대 HangIfReturns가 무한 루프에 빠지는지의 여부는 DoesThisProgramReturn의 리턴값에 따라 달라지는데, 이 과정에서 서로 물고 무는 구조적인 모순이 발생하는 셈이다.
이 모순은 DoesThisProgramReturn라는 함수가 존재한다는 가정으로부터 비롯되었다. 그러니 튜링 기계 하에서 다른 코드의 실행 종료 여부를 완벽하게 판단하는 코드를 똑같은 튜링 기계 기반으로 구현하는 것은 불가능하다는 것이 입증된다.

이 논리는 "정지 문제"(halting problem)이라고 불리며, 컴퓨터라는 기계의 계산 가능 범위를 고민하게 하는 매우 탁월한 통찰이다. 이걸 처음으로 생각해서 논문으로 발표한 사람이 바로 그 이름도 유명한 앨런 튜링이다.

과학 철학에서 "반증 가능한가", 천문학에서 "관측 가능한가"처럼.. 전산학에서는 "계산 가능한가, 튜링 기계를 돌려서 답을 구할 수 있는 문제인가"가 중요한 고민거리가 된다. 계산 자체가 이론적으로 가능해야 그 다음 관심사는 "실용적으로 유의미한 시간 만에 빨리 해결할 수 있는가?", 더 구체적으로는 "입력 크기 N에 관한 다항식 급의 시간 안에 해결 가능한가 (팩토리얼이나 지수 함수 급이 아니라)"라는 시간 복잡도가 될 것이다.

TSP(순회하는 세일즈맨) 문제 같은 NP-완전 문제는 이론적으로 알려진 시간 복잡도가 너무 높기 때문에 실생활에서는 적당히 성능이 좋은 다항 시간 근사 알고리즘이 쓰인다.
그래도 정지 문제는 3-SAT 문제라든가 NP-완전처럼 시간 복잡도를 따지는 증명보다는 덜 난해하고 직관적인 설명도 가능하기 때문에 수식 없이 블로그에다 증명 방식을 소개도 할 수 있다. 현실에서는 논리적으로 100% 완벽하고 헛점이 없고 100% 정확하게 동작하지는 못하지만 그래도 현실적으로 충분히 정확하고 속도도 적절한 각종 소스 코드 정적 분석 기능이 개발되어 쓰이고 있다.

Posted by 사무엘

2021/05/24 19:36 2021/05/24 19:36
, , , ,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/1891

컴퓨터그래픽에서 벡터 그래픽의 반의어로 픽셀과 비트맵을 다루는 체계를 래스터 그래픽이라고 흔히 부른다. 종이가 아니라 해상도가 상대적으로 낮은 모니터 화면이 주 무대이고, 면을 채우는 기본 단위가 scan line(주사선)이라는 관점에서 정립된 용어이다.

그리고 2D 비트맵(더 정확한 명칭은 래스터..?) 그래픽 API를 보면 어떤 플랫폼용 어떤 언어의 라이브러리이든지 점과 직선, 곡선을 그리는 함수가 있고, 사각형과 원을 그리는 함수가 있다. 이게 기본이다.
점이나 사각형이야 그리는 방식이 너무 trivial하니 제끼고, 원이나 곡선을 빠르게 그리는 원리는 기하 알고리즘의 일종으로 다뤄지기도 한다. 그 단순한 직선조차도 굵기가 2픽셀 이상이 되면 중심점을 생각해야 할 것이고, 무거운 부동소수점 연산 없이 anti-aliasing까지 하면서 그린다는 조건이 추가되면 결코 쉽지 않은 일이 된다.

그리기 기능 중에서 특정 픽셀부터 시작하는 flood fill은 무척 독특한 동작이다. 기하 알고리즘이라기보다는 스택 메모리를 동원해서 컴에게 길 찾기 재귀호출 노가다를 시키는 코딩의 영역이다. 빼곡한 미로의 내부에 있는 한 점에서 flood fill을 시켜 보면 이건 본질적으로 길 찾기와 다를 바 없다는 걸 알 수 있을 것이다.

글쎄, flood fill은 그래픽 에디터에서 사용자가 내리는 채우기 명령을 구현하는 형태로나 쓰이지, 직선과 곡선, 사각형과 원처럼 그림을 그리는 구성요소로서 프로그램이 내부적으로 사용할 일은.. 정말 아주 특수한 상황이 아니라면 없을 것이다. 도형 자체를 처음부터 내부가 채워진 형태로 그려야지, 도형의 윤곽만 그린 뒤에 도형 내부의 임의의 점을 따로 주고 채우는 건 몹시 비효율적이기 때문이다.

그래서 그래픽 라이브러리에는 다각형을 그리는 함수가 있다. 다각형의 경계선만 찍찍 그리는 것이야 LineTo만으로 얼마든지 할 수 있으므로, 이런 함수는 내부가 채워진 다각형을 그리는 것이 핵심이다. 그러니 이 함수는 다른 함수와 달리, 반드시 다각형의 꼭지점들이 담긴 배열을 전달받아야 한다.
옛날 도스 시절의 베이식은 타 언어들에 비해 그래픽 모드의 접근성이 좋았지만, 정작 다각형을 그리는 API는 없었다.

그럼 다각형을 채우는 기능은 어떤 방식으로 동작하는 걸까?
이걸 구현하기 위해서는 어떤 점이 다각형의 내부에 속하는지를 판단해야 한다. 더 나아가서 이 점에서 한쪽으로 scan line을 그어 나갈 때 어디까지가 동일하게 다각형의 내부 또는 외부인지를 판단해야 한다.

이걸 판단하는 방법은 의외로 간단하다. 그 점으로부터 아무 방향으로(예: x축 양의 방향) 한없이 직선을 그을 때, 그 선이 다각형을 구성하는 선분과 얼마나 몇 번이나 마주치는지를 판단하면 되며, 이걸 판단하는 방법도 크게 두 갈래로 나뉜다. 바로 (1) 홀짝 아니면 (2) 0여부이다.

홀짝법은 마주친 선분이 짝수 개이면 다각형의 외부이고, 홀수 개이면 내부라고 판단한다. 다시 말하지만 이 가상의 선은 정말 아무 방향으로나 그리면 된다. 다각형이 모든 방향으로 닫혀서 내부에 공간이 존재한다는 사실 자체가 이 판별법의 correctness를 보장해 준다.

0여부는.. 홀짝보다 더 절묘하다. 초기값이 0인 가중치라는 걸 두는데, 마주친 선분이 우리가 그은 가상의 선을 위에서 아래로 교차한다면 가중치에 1을 더한다. 그렇지 않고 아래에서 위로 교차한다면 1을 뺀다.
이렇게 해서 최종적으로 가중치가 양수든 음수든 0이 아닌 값이 나온 점은 다각형의 내부라고 간주하고, 0인 점은 외부라고 간주한다.

0이나 홀짝이나 그 말이 그 말 같은데.. 실제로 자기네 선분끼리 배배 꼬아서 교차하지 않는 일반적인, 평범한 오목/볼록다각형이라면 어느 판별법을 사용하든 결과에는 아무 차이가 없다.
하지만 당장 오각형 별표를 한붓그리기로 그린 궤적을 줘 보면 둘은 서로 차이를 보인다.

사용자 삽입 이미지
Windows API에서는 SetPolyFillMode라는 함수가 있어서 두 방식을 모두 사용해 볼 수 있다. 더 단순한 홀짝법이 ALTERNATE이고 기본값이다. 0여부는 WINDING... Windows 1.x 시절부터 존재해 온 오래된 고전 API여서 그런지, 매크로 상수의 앞에 접두사가 붙어 있지도 않다(PFM_* 같은?? ㅎㅎ).

오각형 별표에서 별의 중앙에 생긴 공간을 보면.. 그 옆으로 다각형 경계를 나타내는 선이 어느 방향이든 두 개가 존재한다(짝수). 그런데 이들은 방향이 둘 다 오르막 아니면 둘 다 내리막이며, 이 때문에 winding value는 nonzero가 된다. 그러니 ALTERNATE일 때는 이 공간이 비워지지만 WINDING일 때는 공간이 채워지는 것이다.

그 위의 더 복잡한 꼬인 사각형도 상황이 비슷하다. 잘 살펴보면 이 궤적도 홀수점이란 게 전혀 존재하지 않으며 한붓그리기가 가능하다.
그런데 WINDING일 때는 궤적이 꼬여서 생긴 내부의 사각형 공간 둘 중에서 좌측 하단 한 곳만 채워져 있다. 그 이유는 역시 저기서만 winding value가 nonzero이기 때문이다.

일반적으로 WINDING(0여부)이 판정하는 다각형 영역은 ALTERNATE(홀짝)의 상위 호환이다. ALTERNATE가 판정하는 영역을 100% 포함하면서 일부 영역을 추가적으로 더 판정한다는 뜻이다. 그렇다고 해서 모든 닫힌 영역을 한 치의 예외 없이 몽땅 내부라고 판정하는 건 아니다.

뭐.. 현실의 벡터 그래픽에서 이 따위 선끼리 교차하는 배배 꼬인 폴리곤을 생성하는 것은 애초부터 권장되지 않는 금지 사항이다. 가령, 속이 빈 오각별을 그리고 싶으면 저렇게 보이는 대로 삼각형 다섯 개로 풀어서 표현하라는 것이다. 윤곽선 폰트 등 벡터 그래픽 편집기들은 그렇게 폴리곤의 모양을 자동으로 수정해 주는 기능도 제공한다.
그러니 이렇게 fill mode의 차이점을 미주알고주알 관찰할 일이 현업에서는 거의 없을 것이고, 이런 건 그냥 학교에서 컴퓨터그래픽스 기초를 공부할 때 이런 방식도 있다는 걸 알기만 하고 넘어가면 될 것 같다.

하지만 그게 전부가 아니다. 다각형 채우기의 기능이 더 확장되면 다음 영역에도 도달하는데, 이때 fill mode의 차이점이 다시 드러나게 된다.

1. 여러 다각형을 한꺼번에 그리기
이건 내부에 구멍이 뚫린 다각형을 그릴 수 있다는 것에 의의가 있다. 구멍은 Polygon 함수를 연달아 호출하는 것으로는 표현할 수 없기 때문이다.

Windows에는 여러 다각형을 한꺼번에 그리는 PolyPolygon이라는 함수가 있다. 그런데 아까처럼 한 다각형에서 변들이 서로 교차하고 꼬였을 때뿐만 아니라, 변은 꼬이지 않았고 여러 다각형들의 영역이 서로 겹칠 때에도 fill mode의 차이는 유의미한 동작의 차이를 만들어 낸다.

사용자 삽입 이미지

위의 그림은.. 뭐 이론적으로는 한붓그리기가 가능하기 때문에 역시 꼬인 단일 다각형으로 궤적을 나타낼 수 있다. 하지만 앞서 예를 들었던 오각별이나 그 사각형 그림과 달리, 일부 점과 점이 겹치는 건 피할 수 없을 것이다. 무슨 말인가 하면, 저 궤적을 꼭지점 좌표의 배열로 기술했을 때, 4개의 선분과 만나는 점은 두 번 등장하는 부분이 생긴다는 것이다.

꼬인 단일 다각형이 아니라 영역이 일부 겹치는 사각형과 삼각형을 서로 떼어서 PolyPolygon으로 그린 경우.. ALTERNATE(홀짝)에서는 짝수 개의 다각형에 속하는 영역은 비우고, 홀수 개에 속하는 영역만 칠한다. 그러고 보니 동작이 뭔가 XOR스러워 보인다. 각 다각형들의 꼭지점이 기술된 방향은 어느 쪽이건 무관하다 (시계 or 반시계 방향)

그러나 WINDING(0여부)일 때는 그 특성상 방향이 같은 다각형들은 겹치더라도 영역을 모두 칠한다. 겉의 껍데기가 시계 방향이라면.. 그 안의 구멍은 반시계 방향으로.. 다른 방향으로 칠해져야 구멍이 비게 된다! 다시 말하자면, WINDING에서도 위의 그림의 왼쪽처럼 중앙이 비어진 그림을 그리고 싶다면 사각형과 삼각형의 좌표 방향이 서로 반대여야 한다.
꼬인 단일 다각형에서 fill mode의 차이점을 설명하는 프로그래밍 서적들이.. 다중 다각형까지 연계해서 동일 개념을 설명하는 경우는 내가 딱히 못 본 것 같다.

2. 직선뿐만 아니라 베지어 곡선까지 포함된 궤적의 내부를 채우기
위와 같은 구멍 감지에다가 곡선 지원까지 포함되면.. 이건 뭐 윤곽선 글꼴 래스터라이저가 번듯하게 완성된다. 물론 본격적인 폰트 엔진은 거기에다 작은 크기에 대비한 정교한 안티앨리어싱과 힌팅, 글꼴 글립 캐시, 더 나아가 복잡한 유니코드 문자 형태 분석까지 추가되는데 이것들 하나하나가 별개의 전문 영역일 정도이다.

FreeType 라이브러리는 그 중에서 제일 저수준인 그리기, 안티앨리어싱, 힌팅까지만 담당한다. 요즘 소프트웨어들은 글자 하나를 찍는 것도 겨우 8*16, 16*16 비트맵 글꼴 찍던 시절과는 차원이 다르게 더 복잡해져 있는 셈이다.
그건 그렇고.. Windows API에는 직선과 곡선이 포함된 도형을 한꺼번에 그리는 것은 윤곽선만으로 한정이다. PolyDraw라는 함수가 있다.

내부를 채우는 것은 한 함수로 지원되지 않으며, path라는 걸 써야 한다. 얘는 Windows GDI가 제공하는 강력한 벡터 그래픽 라이브러리로, 직선, 베지어 곡선, 원과 원호, 심지어 다른 트루타입 글꼴의 글립까지 몽땅 궤적으로 표현해서 한꺼번에 내부를 채울 수 있다. 구멍 처리도 물론 된다.
BeginPath (그리기) CloseFigure (그리기) EndPath 이런 식으로 말이다. 위의 1과 2를 모두 할 수 있다.

내 경험상 트루타입 폰트는 WINDING 방식으로 래스터라이징을 한다. 글꼴 글립을 그릴 때부터 제일 밖의 path는 시계 방향이고, 그 안의 구멍 윤곽을 기술하는 path는 반시계 방향이고, 구멍 안의 칠하는 영역은 또 시계 방향.. 이런 식으로 디자인을 해야 한다.

허나, 예전에 MS Office 2003 이하 버전에서 제공되던 클래식 WordArt는 이 원칙을 지키지 않고 트루타입 글꼴도 홀짝 ALTERNATE 방식으로.. 짝수 회 overlap 영역은 무조건 비웠던 것 같다.
그래서 composite glyph 형태로 표현되는 비완성형 한글 글꼴에서 글립이 겹칠 수 있는 복잡한 글자를 찍어 보면 저렇게 흰 부위 glitch가 발생하곤 했다. (아래 그림에서 ㅆ, ㅠ, ㅔ 부분 참고)

사용자 삽입 이미지

Office 2007 이상부터 제공되는 WordArt는 이 문제가 해결됐다. 그리고 아래아한글의 글맵시도 0여부 WINDING 방식으로 맞게 색칠을 하기 때문에 glitch가 발생하지 않는다.

그러고 보니.. MS Office는 지난 2007때부터 그래픽 엔진이 크게 바뀌었다. 워드아트의 글자 장식 기능도 리뉴얼 됐고 PowerPoint 같은 데서도 직통으로 사용 가능해졌는데, 정작 본가인 Word에서는 2003 이하의 클래식 워드아트가 제공됐다. 다음 버전인 Office 2010부터 Word에서도 동일하게 리뉴얼된 워드아트가 제공되기 시작했다.

Posted by 사무엘

2021/05/12 08:35 2021/05/12 08:35
, , ,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/1885

« Previous : 1 : 2 : 3 : 4 : 5 : Next »

블로그 이미지

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

- 사무엘

Archives

Authors

  1. 사무엘

Calendar

«   2024/03   »
          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:
2620011
Today:
3010
Yesterday:
1544