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

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

0. 들어가는 말

세상에는 누구나 드나들 수 있는 공공장소와 누구나 신호를 주고받을 수 있는 통신망이 있지만, 사람마다 사생활도 있고 비밀도 있다. 이런 게 보장되지 않으면 인간이 정상적으로 살아갈 수 없으며, 사실은 생존에 필요한 기본 욕구를 충족시킬 수도 없어진다.
그렇기 때문에 어떤 장소나 어떤 정보는 내부의 믿을 수 있는 사람, 우리 조직 소속인 사람만 접근할 수 있게 해야 한다.

이를 구현하기 위해 전자에 대해서는 열쇠와 자물쇠라는 게 만들어져 왔고, 후자를 위해서는 암호 기술이라는 게 개발되었다. 열쇠가 없는 사람, 암호를 모르는 사람은 문을 열고 들어갈 수 없고 그 자료를 열람할 수 없다. 심지어 정보가 담긴 매체라든가 물건이 담긴 금고 자체가 유출되더라도 그 안의 물건에 손댈 수는 없다.

열쇠와 암호는 서로 담당하는 영역이 다르지만 심상이 아주 비슷한 구석도 있다. 요즘은 자물쇠도 열쇠 대신 일종의 숫자 암호인 디지털 도어락으로 바뀌고 있고, 암호학에서도 key라는 용어가 즐겨 쓰이니 말이다.

다만, password라는 개념의 '암호'와, 원본 정보를 password 없이는 알아볼 수 없게 변조하는 '암호화'(cryptography, encryption), 그리고 암호화가 적용된 텍스트를 작성하는 것 내지 그 결과물인 암호문(cipher).. 이게 우리말에서는 딱 부러지게 잘 구분되지는 않는다는 점을 감안할 필요가 있다. 마치 '뛰다'(jump/run), '다른'(other/different), '푸르다'(green/blue) 이런 게 잘 구분되지 않는 것처럼 말이다.

보이니치 괴문서처럼 암호 사용 여부와는 무관하게 단순히 체계와 의미가 파악되지 못한 물건도 decipher되지 못했다고 말한다.
그에 비해 한국어 ‘해독’은 동음이의어 한자의 특성 때문에 ‘독’에 read라는 뜻뿐만 아니라 poison이라는 뜻까지 있어서.. 미묘하게 중의적인 심상을 자아낸다. 마치 ‘충전’의 중의적인 심상처럼 말이다. (전기도 충전, 금액도 충전..)

1. 패스워드의 관리, 해시 함수

먼저, 암호화와 무관하게 로그인 패스워드 자체에 대한 보안을 논하는 기본 원칙이 있다. 이 주제에 대해서는 본인이 마지막으로 글을 썼던 때가 무려 7년 전이었구나.;; (☞ 이전 글)
사용자의 입장에서는 “다양한 종류의 문자를 섞어서 최소한 10자 이상의 긴 문자열로 정할 것, 주기적으로 바꿔 줄 것” 이런 게 있다.

물론 누군가의 원한을 사고 있어서 작정하고 당신의 계정을 뚫으려 노력하는 공격자라도 있는 게 아니라면.. 이런 얘기에 지나치게 민감해할 필요는 없다. 암호 좀 허술하게 만든다고 해서 현실에서 당장 위험에 빠지는 건 아니다. 하지만 그렇다고 해서 1234, asdf, iloveyou, 생일, 전화번호 정도로 암호를 너무 성의없게 만드는 건 정말 피해야 한다.

그리고 사용자의 접속 정보를 저장하는 운영자의 입장에서는 암호를 절~대로 평문 그대로 저장하지 말아야 한다. 게다가 암호 문자열이 무슨 도스 시절 파일 이름마냥 10~15자 같은 제약이 걸려 있거나 특정 특수문자 기호를 지정하지 못한다면.. 그건 정말 기본적인 보안 관념도 없던 쌍팔년도 시절 사고방식의 미개한 사이트라고 욕 먹어야 할 것이다.

사용자가 암호를 잊어버렸다면 사이트 운영자라도 그 암호를 알 수 없는 게 정상이다. 본인 인증을 시행한 뒤에 임의로 지정한 새 암호를 알려줘야지, 기존 암호를 그대로 알려주는 사이트는 그 자체가 보안이 매우 허술하다고 실토하는 것과 같다.

그러니 이런 패스워드는 딱히 key 없는 단방향 암호화라는 변조를 거쳐서 저장해야 하는데, 이럴 때 해시 함수라는 게 쓰인다. hash란 어떤 임의의 길이의 원본 문자열이 주어졌을 때 원본과는 완전히 다르고 무질서하게 변조된 다른 고정된 길이의 문자열 내지 바이트 시퀀스를 되돌리는 수학 함수이다. 원본 문자열이 조금만 바뀌어도 완전히 확 달라진 결과값이 나와야 한다.

F(X) → Y인데, 역으로 Y로부터 X를 복원하는 것은 수학적으로 불가능하다. 그리고 F(A) ≠ F(B) 라면 절대적으로 A≠B이지만, F(A)=F(B)이면서 여전히 A≠B일 확률은 매우 매우 낮은 확률로 존재한다. 비유하자면, 퀵 정렬의 시간 복잡도를 n^2로 만드는 input을 우연히 만들 수 있을 정도의 확률로 존재한다.

패스워드의 비교는 사용자가 입력한 문자열을 hash한 결과와, 저장된 패스워드 hash값을 비교함으로써 행해진다. 평문을 비교하는 게 아니라는 것이다.
사실, 이런 해시 함수는 패스워드의 보관뿐만 아니라 방대한 파일이 정확하게 잘 전송되었는지 동등성을 검증하는 용도로도 즐겨 쓰인다. 수 GB짜리 파일의 해시값이 얼마가 나와야 정상인데 엉뚱한 값이 나왔다면 중간에 오류가 있었다는 뜻이 되기 때문이다.

해시 함수가 튼튼하고 안전하려면 (1) F(X)로부터 X를 역으로 추적하는 것이 불가능해야 하고, (2) 서로 다른 두 입력 A, B에 대해서 동일한 해시값이 산출되는.. 다시 말해 ‘충돌’ 사례가 없어야 한다. 전자는 암호화된 값으로부터 패스워드를 복원하는 것이고, 후자는 의도하지 않았던 엉뚱한 암호로 원래 패스워드의 사칭을 가능하게 하기 때문이다.

성능 좋은 해시 알고리즘으로는 MD5니, SHA-256 이런 부류가 공개되어 쓰이고 있다. 이들도 한번 만들고 끝이 아니라 버전과 출력 해시의 길이가 올라가는 편인데, 기를 쓰고 공격하려 애쓰는 연구자에 의해 충돌하는 입력값 쌍이 발견되기도 한다. 그러면 그게 해당 알고리즘을 사용하는 소프트웨어의 잠재적 보안 결함으로 이어진다.

그리고 해시값으로부터 원래 입력을 역추적하기 위해 요즘은 상상을 초월하는 물량 데이터빨이 동원된다. “MD5 해시값을 자동으로 계산해서 구해 드립니다”라는 웹페이지를 개설한 뒤, 전세계 사용자가 입력했던 문자열과 그 해시값 수십억 개를 몽땅 보관해 놓는 것이다. 그래서 산술 연산을 하는 게 아니라 DB를 조회함으로써 해시값 복원을 한다. 우리가 남들도 떠올릴 만한 평범한 문자열로 패스워드를 만들면 위험한 이유가 이 때문이다.

2. 대칭 키 암호화

이게 우리가 흔히 생각하는 데이터 암호화이다. 발신자가 A라는 텍스트를 K라는 패스워드(혹은 key)를 이용해서 E라는 암호화 함수로 암호화해서 B라는 암호문을 얻는다. 수식으로 표현하면 B=E(A, K) 정도? 그러면 수신자는 D라는 복호화 함수를 이용해서 D(B, K)를 돌림으로써 A를 얻는다.
이걸로 끝.. ‘대칭’이라는 말은 발신자와 수신자가 K라는 동일한, ‘대칭인’ key를 공유하는 암호 체계라는 뜻이다.

암호화 함수는 해시 함수와는 달리 복호화 함수도 존재하며, key만 안다면 원문 복원이 가능하다는 차이가 있다. 해시 함수는 애초에 어떤 입력에도 128비트 같은 동일한 길이, 즉 동일한 정보량을 가진 해시값이 돌아오지만, 암호화 함수는 출력의 정보량이 입력의 정보량과 대등하다. 그러니 용도가 서로 근본적으로 완전히 다르다.

컴퓨터가 없던 시절에도 마치 VMS로부터 WNT (Windows NT)라는 명칭을 만드는 것처럼 글자들을 일정 간격 앞뒤의 것으로 변조하거나, 심지어 key 문자열의 형태를 토대로 각 글자들을 가변적인(하지만 규칙과 패턴은 물론 있는) 오프셋만치 변조하는 기법 정도는 응당 쓰였다. 모든 글자를 고정적인 오프셋만치 변조하는 암호는 각 글자들의 빈도수 분석을 통해 비교적 금방 깰 수 있을 것이다.

2차 세계 대전까지만 하더라도 전자식 컴퓨터라는 게 사실상 없던 시절이었고, 지금에 비하면 매우 단순하고 원시적인 암호가 쓰였다. 연합군이 승리한 것에는 적국(일본, 독일) 군대의 암호를 풀어낸 것이 아주 큰 기여를 했음이 주지의 사실이다.
컴퓨터가 등장한 뒤부터는 매우 컴퓨터 친화적인 비트 회전과 XOR 연산이 암호화에 즐겨 쓰이고 있으며 그 수준이 과거엔 상상도 할 수 없을 정도로 복잡해졌다. 문자열을 암호화하기 위해서는 문자열을 구상하는 각 문자들을 숫자처럼 취급하는 게 필수이다.

정보 보호라는 업계에서 이런 암호화와 관련하여 통용되는 철칙이 있다. 암호화 알고리즘은 자신의 동작 방식과 로직이 소스 코드 차원에서 몽땅 공개되어 있더라도 절대적으로 안전해야 한다는 것이다. 데이터의 안전은 key가 보장해야지, 알고리즘을 공격자가 알고 있는지의 여부와는 무관해야 한다.
그렇기 때문에 이 바닥은 소스를 공개할 수 없는 우리만의 초특급 비밀 노하우 원천기술 같은 게 없다. 모든 게 투명하게 공개돼 있고 심지어 취약점이 발견된 것, 수정 내역도 공개된다. 이런 열린 관행 덕분에 컴퓨터 세계는 역설적으로 더 안전해질 수 있었다.

여담이지만, 지난 2009년엔 ‘코드소프트’라는 정체를 알 수 없는 어느 스타트업 기업에서 상금까지 걸면서 자기네 암호화 알고리즘에 대한 크랙 공모전을 주최했으나 비슷한 시기의 T-max 운영체제 같은 흑역사만 남겼던 적이 있다. 자기네 핵심 기술이라던 암호화 알고리즘은 허술하기 짝이 없어서 겨우 몇 시간 만에 뚫려서 큰 망신을 당했으며, 그 회사도 얼마 못 가 통째로 폐업했기 때문이다(소스는 비공개이고 임의의 데이터에 대한 암호화 결과 확인만 가능). 걔들은 암호화 알고리즘의 전문가는 고사하고 보안에 대한 기본 관념이 있긴 한 기업이었는지가 의문이 든다.

대칭 키 암호화 알고리즘으로는 AES, DES 같은 기성 표준 알고리즘이 있고 이것도 버전 내지 사용하는 정보량(비트수)이 올라가고 있다. AES는 오늘날의 컴퓨터 성능으로는 뚫리는 데 걸리는 시간이 위험할 정도로 짧아졌기 때문에 이제 사용이 권장되지 않는 지경이 되었다.
우리나라에서도 SEED, ARIA, LEA라는 알고리즘을 자체 개발해서 국가 표준으로 지정한 바 있다. 국정원 내지 한국 인터넷 진흥원 이런 데서 날고 기는 수학 박사를 채용해서 머리 굴려서 개발한 듯하다.

문서나 압축 파일에 암호를 거는 기능에도 응당 이런 암호화 알고리즘이 쓰인다.파일 내부에다가 패스워드를 평문으로 저장하는 미친 짓을 하지는 말아야 할 것이다. 혹은 파일 내용 자체를 암호화하지 않아서 헤더의 패스워드 부분만 건너뛰고 나면 나머지 내용을 고스란히 읽을 수 있게 하는 것도 치명적으로 잘못된 설계이다.
틀린 패스워드를 주면 해독이 잘못되어 완전히 엉뚱한 파일이 생성될 텐데, 패스워드가 맞는지 틀린지를 확인하는 건 정상적으로 해독됐을 때의 파일 checksum hash 같은 걸 별도로 둬서 확인해야 한다. 암호화 알고리즘 다음에 붙는 CBC, GCM 같은 모드 명칭은 바로 이런 검증 방식을 가리킨다.

안전한 암호화 알고리즘이라면 평문이나 key가 조금만 달라져도 이들의 원래 형태와 통계적 특성을 전혀 알 수 없는 엉뚱한 암호화 결과가 출력으로 나와야(혼돈과 확산) 안전할 것이다. 이 점에서는 해시와 비슷한 구석이 존재하며 심지어 난수 생성 알고리즘과도 비슷하다고 볼 수 있다. 입력을 0, 1, 2 .. 순차적으로 주고 이를 hash시킨 결과가 난수나 마찬가지이고 암호화도 이와 크게 다르지 않을 테니까.. 하지만 암호화, 해시, 난수는 전문적으로 들어가면 지향하는 목표가 다른 분야라고 한다.

말이 나왔으니 말인데.. 임의로 생성 가능한 문자열과 이를 hash한 문자열을 혼합하면.. 올바른 번호와 잘못된 번호의 구분이 존재하는 일련번호(serial key) 체계도 생성할 수 있다.
간단하게는 우리나라 주민등록번호가 대표적인 예이다. 검증용으로 쓰이는 마지막 자리 숫자가 hash 함수의 결과값이니까 말이다.

소프트웨어에서 불법 복제를 감지하고 예방하기 위해 발급되는 제품 key도 다 이런 원리로 발급된다. 상업용 소프트웨어야 처음부터 고정된 시리얼 키가 제품 패키지에 들어있으니 사용자 이름과 무관하겠지만, 셰어웨어 등록판을 생성하는 시리얼 키는 사용자의 이름도 공식에 응당 반영된다.

규칙에 어긋난 잘못된 문자열을 입력하면 해당 제품의 설치 프로그램은 에러 메시지를 내뱉으면서 다음 단계로 진행을 하지 않을 것이다. key의 생성 규칙은 그 제품 개발사의 중대한 영업 기밀이다.

하지만 이렇게 수학적인 방법, 소프트웨어적인 방법은 역공학을 통해서 뚫리기도 너무 쉽다. 암호학에서 알고리즘이 아니라 key만 믿어야 한다고 괜히 강조하는 게 아니다.
옛날에 불법 복제 어둠의 경로를 가 보면 도대체 어떻게 알아냈는지 특정 소프트웨어의 제품 key를 생성해 주는 툴이 버젓이 굴러다니곤 했다. 그렇기 때문에 요즘은 이 제품 key가 실제 구매자가 사용하는지의 여부를 제품 개발사 서버로부터 일일이 추가로 확인받곤 한다.

설계 차원에서 결함이 있지 않은 안전한 암호화 알고리즘이라면 key 없이 복호화를 하는 방법이 존재하지 않는다. 그렇기 때문에 이런 암호문은 그냥 a부터 z까지 모든 글자 조합을 무식하게 일일이 대입하는 brute force 방식으로만 풀 수 있다.
패스워드의 길이가 한 글자 늘어날 때마다 공격에 소요되는 시간이 수십 배씩 기하급수적으로 늘어나니.. 이 시간 덕분에 오늘도 인간의 컴퓨팅 세계는 딱히 금융 사고나 개인정보 유출 사고가 별로 없이 안전하게 돌아가고 있다.

하지만 컴퓨터의 계산 성능은 하루가 다르게 향상되고 있고 암호 공격은 병렬화에도 아주 유리한 분야이다.
이런 brute force 공격을 저지하기 위해 요즘 암호를 입력받는 프로그램, 웹사이트 등에서는 암호가 틀릴 때마다 수 초씩 딜레이를 일부러 주고, n번 이상 암호를 틀리면 계정을 정지시키는 조치까지 취한다. 그 어떤 암호 시스템도 하나하나 다 대입해 보는 제일 무식하고 원천적인 전수조사에는 언젠가 뚫릴 수밖에 없는데.. key가 너무 허술하게 만들어져 있으면 거기에 더욱 취약해질 것이다.

3. 공개 키 암호화

지금까지 key를 따로 받지 않는 대표값 변조(해싱), 그리고 key를 받는 대칭 키 암호화까지 얘기가 나왔다. 대칭 키 암호화는 입력 데이터를 받아들이는 방식에 따라 블록 암호화 내지 스트림 암호화로도 나뉘는데, AES/DES 같은 것들은 블록 암호화로 분류된다.
그런데 1970년대에는 이런 것과는 성격이 근본적으로 다른 완전히 새로운 암호화 분야가 개척되었다. 바로 대칭이 아닌 비대칭, 또는 공개 키 알고리즘이라는 개념이 제안되고 개발된 것이다.

왜냐하면 제아무리 날고 기는 복잡 정교한 암호화 알고리즘이 있다 하더라도 그것들은 발신자와 수신자가 모두 동일한 key를 알아야 하고 보안을 위해서는 수시로 교체해야 하고, 그 바뀐 key를 모든 구성원에게 전해 줘야 한다는 원천적인 한계와 위험성이 있기 때문이다. 군대에서 새 암구호를 어떤 절차를 통해 전파하는지를 생각해 보자.

key를 주고 받는 건 암호라는 걸 운용하는 모든 조직이 감내해야 하는 어쩔 수 없는 숙명인 것 같다. 하지만 암호화 때 사용되는 key와 복호화 때 사용되는 key가 다르고(비대칭), 전자는 마음대로 주변에 공개해도 되는(공개 키) 알고리즘은 이런 한계를 극복해 준다. 이런 마법 같은 일이 어떻게 가능할까..?

이 암호화는 수학적 비가역성 내지 난해함에 근거를 두고 있다. 자릿수가 많은 두 수를 곱하는 건 사람의 입장에서 몹시 고된 노가다이겠지만.. 역으로 이미 곱해진 듣보잡 수를 아예 소인수분해 하는 것은.. 뭐 차원이 다를 정도로 난감하고 시간이 오래 걸리는 일일 것이다. 페르마 수 같은 게 n이 조금만 커져도 합성수인 것만 알려졌을 뿐 완전한 소인수분해가 안 된 놈들이 부지기수인 게 이 때문이다.

공개 키 암호화 중 하나로 유명한 RSA는 수십 자리 이상의 엄청나게 큰 소수 둘을 골라서 이 원천으로부터 공개 key와 개인 key pair를 만들어 낸다. 즉, 처음부터 동일한 원천으로부터 두 key 쌍이 계산에 의해 만들어진다는 것이다. 비록 계산이긴 해도 한 key로부터 나머지 key를 역으로 유도하는 것은 무진장 어렵고 시간이 많이 걸린다.

이런 공개 키 암호화는 제약이 크다. 앞서 살펴봤던 재래식(?) 암호화처럼 임의의 메모리 블록이나 문자열을 취급하지는 못하며, 평문과 key, 암호화 결과 모두 그냥 숫자 달랑 하나일 뿐이다. 숫자에다가 문자열에 맞먹는 정보를 담으려면 그 수가 엄청나게 커져야 한다.
그리고 얘는 그런 주제에 계산량이 차원이 다르게 많다. 컴퓨터 친화적인 XOR이나 비트 회전 같은 게 아니라 거대 정수에 대한 산술 연산을 무진장 해야 하기 때문이다.

그렇기 때문에 이런 암호화 알고리즘은 재래식 블록 암호화처럼 몇 MB짜리 데이터 자체를 암호화하는 단순한 용도로 쓸 수 없다.
그 대신 재래식 암호화 알고리즘에다가 돌릴 짤막한 key만을 암호화하는 용도로 병행해서 쓰인다. 멀티스레드 프로그램에서 TLS 슬롯은 공간이 한정되어 있으니 거기에다가 생 데이터를 몽땅 저장하는 게 아니라 그냥 포인터만 저장해 놓는 것과 비슷한 이치랄까..? 마치 손실 압축과 비손실 압축만큼이나 고유한 용도가 있는 셈이다.

https 보안 사이트 내지 인터넷 뱅킹에서 로그인을 할 때 시간이 0.n초나마 랙이 있는 이유는 네트워크 트래픽 때문이 아니라 순수하게 계산 때문에 그렇다. 그때마다 암호 해독을 위해 OpenSSL에 구현된 BigInt 같은 라이브러리의 코드가 실행되면서 큰 수 연산과 값 비교가 행해진다고 생각하면 되겠다.

공개 키 암호화로서 RSA가 아주 유명하지만 이런 소수와 소인수분해 말고 타원곡선이나 이산로그 같은 다른 어려운 연산에 기반을 둔 알고리즘도 있다.
이 암호화 기술은 인터넷의 발달과 더불어 우리의 생활을 크게 바꿔 놓았다. key를 위험하게 통째로 주고받지 않아도 되는 암호화 덕분에 인터넷 상으로 금융 거래도 할 수 있게 되고 디지털 서명, 인증서라는 것도 존재할 수 있게 됐기 때문이다!

보통은 공개 key로 암호화를 해서 개인 key로 복호화를 하는데, 반대로 어떤 문서를 개인 key로 암호화하고 공개 key로 복호화하게 하면 된다. 그러면 이 문서는 누구나 열람은 가능하지만, 만든 사람은 그 공개 key에 대응하는 개인 key의 소유자밖에 없다는 것이 입증된다. 놀랍지 않은가?

hash가 어떤 데이터가 원본과 동일한지 무결성을 보장한다면, 공개 key 암호화는 어떤 데이터가 반드시 특정인으로부터 만들어졌고 변조되지 않았다는 것을 보장할 수 있다.
도장이고 자필 서명이고 자물쇠와 열쇠 같은 모든 실물은 조작이 가능하며 컴퓨터야 뭐 0과 1 무엇이건 해킹이 가능한 디지털 세상이다. 이런 바닥에서 믿을 것은 수학적인 비가역성밖에 없어진다는 것이다.

이 세상에서 생명을 다루는 의료 다음으로 중요하고 착오가 절대로 없어야 하는 크리티컬한 임무는 아무래도 돈 거래, 기밀 거래일 텐데, 이 정도 기반은 갖춰진 뒤에야 인터넷이 안전하게 돌아가고 있다. 그러나 초창기에 인터넷은 기반 프로토콜 차원에서 이런 암호화 알고리즘이 제공되지 않았다.

그렇기 때문에 전자상거래나 인터넷 뱅킹을 남보다 일찍 서둘러 구현하려면 특정 운영체제에 종속적인 온갖 비표준 편법 기술이 동원돼야 했다. 오죽했으면 2000년대 초에 SEED 같은 알고리즘까지 개발한 걸 보면 공개 키뿐만 아니라 대칭 키 암호화까지 모두 허술했던가 보다.
허나 이게 바로 우리나라 특유의 IE + ActiveX 의존이라는 독이 되어서 오늘에 이르고 있다. 일본이 일찍부터 철도 왕국이 되긴 했지만 협궤 때문에 발목 잡힌 것과 비슷한 현상이랄까..?

이상이다. 인증서가 어떻고 공개 키, 개인 키, 디지털 서명 이러는 바닥은 통상적인 hash나 블록 암호화와는 영역이 상당히 다르다는 것, 그리고 이런 공개 키 암호화 덕분에 인터넷 보안 수준의 차원이 달라졌다는 것이 핵심이다. 이 바닥도 날고 기는 괴수들이 너무 많다..;;

Posted by 사무엘

2021/03/31 08:33 2021/03/31 08:33
, ,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/1871

1. 프로그래밍 용어· 명칭과 타 분야 비교

  • 2의 제곱근 vs 제곱근(루트) 2: 어순의 차이로 의미가 달라지는 new operator/operator new, 함수 템플릿 vs 템플릿 함수 같은 C++ 용어와 상황이 비슷하다. 특히 다들 전자가 후자를 포함하는 편이기도 하다.
  • 전철역에서 논현, 신길, 양평: namespace가 필요한 좋은 예이다..;;; (1) 얘들은 고유명사 지명이 지역간에 충돌하는 사례이고 (2) 월드컵경기장이나 시청은 보통명사 시설명이 충돌하는 예이다.
    (3) 수색, 광명, 신촌 같은 건 지역이 아니라 일반열차 역과 지하철역이 충돌하는 경우이다. 그리고 (4) '회송'은 역의 이름으로는 쓰이지 않는(쓰일 수 없는) reserved word 정도에 대응할 것이다.
  • 배의 명칭 A급 B함/호(포항급 초계함 천안함, 올림픽급 타이타닉 호, 베헤모스급 배틀크루저 히페리온): 프로그래밍으로 치면 A는 타입명이고 B는 변수명이다.

2. 마침표와 세미콜론

우리는 년월일 날짜를 간략하게 표기할 때 2020. 10. 5. 같은 식으로 숫자 뒤에 마침표를 찍곤 한다. 이때 일을 나타내는 마지막 마침표도 생략하지 말고 반드시 다 찍는 것이 한글 맞춤법에 규정된 원칙이다. 각각의 점이 년, 월, 일을 나타내기 때문이다.

이는 마치 파스칼 언어에서는 세미콜론이 문장의 구분자(separator)인 반면, C/C++에서는 문장의 종결자(terminator)인 것과 비슷하다.
파스칼에서는 end나 else 직전에 등장하는 구문의 끝에 ; 이 생략되지만 C/C++은 그렇지 않다. 날짜 숫자의 뒤에다 찍는 .는 파스칼이 아닌 C/C++의 세미콜론과 같은 성격이라고 생각해야 한다.

3. 병렬화

같은 용량의 데이터가 있을 때 압축을 하는 것은 압축을 푸는 것보다 계산량이 훨씬 더 많은 어려운 작업임이 주지의 사실이다.
그 대신, 압축 "하기"는 CPU 멀티코어를 활용해서 속도를 쭉쭉 끌어올릴 수도 있는 반면, "풀기"는 그런 병렬화는 안 되고 그냥 단일 코어에서 linear한 작업에 의존할 수밖에 없다. 기껏해야 풀어야 하는 압축 파일 자체가 여러 개일 때에나 여러 CPU에다가 던져줄 수 있을 것이다.

C/C++ 파일을 빌드하는 절차도 이와 비슷해 보인다. '컴파일'은 아무래도 분산 처리와 병렬화가 가능하지만, 모든 결과물이 하나로 집약되는 '링크'는 그게 불가능한 최종 병목이 될 수밖에 없다.

4. 버퍼의 크기

일상적으로 무슨 모임 같은 데서(본인의 경우는 교회에서 청년부 모임 같은..) 인원수대로 프린트물이나 간식 같은 것을 준비해야 할 때가 있다. 평소에 모임 참석자가 얼마 정도 되는지에 대한 대략의 데이터는 있지만 딱 정확하게 몇 명인지는 알 수 없을 때는 준비물을 몇 개 정도 챙겨야 너무 남거나 모자라는 일이 없이 최대한 딱 맞을 수 있을까?

이건 나름 통계적인 노하우가 필요한 일이다. 가끔 모자라는 일이 발생해도 괜찮은지, 아니면 모자라는 일은 절대 없어야 하는지에 따라서도 전략이 달라진다. 프로그래밍으로 치면 static한 배열의 크기를 잡는 것과 매우 비슷해 보인다는 생각을 본인은 오래 전부터 했다. ㅎㅎ

문자열 클래스의 경우, 사소한 문자열까지 늘 동적 메모리를 할당하는 건 번거로우니 자체적으로 자그마한 배열도 갖고 있고, 그 배열 크기를 초월하는 긴 문자열을 배당할 때만 동적 메모리를 사용하게 하는 구현체도 존재한다. C++의 표준 string 클래스도 반드시 저렇게 동작해야 한다는 조건은 없지만 대체로 이런 식으로 구현된 걸로 본인은 알고 있다.

이런 것 말고도

  • 건물을 지을 때 이 정도 건물에서는 화장실에 변개를 몇 개 설치하는 게 좋을까?
  • 엘리베이터는 어느 정도 크기로 몇 개 설치하는 게 좋을까?
  • 이 정도 도로의 교차로 내지 횡단보도에서는 신호 주기를 어느 정도로 주는 게 좋을까?

같은 문제도 치밀한 공학 및 통계 계산의 산물이지 싶다. 동시에 사용하는 사람의 수가 최대인 시간대에 대기 시간이 너무 길어지지 않게 하는 한편으로, 나머지 한산한 시간대에 시설들이 사용자 없이 놀면서 발생하는 비효율도 최소화해야 하기 때문이다.

5. 훅킹

훅(hook) 내지 훅킹이란 컴퓨터 소프트웨어가 돌아가는 과정을 몰래 들여다보고 필요하면 변조도 하는 메커니즘을 말한다. 훅킹은 대체로 시스템 프로그래밍 분야에 속하며 꽤 강력한 고급 테크닉으로 간주된다.

(1) 메시지 훅
Windows에는 SetWindowsHookEx라는 엄청난 함수가 있어서 시스템과 응용 프로그램 사이에서 오가는 메시지들을 매우 수월하게 들여다볼 수 있다. 그러니 Spy++ 같은 프로그램을 만들 수 있다.
권한 문제만 없다면 심지어 다른 프로그램의 메시지를 들여다볼 수도 있다. 이 경우, 훅 프로시저가 내 프로세스가 아니라 그 메시지를 받은 프로세스의 문맥에서 실행된다는 점을 주의할 것. 32비트와 64비트별로 DLL을 따로 만들고, 프로세스 간의 통신 같은 잡다한 수고만 좀 해 주면 된다.

(2) API 훅
다른 프로그램이 그냥 기계어 수준에서 운영체제의 특정 함수를 호출하는 것을 감지하고, 그 함수 대신 내가 심은 함수가 호출되게 할 수 있다. C 언어 형태의 클래식 API가 제일 쉽고, COM도 결국은 CoCreateInstance 같은 함수를 훅킹하면 이론적으로 가능하다. 실행되는 기계어 코드를 변조하는 게 아니라 import 섹션 주소를 변조하는 고전적인 테크닉이 있다.

16비트 시절에는 API 훅을 시스템 전체에다 걸어서 운영체제 외형을 통째로 마개조 할 수도 있었지만 32비트 이후부터는 그 정도까지는 어렵다. 다만, 시스템 전체에다가 설치한 메시지 훅과 CreateRemoteThread 등 다른 어려운 테크닉들과 연계하면 API 훅도 어느 정도 global하게 설치하는 게 가능은 하다.
과거에 한컴사전이 GDI 그래픽 API에다가 훅을 걸어서 단어 자동 인식 기능을 제공했던 적이 있다. 마우스 포인터 주변의 화면 캡처 + 필기 인식이 아니다~!

(3) 패킷 훅
심지어 시스템 전체에서 오고 가는 네트워크 패킷을 모니터링 할 수도 있다. 이게 기술적으로 가능하니까 packet sniffer이라고 불리는 유틸리티들도 존재 가능할 것이다. 이에 대해서는 본인도 더 아는 게 없다.
macOS는 Windows와 달리 메시지 훅이고 API 훅 같은 건 존재하지 않는 것으로 본인은 알고 있다. 하지만 macOS라도 패킷 모니터링은 아마 가능할 것이다.

packet sniffer이라든가 심지어 VPN 툴 같은 건 어떤 API를 써서 어떻게 만드나 모르겠다. 신기한 물건이다.

Posted by 사무엘

2021/02/01 08:34 2021/02/01 08:34
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/1849

1. 그레이스케일

이건 이미지를 흑백 형태로 바꾸는 것이 핵심이다. 색을 구성하는 정보량의 차원이 줄어들고(3차원 → 1차원으로) 결과적으로 전체 색깔수가 줄어들기는 하지만(수천~수십만 종류의 색상 → 256단계의 회색), 그래도 아예 B&W 단색으로 바꾸는 건 아니다.
각 픽셀들은 색상과 채도가 제거되고 명도만 남아서 흑부터 백 사이에 다양한 명도의 회색으로 기계적으로 바뀐다. 같은 색의 픽셀이 인접 픽셀이 무엇이냐에 따라서 다르게 바뀐다거나 하지는 않는다.

그런데 그레이스케일 공식이 딱 하나만 존재하는 게 아니다. RGB 세 성분의 산술평균을 주면 될 것 같지만, 그렇게 그레이스케일을 하면 그림이 굉장히 칙칙하고 탁하게 보이게 된다.

똑같이 최대값 255를 주더라도 빨강(255,0,0), 초록(0,255,0), 파랑(0,0,255) 각 색별로 사람이 인지하는 명도는 서로 일치하지 않는다. VGA 16색 팔레트를 다뤄 본 사람이라면, 밝은 빨강이나 밝은 파랑을 바탕으로는 흰 글자가 어울리지만, 밝은 초록은 그 자체가 너무 밝아서 흰 글자가 어울리지 않는다는 것을 알 것이다.

사용자 삽입 이미지

그러니 공평하게 33, 33, 33씩 가중치를 주는 게 아니라 거의 30, 60, 10에 가깝게.. 초록에 가중치를 제일 많이 부여하고 파랑에는 가중치를 아주 짜게 주는 것이 자연스럽다고 한다.

이런 공식은 누가 언제 고안했으며 무슨 물리 상수처럼 측정 가능한 과학적인 근거가 있는지 궁금하다. 옛날에 흑백 사진을 찍으면 색깔이 딱 저 공식에 근거한 밝기의 grayscale로 바뀌었던가?
본인은 저 그레이스케일 공식을 태어나서 처음으로 접한 곳이 아마 QBasic 내지 QuickBasic의 컬러/팔레트 관련 명령어의 도움말이었지 싶다.

2. 디더링

이건 그레이스케일과 달리, 색깔수를 확 줄이는 것이 핵심이다. 그 대신 반드시 단색 흑백이어야 할 필요가 없다. 가령, 트루컬러를 16색으로 줄이는 것이라면 RGB 원색이 살아 있는 컬러라 할지라도 디더링의 범주에 든다. 이런 것처럼 말이다.

사용자 삽입 이미지

디더링에서는 어떤 원색을 직통으로 표현할 수 없을 때 근처의 비슷한 여러 색들을 고르게 흩뿌려서 원색과 비슷한 색감을 나타낸다. 팔레트까지 임의로 지정이 가능하다면 256색 정도만 돼도 생각보다 그럴싸하게 원래 이미지를 재현할 수 있다. 그런 게 아니라 그냥 흑백 단색 디더링이라면 아까 그레이스케일처럼 어떤 공식에 근거해서 명도를 추출할지를 먼저 결정해야 할 것이다.

0부터 1까지 가중치별로 점을 골고루 균등하게 뿌리는 공식은 이미 다 만들어져 있다. 이건 Ordered dither이라고 불리며, 보통 8*8 크기의 64단계 격자가 쓰이는 편이다. 그 구체적인 방식에 대해서는 수 년 전에 이 블로그에서 이미 다룬 적이 있다.

그레이스케일은 RGB(0.4,0.2,0.6)라는 색을 0.3이라는 명도로 바꾸는 것에 해당하는 기술이고, 단색 디더링은 이 색이 0.3, 0.3, 0.3 … 이렇게 쭉 이어지는 것을 1, 0, 0, 1, 0, 0 이런 식으로 이산적으로 표현하는 것과 같다.
그런데 원색을 기계적으로 이런 격자로 치환하기만 하면 보기가 생각보다 굉장히 좋지 않다.

원래 0.3을 표현해야 하는데 지금 지점에서 부득이하게 1을 찍어 버렸다면 0.7이라는 오차의 여파를 인접 픽셀에다가 떠넘겨서 거기서 계속해서 감당하게 해야 한다. 즉, 그레이스케일은 그냥 인접 픽셀을 신경 쓰지 않고 픽셀 대 픽셀 변환만 했지만 디더링은 그렇지 않다. ordered dither 내지 더 단순무식한 nearest color 찍기 신공이 아니라면.. 이전 픽셀에서 발생한 오차를 수습하는 error diffusion을 동원해야 부드러운 결과물이 나온다.

사용자 삽입 이미지

그런 지능적인(?) 디더링 알고리즘은 196~70년대에 컴퓨터그래픽이라는 분야가 등장한 초창기부터 연구되어 왔으며, 고안자의 이름을 따서 Floyd-Steinberg, Burks, Stucki 같은 알고리즘이 있다. 이미지를 다루는 사람이라면 포토샵 같은 그래픽 편집 프로그램에서 저런 명칭들을 본 적이 있을 것이다.
이런 알고리즘들은 ordered dither와 달리, 점들이 일정 간격으로 산술· 기계적으로 단순 투박하게 찍힌 게 아니라 뭔가 한땀 한땀 손으로 입력된 것 같고 부드러운 느낌이 든다. 그리고 무엇보다 색깔이 크게 바뀌는 경계 영역이 훨씬 더 선명하다.

3. 하프톤 (망점)

그레이스케일이 색깔 표현에 제약이 없는 아날로그 영상물(특히 흑백 필름 사진) 같은 느낌이 나고, 디더링은 초기에 해상도와 색상이 부족했던 디지털 영상과 관계가 있다면.. 하프톤은 색상이 부족한 대신 해상도가 높은 '인쇄물'과 관계가 깊은 기법이다.

사용자 삽입 이미지

하프톤은.. 일정 간격으로 망점을 두두두둑.. 찍고, 그 망점의 크기/굵기만으로 명도를 조절한다. 깨알같은 점들의 양과 배치 방식을 고민하는 통상적인 디더링과는 문제 접근 방식이 약간 다르다.
출력물의 해상도가 영 시원찮은 데서 하프톤을 동원하면 망점이 너무 커서 눈에 거슬릴 수 있다. 회색을 만들려고 했는데 하양과 검정이 그대로 눈에 띄게 된다는 것이다.

그러나 아무 인쇄물에서나 흑백이든 컬러든 문자 말고 음영(색깔 배경)이나 사진을 하나 보시기 바란다. 전부 촘촘한 점들로 구성돼 있다.
컴퓨터용 프린터나 전문 출판물 인쇄기들이 무슨 수십~수백 종에 달하는 물감을 갖고 있지는 않다. 잉크는 3원색에다가 검정 이렇게 4개만 갖고 있고, 나머지 색은 전부 얘들을 적절한 배율로 섞은 망점의 조합만으로 표현한다.

컴퓨터에서 보는 사진 이미지를 프린터로 출력하기 위해서는 가산 혼합 기반인 RGB 방식의 색을 감산 혼합 CMYK 방식으로 변환하고, 색 축별 망점 배합을 계산해야 할 것이다. 이건 디더링과는 다른 영역이다. 프린터 드라이버가 하는 일 중의 하나가 이것이며, 전문적인 사진이나 출판 프로그램 역시 색 축별로 인쇄 형태의 저수준 데이터를 export하는 기능을 제공한다.

그래도 요즘은 사진조차 필름 현상이 아니라 디지털 카메라로 찍은 뒤에 포샵질을 하고 고급 인화지에다 '인쇄'해서 만들어 내는 세상이니.. 컬러 인쇄 기술도 예전보다 굉장히 많이 좋아지고 저렴해졌다. 1990년대까지만 해도 가정용으로 컬러 레이저 프린터라는 걸 생각이나 할 수 있었겠는가?

유니코드 문자 중에 U+2591 ~ U+2593은 단계별 음영을 나타낸다.
굴림· 바탕 같은 통상적인 Windows 글꼴은 이를 하프톤 형태로 표현한 반면, 함초롬바탕은 디더링 형태로 표현했음을 알 수 있다.
윤곽선 글꼴의 래스터라이즈 방식의 특성상 디더링보다는 하프톤이 부담이 덜하기도 하다. 윤곽선 글꼴은 뭔가 덩어리· 군더더기가 늘어날수록 출력 성능이 급격히 떨어지기 때문이다. 그래서 매끄러운 곡선 말고 오돌토돌, 쥐 파먹은 효과 같은 걸 표현한 글꼴은 크기도 크고 처리하기 버거운 편이다.

사용자 삽입 이미지

이상이다. 이 사이트에도 그레이스케일, ordered 디더링, 기타 휴리스틱-_- 디더링, 그리고 하프톤까지 다양한 사례가 소개되어 있으니 관심 있는 분은 참고하시기 바란다.

우리가 사는 공간이 3차원일 뿐만 아니라, 시각 정보의 기본 단위인 색깔이라는 것도 어떤 방식으로 분류하든지 결국 3개의 독립된 축으로 귀착된다는 게 신기하지 않은가? 신학에서는 이게 하나님의 속성인 삼위일체와 관계가 있다고도 말하는데, 그건 뭐 결과론적인 해석이며 물증이라기보다는 심증 수준에서 만족해야 하지 싶다.

음악에서는 음계, 음정, 화성학 같은 이론이 수학과 연결되어 오래 전부터 연구돼 왔다.
그럼 일명 color theory라고 불리는 분야는 언제부터 누구에 의해 연구돼 왔을까? RGB, CMY, HSL 사이를 변환하는 공식 같은 것 말이다. 더디링은 컴퓨터그래픽 영역이겠지만 순수하게 색에 대한 수학적인 분석은 미술과 전산학 어디에도 딱 떨어지지 않아 보인다. 내가 알기로는 전파로 영상을 주고 받는 텔레비전 기술이 개발된 20세기 초쯤에야 이런 분야가 개척됐다.

본인이 색과 관련하여 감이 오지 않고 아직도 좀 알쏭달쏭한 걸 얘기하면서 글을 맺도록 하겠다.
모니터 화면 같은 건 그 본질이 빛이며, 빛은 색을 태생적으로 지니고 있다. 그러나 다른 세상 만물들, 특히 인쇄물은 색만 있지 빛은 지니고 있지 않다. 조명을 받아야만 자기 색을 비춰 보일 수 있다.

빛은 원색이 RGB라고 여겨지며, 섞일수록 더 밝아져서 최종적으로 white에 도달하는 ‘가산 혼합’을 한다. 그러나 빛이 없는 나머지 사물의 색들은 섞일수록 더 어두워져서 최종적으로 black에 도달하는 ‘감산 혼합’을 한다. 이 정도는 이미 초등학교 미술 시간에 배운다.

다만, 빛의 3축과 색의 3축은 노랑/초록 말고 빨강/파랑 부분도 서로 미묘하게 차이가 난다는 것부터는 고등교육 이상의 영역으로 보인다. 본인도 그걸 대학 이후에나 접했기 때문이다.
왜 그런 차이가 나는지에 대해서는 논외로 하더라도, 빛이건 색이건 두 색상을 물리적으로 섞지는 말고 디더링 하듯이 오밀조밀 가까이 배치시켜 놓으면 멀리서 볼 때 정확하게 어떤 혼색이 나타날까? 이걸 잘 모르겠다.

이건 빛이든 인쇄된 색이든 차이가 없어야 하지 않을까? 그리고 만약 차이가 없다면 그 결과는 감산 혼합이나 가산 혼합 중 어느 것과도 정확하게 일치하지 않을 것이다. 그 관계가 무엇일까? 마치 산술/기하/조화 평균처럼 서로 비슷하면서도 미묘하게 다른 결과가 나오지 않을까 싶다.

이해를 돕기 위해 아래 그림을 살펴보자. 반드시 확대/축소 왜곡되지 않은 원래 크기 형태로 볼 것!! (화면 확대 배율도 96DPI/100%로 맞춰야 함)
왼쪽은 그냥 RGB(0,0,0) 검정과 RGB(255,255,255) 하양을 1:1로 섞은 것이고, 오른쪽은 RGB(0,0,255) 파랑과 RGB(0,255,0) 초록을 섞어서 청록을 만든 것이다. 여기서 섞었다는 것은 픽셀 디더링을 말한다. 그리고 우측 하단에는 본인이 보기에 이들과 가장 비슷하다고 생각하는 순색(solid color)을 칠해 보았다.

사용자 삽입 이미지

255짜리 순색 파랑 255짜리 순색 초록을 섞어서 가산 혼합이 됐다면 RGB(0,255,255) 밝은 cyan 청록이 나타나야 하겠지만 실제로는 전혀 그렇게 되지 않았다. 그런데 그렇다고 해서 평균인 128짜리의 훨씬 어두운 색이 된 것도 아니다.
본인이 보기에 가장 비슷한 순색의 명도는 대략 180~184 정도이다. 생각보다 제법 밝다. 아.. 그래서 옛날에 VGA 팔레트도 어두운 색을 무식하게 128로 지정하지 않고 170 정도의 값을 줬는가 싶은 생각이 든다. 다른 색과 섞었을 때 재현 가능한 색이 나오라고 말이다.

이런 현상을 설명하기 위해 감마 보정 등 다른 어려운 이론들도 나온 게 아닌지 추측해 본다. 디더링 알고리즘이란 게 내가 생각했던 것보다 여러 단계로 나뉘고 더 어렵고 복잡할 수도 있겠다는 생각이 든다. 적절한 명도 추출하기, 적절히 대체색으로 분비하기, 오차 보정하기 등..;; 시각 디자인의 세계는 오묘하다.

Posted by 사무엘

2020/07/06 08:35 2020/07/06 08:35
, , , ,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/1770

원소가 0 아니면 1 두 종류밖에 없는 N*N 크기의 어느 정사각행렬 M(N)이 있다. N은 2의 거듭제곱 형태로만 가능하며, M(N)의 생성 규칙은 이러하다.

일단, 크기가 1인 M(1)은 그냥 {0} 하나뿐이다.
그 뒤, M(2*n)은 M(n)의 각 원소들에서 0과 1을 뒤바꾼 놈을 M(n)의 왼쪽과 위쪽, 그리고 좌측 상단에 총 3개 카피를 씌우는 형태로 생성된다. 그러므로 M(2)는

(1 1)
(1 0)

이 되며, 다음 M(4)는 쟤를 뒤바꾼 놈을 또 덧붙여서

(0 0 0 0)
(0 1 0 1)
(0 0 1 1)
(0 1 1 0)

이 된다. 생성 규칙이 이런 식이다.
이런 식으로 M(16), 더 나아가 M(256)을 그림으로 나타내면 이런 모양이 된다.

사용자 삽입 이미지

흐음. 무슨 프랙탈 같기도 하고..
이런 행렬은 고안자의 이름을 따서 Walsh 행렬이라고 부른다.
그런데, 모노크롬이나 16색을 어렵지 않게 접할 수 있던 옛날에 이런 무늬를 화면에다 깔아 놓으면 꽤 근사해 보였을 것 같다~!

이걸 갖고 더 재미있는 장난을 칠 수도 있다.
옛날옛적에 학교에서 전자· 컴공을 전공했던 분이라면 혹시 그레이 코드(gray code)라고 기억하는 분 계신가?
통상적인 2진법과 달리, 숫자가 1씩 증가할 때 언제나 1개의 비트만이 바뀌게 숫자를 특이하게 표현하는 방식이다. 즉, 01111이다가 10000으로 바뀌는 식의 격변이 없다는 것이다. 물론 이런 숫자 인코딩을 갖고 진지한 산술 연산을 할 수는 없지만, 다른 용도로 쓸모는 있다고 한다.

사용자 삽입 이미지

0 1 3 2 6 7 5 4 ...
난 저걸 봐도 비트를 flip하는 규칙 자체를 잘 모르겠다. 숫자가 커질수록 긴가민가 헷갈린다. 솔까말 이거 규칙을 찾는 걸로 IQ 테스트 문제를 내도 될 것 같다.
그런데 일반 숫자를 그에 상응하는 그레이 코드로 바꾸는 공식은 어이없을 정도로 간단하다. x^(x>>1), 다시 말해 자신의 절반값과 자신을 xor 하면 된다.

자, 여기서 끝이 아니다.
저 수열에서 각 숫자들을 구성하는 2진법 비트의 배열 순서를 뒤집어 보자. 10진법으로 치면 1024를 4201로 바꾸는 것과 같다.

비트를 shift나 rotate하는 게 아니라 reverse 하는 건 내가 알기로 왕도가 없다. 그냥 for문 돌려서 1비트씩 차근차근 처리하는 수밖에 없다. 마치 주어진 숫자를 2진법으로 표현했을 때 1의 개수를 구하는 것처럼 말이다.
비트 수가 고정돼 있고 속도가 무진장 빨라야 한다면 미리 계산된 테이블을 참조해야 할 것이다.

N=8이라면 비트 자릿수는 3일 테고.. 0 1 3 2는 2진법으로 각각 000, 001, 011, 010일 텐데,
이걸 뒤집으면 차례대로 000, 100, 110, 010.. 즉 0 4 6 2 ... 형태로 바뀐다. 이 정도면 완전 난수표 수준으로 숫자를 뒤섞은 거나 마찬가지로 보인다.

저 수열이 확보됐으면 그걸 토대로 기존 Walsh 행렬을 개조해 보자. 즉, 지금 줄 배열이 0 1 2 3 4..의 순인데, 그걸 0 4 6 2 ... 즉, 둘째 행(1)에다가 다섯째 행(4)을 집어넣고, 다음 행에다가 일곱째 행(6)을 넣는 식으로 순서를 바꾼다. 그러면..

사용자 삽입 이미지

이런 인상적인 모양의 무늬가 만들어진다. 이것도 크기별로 규칙성이 있다. 좌측 상단은 사각형이 큼직하고, 우측 하단으로 갈수록 픽셀이 조밀해진다.
얘는 여러 명칭으로 불리는데, 통상적으로는 Walsh 행렬의 Hadamard 변환이라고 불린다.
실제 저 행렬/테이블을 구하는 건 아무 프로그래밍 언어로나 10분이면 코딩 가능할 것이다. 참고로 비트 reverse 같은 난감한 동작 없이 저 행렬을 얻는 다른 계산법도 존재한다.

이런 무늬 행렬은 전자공학 신호 처리 쪽에서 쓰인다고는 하는데.. 난 그쪽을 전공하지 않아서 잘 모르겠다. 단지 0과 1만 갖고도 인간 두뇌의 잉여력이 얼마나 폭발할 수 있는지에 경이로움을 느낄 따름이다.

수 년 전에 디더링 패턴의 생성 규칙에 대해 글을 쓰고 나서 이런 재귀적인 무늬를 주제를 다룬 건 무척 오랜만이다. xor은 온갖 난수와 암호도 만들어 내는 이산수학과 정보 이론의 진수임이 틀림없어 보인다. 세상에 이런 게 있다는 걸 알게 됐다는 차원에서 간단히 글을 남기게 됐다.

(xor은 x-y 2차원 평면에다가 진리표를 나타냈을 때 0과 1 결과를 직선 하나로 단순 분류할 수 없는 유일한 연산이기도 하다. 일명 XOR 문제..;; 마치 특정 그래프에 대해 한붓그리기가 불가능한 것과 비슷한 인상을 주는데.. 과거에 한때는 퍼셉트론 무용론과 함께 AI 겨울을 야기한 이력이 있다.)

Posted by 사무엘

2020/06/09 08:35 2020/06/09 08:35
, , ,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/1760

1. 완전히 새로운 알고리즘 분야

컴퓨터는 정말 대단한 기계이다.
정보의 최소 단위인 0과 1을 분간하고, 임의의 주소가 가리키는 메모리의 값을 읽거나 쓸 수 있고 프로그램의 실행 지점도 메모리의 값을 따라서 변경 가능하게 했더니(튜링 완전) 그야말로 무궁무진한 양의 정보를 가히 무궁무진한 방식으로 처리가 가능해졌다.

이런 이론적인 근간이 마련된 뒤에 반도체의 집적도가 더 올라가고 메모리와 속도가 더 올라가고 가격이 더 내려가는 건 그냥 시간 문제일 뿐이었다.
그런데.. 단순히 복잡한 계산이나 방대한 검색을 빠르게 해내는 것만으로 컴퓨터가 인간의 고유 영역을 완전히 침범하고 대체했다고 보기는 곤란하다. 그건 그냥 자동차가 인간보다 더 빠르고 중장비가 인간보다 더 힘센 것만큼이나, 기계가 인간의 역할을 일부 보조하고 확장하는 것일 뿐이다.

물론 단순히 동력과 관련된 분야는 말이나 소 같은 동물도 인간보다 약간이나마 더 우위에 있긴 했다. 그에 비해 정보 처리 분야는 자연계에 지금까지 인간의 라이벌 자체가 아예 존재한 적이 없었다는 차이가 있다.
그러나 인간도 속도가 느리고 개인의 능력이 부족할 뿐이지.. 많은 인원을 동원하고 많은 시간만 주어지면 기계적인 정보 처리 정도는 '유한한 시간' 안에 언젠가 다 할 수 있다. 일을 좀 빠르고 정확하게 수행하는 것만 갖고 '창의적이다', '인간을 닮았다'라고 평가해 주지는 않는다.

정렬과 검색에, 다이나믹이니 분할 정복이니 하는 최적해 구하기처럼 고전적인 분야에서 고전적인(?) 방법론을 동원하는 알고리즘은 이미 수십 년 전에 다 연구되어서 깔끔한 결과물이 나왔다. 그런 건 이미 대학교 학부 수준의 전산학에서 다 다뤄지는 지경이 됐으며, 정보 올림피아드라도 준비하는 친구라면 아예 중등교육 수준에서 접하게 됐다.

그런데 현실에서는 그렇게 깔끔하게 떨어지지 않는 더 복잡하고 난해한 문제를 풀어야 한다. 깔끔하게만 접근했다가는 시간 복잡도가 NP-hard급이 되어 도저히 감당할 수 없는 문제를 적당히 타협하여 풀어야 한다.
중· 고등학교의 고전역학 문제에서는 "공기의 저항은 무시한다" 단서가 붙지만, 대학교에 가서는 그런 것까지 다 고려해야 하는 것처럼 말이다.

대수적으로 답을 구할 수 없는 문제에 대해 근사치를 효율적으로 구하기 위해 수치해석이라는 기법이 등장했듯, 전산학에도 각종 휴리스틱과 근사 알고리즘이라는 게 존재한다. 압축 알고리즘으로 치면 무손실이 아닌 손실 분야인 셈이다. 구체적인 건 학부 수준을 넘어 대학원에 소속된 별도의 연구실에서 다룰 정도로 난해하다.

그런데.. 이런 것들은 여전히 사람이 범접하지 못하는 분량의 계산 문제를 최대한 빠르게 효율적으로 푸는 방법에 대한 연구이다. 그런 것 말고 사람은 간단히 하는데 컴퓨터에게는 굉장히 난해해 보이는 일이 있다.
컴퓨터로 하여금 텍스트나 음성 형태의 인간의 자연어를 알아듣고 타 언어로 번역한다거나, 그림으로부터 글자 같은 정보를 알아보게 할 수 없을까?
컴퓨터를 바둑· 장기· 오목 같은 게임의 고수로 키울 수 없을까?

이건 단순히 TSP(순회하는 세일즈맨 문제)를 더 그럴싸한 가성비로 다항식 시간 만에 푸는 것과는 분야가 다르다.
저런 걸 기계가 인간과 비슷한 속도와 정확도로만 해내더라도 굉장한 이득이다. 기계를 부리는 비용은 인간을 고용하는 인건비보다 넘사벽급으로 저렴한 데다, 기계는 인간 같은 감정 개입이 없고 지치지 않고 실수도 전혀 하지 않기 때문이다.

하물며 속도와 정확도가 인간 전문가의 능력을 능가하게 된다면 게임 끝이다. 기계적인 단순 노동력이나 판단력만을 요구하는 일자리는 사라지며, 인간은 기계가 대신할 수 없는 더 창의적이고 전문적인 일자리로 갈아타야 할 것이다.

2. 흑역사

소위 '인공지능'에 대한 연구는 진공관이니 트랜지스터니 하던 무려 1950년대 컴퓨터의 초창기 때부터 천조국의 날고 기는 수학자, 컴퓨터 공학자들에 의해 진행돼 왔다. 특히 세부 분야 중 하나로서 기계번역도 연구됐으며, 1954년에는 조지타운 대학교와 IBM이 공동 연구 개발한 기계번역 솔루션이 실제로 출시되기도 했다.

인류 역사상 최초로 기계번역이란 게 연구된 언어는 러시아어 → 영어이며, 이는 전적으로 냉전 덕분이다. 하긴, 2차 세계 대전 때는 번역이 아니라 암호를 해독하는 기계가 개발되긴 했었다. 적성국가들의 언어 중 일본어는 영어와의 기계번역을 연구하기에는 구조가 너무 이질적이고 어려웠을 것이다.

그래도 인간 번역가가 아닌 컴퓨터가 러시아어 텍스트로부터 영어 텍스트를 허접하게나마 뱉어 내자 학계와 업계는 흥분했다. 이런 식으로 조금만 더 연구하면 컴퓨터가 금방이라도 세계의 언어 장벽을 다 허물어 줄 것 같았다.

그때는 학자들이 자연어에 대해서 뭔가 순진 naive하게 원리 원칙대로 규칙 기반으로, 낭만적으로 접근하던 시절이었다. 인간의 언어도 무슨 프로그래밍 언어처럼 유한한 문법과 생성 규칙만으로 몽땅 다 100% 기술 가능하고 parse tree를 만들고 구문 분석이 가능할 거라고 생각했다. 물론 그 규칙이 간단하지는 않겠지만, 촘스키 같은 천재 언어학자 몇 명을 외계인과 함께 골방에다 갈아 넣고 며칠 열나게 고문하면 다 찾아낼 수 있을 것이고.. 그러면 언어의 기계 분석은 게임 끝이지 않겠냐 말이다.

궁극적으로는 전세계 모든 언어들의 교집합과 합집합 요소를 망라하는 중간(intermediate) 언어도 만들 수 있을 것이라고 생각했다. 세계 각국의 언어들을 그 중간 언어와 번역하는 시스템만 만들면 전세계 사통발달 언어 번역 시스템을 만들 수 있지 않겠는가? 이 정도 생각은 나조차도 한 적이 있다.

그랬으나.. 뚜껑을 열어 보니 영광은 거기서 끝이었다.
기계번역은 빵점 백지 상태에서 4, 50점짜리 답안을 내놓는 것까지는 금방 할 수 있었지만, 거기서 성적을 7, 80점짜리로라도 올려서 실용화 가능한 상품은 오랫동안 연구비를 아무리 투입해 줘도 선뜻 나오지 않았다.
인간의 언어라는 게 절대로 그렇게 호락호락 만만하지 않고 매우 불규칙하고 복잡한 구조라는 게 연구하면 연구할수록 드러났기 때문이다. 지금까지 사용한 연구 방법론 자체가 약발이 다하고 한계에 다다랐다.

이 때문에 1970년대에는 돈줄을 쥔 높으신 분들이 "인공지능"이란 건 밥값 못 하는 먹튀 사기 허상(hoax)일 뿐이라고 매우 비관적이고 보수적으로 생각하게 됐다. 컴퓨터는 그냥 계산기일 뿐, 그 돈으로 그냥 인간 번역가나 더 양성하고 말지..
이 단어 자체가 학계의 흑역사 급으로 금기시되어 버렸다. 인공지능이란 게 키워드로 들어간 논문은 저널에서 믿고 걸러냈으며, 관련 연구들의 연구비 지원도 모조리 끊길 정도였다.

이 현상을 학계에서는 제1차 AI 겨울(혹한기, 암흑기, 쇼크, 흑역사 등등...)이라고 부른다. 과거의 무슨 오일 쇼크 내지 게임 업계 아타리 쇼크처럼 말이다.
그렇게 고비를 겪었다가 더 발달된 연구 방법론으로 활로가 발견되고, 그러다가 또 2차 겨울을 극복한 뒤에야 요 근래는 인공지능의 중흥기가 찾아왔다고 여겨진다.

3. 문제는 데이터

지금은 기계번역이건, 게임 AI이건, 패턴인식이건 무엇이건.. 인공지능의 주재료는 규칙이 아니라 데이터이다.
기계번역 시스템을 개발하는데 언어학 문법 지식이 동원되지 않으며, 보드 게임 AI를 만드는데 통상적인 게임 규칙 기반의 알고리즘이 동원되지 않는다. 이상한 노릇이 아닐 수 없다.

그러는 게 아니라 요즘 인공지능이라는 것은 아이디어는 매우 간단하다. 기출문제와 정답을 무수히 많이, 인간이 상상할 수도 없을 정도로 많이 주입시켜 준 뒤, 이로부터 컴퓨터가 규칙성을 찾아내고 새로운 문제가 주어졌을 때 정답을 추론하게 하는 방법을 쓴다. 해결하고자 하는 문제를 기술하고 정답의 조건을 명시하고 알고리즘을 구현하는 걸 인간이 일일이 하는 게 아니라.. 그 자체를 컴퓨터가 알아서 하게 하는 것이다.

이것이 '기계학습', 그 이름도 유명한 machine learning이다. 이것이 이전에 인공지능을 구현하는 방법론이던 '전문가 시스템'을 대체했다. 이런 무지막지한 방법론이 적용 가능할 정도로 요즘 컴퓨터의 속도와 메모리가 매우 크게 향상된 덕분이다.

인간의 입장에서 기계학습을 시키는 방식은 지도(supervised learning) 또는 비지도 학습으로 나뉜다.
그리고 기계의 입장에서 학습(?)을 실제로 수행하는 방법으로는 인공 신경망, 앙상블, 확률(은닉 마르코프 모델), 경사/기울기 하강법 같은 여러 테크닉이 있는데, 기울기 하강법은 복잡한 선형 방정식을 푸는 심플렉스와 비슷하다는 느낌도 든다.

인공 신경망은 생물의 신경망이 동작하는 원리에서 착안하여 만들어진 기계학습 모델이라고는 하지만 당연히 실제 인간 뇌의 작동 방식에 비할 바는 못 된다.
MLP니 CNN이니 RNN이니 하는 신경망 용어들이 존재하며, 그리고 이 인공 신경망을 어떻게 하면 잘 갖고 놀 수 있을까 고민하는 연구 분야를 '딥 러닝'(심층학습)이라고 한다. 마치 네트워크 계층의 다양한 기술 용어만큼이나 AI에도 계층별로 다양한 기술 용어가 존재한다.

게임 AI라면 단순히 뭔가를 인식하고 분류만 하면 장땡인 게 아니라 뭔가 극한의 최적해를 찾아가야 할 텐데.. 이런 걸 학습시키는 건 딥 러닝의 영역이다. 알파고처럼 말이다. 그런데 알파고 하나가 지구상의 최고의 인간 바둑 기사를 이긴 것은 물론이고, 다른 재래식 알고리즘으로 십수 년간 개발되어 온 기존 바둑 AI들까지도 다 쳐발랐다니 무서운 일이 아닐 수 없다. 뭐, 개인용 PC 한 대만으로 그렇게 동작하는 건 아니긴 하지만 말이다.

오늘날 연구되고 있는 인공지능은 무작정 인간과 동급으로 생각하고 창조하는 기계는 당연히 아니고, 컴퓨터의 막강한 메모리와 계산 능력으로 지금까지 주어진 데이터를 토대로 새로운 상황에 대처하는 답안을 꽤 그럴싸하게 제시하는 '약한 인공지능'일 뿐이다.

쉽게 말해 "서당 개 삼 년이면 풍월 읊는다"처럼 말이다.
추리소설를 한 1000편쯤 읽고 나니 다른 새로운 추리 퀴즈에도 설정이 뻔히 보이고 답이 보인다.
드라마를 1000편쯤 보고 나니 비슷비슷한 드라마들은 스토리 전개가 어찌 될지 '안 봐도 비디오'처럼 된다. 그런 것 말이다.

그런데 저게 말처럼 쉬운 일인 건 아니다.
학습 대상인 무수한 텍스트· 이미지· 음성 데이터 내지 각종 게임 복기 데이터를 어떤 형태로 수치화해서 벡터 형태로 표현할 것인가?
그리고 '학습'이라는 걸 하는 동안 해당 AI 엔진의 내부에서는 구체적으로 무슨 계산 작업이 행해지는가?
컴파일러만 해도 결과물로 OBJ 파일이라는 게 생기는데, 그 내부적인 학습 상태는 어떤 형태로 표현되며, 이것만 따로 저장하고 불러오는 방법이 존재하는가? 본인은 AI알못이다 보니 전혀 모르겠다. ㅡ,.ㅡ;;

수천, 수만, 아니 그 이상 셀 수 없이 많은 숫자들로 이뤄진 벡터 I가 또 수없이 많이 있다고 치자. 이 숫자들은 현실 세계를 표현하는 미세한 자질을 표현한다.
그런데 어떤 블랙박스 함수 f가 있어서 f(I_1..n)에 대한 결과가 O_1..m라는 벡터 집합으로 나왔다고 한다.

컴퓨터는 이 I와 O 사이에서 규칙성을 찾아서 I에 대해 O와 최대한 비슷한 결과를 산출하는 함수 f를 구한다. 그러면 이제 임의의 다른 아무 input에 대해서도 수긍할 만한 출력 결과를 얻을 수 있을 것이다.
패턴 인식? 기계번역? 유사 작곡이나 창작? 현실에서 해결하려는 문제가 무엇이건 machine learning이 하는 일은 본질적으로 저걸로 요약된다. 내가 AI 쪽으로 아는 건 이게 전부이다.

지금은 TensorFlow 같은 범용적인 기계학습 엔진/라이브러리까지도 구글 같은 괴물 기업에 의해 오픈소스로 몽땅 풀려 있으며, 이걸 파이썬 같은 간편한 스크립트 언어로 곧장 돌려볼 수도 있는 세상이 됐다.
그런 라이브러리를 직접 개발하고 유지보수 하는 것까지는 바라지도 않는다. 방대한 현실 데이터를 수집해서 저기에다 적절하게 집어넣고, 이로부터 고객이 원하는 유의미한 추세나 분석 결과를 얻는 것만 해도 뭔가 프로그래밍 코딩과는 별개로 아무나 할 수 없는 전문 영역의 일이 돼 있다.

오늘날 AI 엔진의 연구를 위해서는 근간 이론이라 할 수 있는 선형대수학, 편미분, 확률 통계는 무조건 먹고 들어가야 된다. 엔진 코드를 직접 다루지 않고 쓰기만 하는 사람이라도 엔진이 어떤 원리로 돌아가는지 정도는 알아야 가장 적절한 방법론/알고리즘을 선택할 수 있을 테니 저런 것들을 맛보기 수준으로라도 알아야 할 것이다.

과거에 정보 사냥 대회가 있었던 것처럼 이제는 주어진 데이터로부터 새로운 문제를 잘 푸는 기계학습 모델을 설계하는 것이 경진대회의 아이템 내지 학교와 직장의 과제가 될 것으로 보인다. 컴퓨터가 할 수 있는 일이 더 늘어난다면 사람만이 할 수 있는 일은 그보다 더 수준 높고 추상적인 쪽으로 이동할 수밖에 없으니 말이다.

아무리 그래도 그렇지 자연어의 문법과 어휘 자체를 전혀 모르는 상태에서 데이터 학습만으로 댓글이 선플인지 악플인지를 기계가 분간할 수 있는 걸까? 그래도 클레멘타인 영화에 늘어선 댓글이 선플인지 악플인지 판단하려면 그에 대한 특별한 학습-_-;;이 필요할 것 같다.

그리고 변화무쌍 복잡한 필기체의 인식이 아니라, 그냥 자동차 번호판의 정향화된 숫자 내지 겨우 QR 코드의 인식 정도는.. '영상 처리 기술'의 영역이지, 저 정도의 거창하게 기계학습이니 뭐니 하는 인공지능의 영역은 아니다. 그건 구분해서 생각할 필요가 있다.

오래 전부터도 각종 전산학 알고리즘 용어를 검색할 때 종종 걸려 나오긴 했는데.. 국내 개인 사이트 중에 AIStudy라는 곳이 있다. 나모 웹에디터가 있던 시절부터 존재했던 정말 옛날 사이트이다. 그런데 운영자가 내 생각보다 굉장히 어린 친구이다. 정말 대단할 따름이다.
당연히 과학고-카이스트 라인이려나 생각했는데 그렇지는 않고 일반고-서울대 테크를 타 있다. 앞날에 건승을 빌어 본다.

Posted by 사무엘

2019/07/06 08:33 2019/07/06 08:33
, , , ,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/1637

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

블로그 이미지

철도를 명절 때에나 떠오르는 4대 교통수단 중 하나로만 아는 것은, 예수님을 사대성인· 성인군자 중 하나로만 아는 것과 같다.

- 사무엘

Archives

Authors

  1. 사무엘

Calendar

«   2022/08   »
  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:
1855545
Today:
402
Yesterday:
598