2010년 12월 29일 수요일

파이어폭스 검색을 더욱 은밀하게

구글은 검색 정보를 암호화해서 전송할 수 있는 Google search over SSL을 제공한다. 이 사이트에 직접 들어가서 검색을 하면 검색어, 검색결과 등이 암호화되어 네트워크에서 여러분의 검색정보를 영탐할 수 없게 할 수 있다. 하지만, 파이어폭스의 우측 상단에 있는 검색바를 이용한다면, 검색정보가 네트워크에 그대로 드러나게 된다.

Google search over SSL

이 검색창도 Google search over SSL 서비스를 이용하도록 하면, 여러분의 검색정보를 보호할 수 있다. 검색바의 왼쪽에 있는 화살표를 아이콘을 누르면 제일 아래에 '검색 사이트 관리...'를 볼 수 있다. 여기서 '추가할 검색 사이트 찾기...'를 클릭하면, 파이어폭스 애드온 페이지로 연결된다. 여기서 Google search over SSL 관련 애드온을 찾을 수 있는데, 페이지 오른쪽 위편의 '부가 기능 검색하기' 서식에 'Google SSL'이라고 검색하면 관련 SSL을 찾을 수 있다. 몇몇 애드온을 찾을 수 있는데, SSL Search Bar가 제작한 Google (SSL)을 설치해보자. 오른쪽의 녹색 'Firefox에 추가' 버튼을 누르면, 설치가 진행된다. 이제 브라우저의 검색창 아이콘을 다시 클릭해보면, 'Google (SSL)'이 설치된 것을 알 수 있다.

Google (SSL)이 제대로 작동하는 것은 몇 가지 사항을 통해서 확인할 수 있다. 먼저, 브라우저의 검색바에 Google 대신에 Google (SSL)이라고 쓰여 있는 것을 확인할 수 있다. 한번 검색을 해보자. 검색 결과 페이지의 구글 마크에 조가만 SSL 문구를 볼 수 있다. 또, 주소창을 보면 프로토콜이 http가 아니라 https인 것을 알 수 있다. 이제 좀 더 안전한 검색을 할 수 있는 환경이 구축되었다.

Google (SSL)을 사용하도록 설정한 검색바

참고로, SSL 검색에서는 지원되지 않는 기능이 많이 있다. 가장 눈에 띄는 것은 특정일에 따라 변하는 구글 로고를 볼 수 없다는 것! 점차 많은 서비스를 SSL로 제공한다고 하니 일단 기다려보자.

2010년 12월 6일 월요일

리눅스와 윈도의 줄바꿈 차이

글을 입력하면서 커서가 화면의 오른쪽 끝에 이르면 '줄바꿈'을 해야 한다. 리눅스와 윈도 모두 '줄바꿈'을 할 때 누르는 키는 '엔터(Enter)'이고 화면에서 나타나는 모양새는 같은데, 내부적인 처리에는 차이가 있다.

윈도는 옛 타자기 시절의 습관을 고스란히 옮겨 놓은 낭만적인 방식을 택한다. 타자기를 사용하던 시절엔 입력하는 글의 줄을 바꾸려면 두 가지 동작이 필요했다. 먼저, 사용자가 글자를 입력함에 따라 종이를 왼쪽으로 옮겨주는 캐리지(carriage)라는 부품을 오른쪽 끝으로 밀어야 한다. 그런 다음 종이를 조금 위로 올려서 다음 줄의 첫 부분에 활자가 닿을 수 있도록 조정해야 한다. 캐리지를 오른쪽 끝으로 되돌려 놓는 동작은 컴퓨터에서 커서의 위치를 왼쪽 끝으로 되돌려 놓는 동작에 해당하고, 이를 복귀(carriage return)이라고 한다. 문자열 표기(string notation)로는 '\r'로 나타낸다. 종이를 위로 올리는 동작은 현재 커서가 있는 줄의 아래에 입력 가능한 줄을 삽입하고 커서를 한 칸 아래로 내리는 동작에 해당하며 이를 새줄(new line)이라고 한다. 문자열 표기로는 '\n'으로 나타낸다. 실제로 글을 입력할 때 줄을 바꾸려면 엔터 키만 누르지만, 문서의 각 줄 끝에는 '\r\n'이 들어간다.

리눅스(유닉스 계열)는 컴퓨터에 적합한 실용적인 방식을 택한다. 타자기는 기계적인 한계 때문에 '복귀'와 '새줄'이라는 동작을 차례로 해야 했지만, 컴퓨터에서는 굳이 그럴 필요가 없다. 그래서 '줄바꿈'이라는 표시로 '\n'만을 사용한다.

모든 비표준이 그렇듯이, 이러한 차이는 리눅스와 윈도를 오가며 문서를 작성하다 보면 불편한 점을 만든다. 윈도에서 작성한 문서를 리눅스에서 보면 모든 줄 끝에 '^M'이라는 문자가 나타난다. 리눅스는  '\n'만을 '줄바꿈'으로 문자로 인식하고, '\r'은 해당 꺽쇠 표기(caret notation)인 '^M'로 화면에 표시하는 것이다.

윈도 줄바꿈 형식을 사용한 문서를 유닉스 계열의 줄바꿈 형식으로 열면 ^M 문자를 볼 수 있다.

이건 그나마 나은 편이다. 리눅스에서 작성한 문서를 윈도에서 보면 문서의 모든 내용이 한 줄에 표시된다. 윈도에서 줄바꿈으로 인식하는 '\r\n'이라는 제어 문자가 없으니 한 줄에 모든 내용을 표시해버린다.

유닉스 계열의 줄바꿈 형식을 사용한 문서를 윈도에서 열면 줄바꿈이 되지 않는다.

요즘은 편집기가 똑똑해져서 '줄바꿈' 제어 문자가 뭐로 되어 있든지 알아서 잘 처리해주지만, 때로 문제가 되기도 한다. 한 문서에 여러 가지 '줄바꿈' 제어 문자가 들어 있으면, 편집기가 이를 잘 처리하지 못하기도 하고, 시스템 환경과 다른 '줄바꿈' 문자 때문에 스크립트 프로그램이 이상한 오작동을 하기도 한다. 그렇다면, 윈도 방식의 줄바꿈으로 된 문서를 리눅스 방식의 줄바꿈으로 바꾸려면 어떻게 해야 할까?

쉘에서 손쉽게 바꾸는 방법은 아래와 같다.
$ cat <FileName> | tr -d '\r' > out; mv out <FileName>
이맥스에서 두 가지 방법으로 할 수 있다. 첫 번째는 ^M을 공백으로 치환하는 방법이다. C-Home으로 버퍼의 첫 부분으로 간 다음 아래 명령을 실행한다.
M-% C-q C-m RET RET !
C-q는 입력 버퍼에 제어 문자를 입력하게 해주는 키이다. 두 번째로 현재 버퍼의 코딩 방식을 바꿔주는 방법이 있다.
M-x set-buffer-file-coding-system을 입력하거나 C-x RET f를 입력해서, 미니버퍼에
Coding system for saving file (default nil):
이 뜨면, unix를 입력한다.

2010년 10월 27일 수요일

오일러의 수, 전기장, 에너지

매스매티카 사용자에게 오일러의 수, 전기장, 에너지를 생각하면 떠오르는 건 뭘까? 방정식에서 모두 E로 표기된다는 점이다. 그래서 문제가 발생한다. 실수로 아래와 같이 입력하면,
E == m c^2
결과는




이 된다. 이 방정식은 좌변은 오일러의 수로 상수를 나타내므로 틀린 식이다. 매스매티카에서 대문자 E는 오일러의 수를 가리킨다. 즉, 매스매티카에서 E 또는 Esc+ee+Esc, 혹은 \[ExponentialE]를 입력하면 이건 오일러의 수를 나타낸다. 그럼, 전기장이나 에너지를 뜻하는 변수로 E를 쓸 수는 없을까? 유감스럽게도 그렇다. 다른 문자를 사용해야 한다. 하지만, 대안이 있다. 보기에 E와 비슷한 문자를 사용할 수는 있다. \[CapitalEpsilon] 즉, 그리스 문자 ε의 대문자가 E와 비슷하게 생겼는데, 이걸 사용하면 된다.
\[CapitalEpsilon] == m c^2
라고 입력하면 쓸만한 결과를 얻을 수 있다.




다행히도 단축키도 있어서 매번 \[CapitalEpsilon]을 입력할 필요도 없다. 단축키는 Esc+E+Esc이다.

x에 대하여 정리하면...

대중에게 알려진 가장 유명한 방정식은 아인슈타인의 에너지와 질량의 동등성을 나타내는
e == m c^2
일 것 같다. 여기서 m은 물체의 질량, c는 진공에서 빛의 속도, 그리고 e는 이 질량에 저장된 에너지를 뜻한다. 이 방정식을 m에 관해 정리하려면, 즉 m만 좌변에 남기고 모두 우변으로 옮기려면 어떻게 해야 할까? 방정식을 m에 관해 풀면 된다.
e == m c^2
% // Solve[#, m] &
결과는 방정식이 아닌 Rule로 주어진다. 이걸 방정식으로 바꾸려면, 아래와 같이 리스트(List)를 벗겨 내고, 헤더를 Equal로 바꿔주면 된다.
e == m c^2
% // Solve[#, m][[1, 1]] & // Equal @@ # &
그럼, c^2에 관해 정리하려면 어떻게 해야 할까? 위와 같은 방법으로 하면 c^2가 적절한 변수가 아니라는 오류 메시지를 보게 될 뿐이다. 이럴 땐, c^2를 잠시 HoldForm으로 잡아두면 문제를 해결할 수 있다.
e == m c^2
% /. c^2 -> HoldForm[c^2] // Solve[#, HoldForm[c^2]][[1, 1]] & // 
  ReleaseHold // Equal @@ # &
Solve로 항을 정리한 후에 ReleaseHold를 사용하면 간단하게 HoldForm을 제거할 수 있다.

2010년 9월 26일 일요일

주기율표에 나오는 원소기호로 만들 수 있는 가장 긴 단어는?

KAIST의 정재승 교수가 트위터에 던진 질문인데, 인터넷에서 몇몇 분이 이 문제를 풀었다. 그 중, 조승연 씨가 파이썬으로 작성한 코드는 아래와 같다.
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import re

f = open("/usr/share/dict/words", 'r')
maxlen = 0
maxword = ""
pattern = r"^(Ac|Al|Am|Sb|Ar|As|At|Ba|Bk|Be|Bi|Bh|B|Br|Cd\
|Ca|Cf|C|Ce|Cs|Cl|Cr|Co|Cu|Cm|Ds|Db|Dy|Es|Er|Eu|Fm|F|Fr\
|Gd|Ga|Ge|Au|Hf|Hs|He|Ho|H|In|I|Ir|Fe|Kr|La|Lr|Pb|Li|Lu|Mg\
|Mn|Mt|Md|Hg|Mo|Nd|Ne|Np|Ni|Nb|N|No|Os|O|Pd|P|Pt|Pu|Po\
|K|Pr|Pm|Pa|Ra|Rn|Re|Rh|Rg|Rb|Ru|Rf|Sm|Sc|Sg|Se|Si|Ag\
|Na|Sr|S|Ta|Tc|Te|Tb|Tl|Th|Tm|Sn|Ti|W|Uuh|Uuo|Uup|Uuq\
|Uus|Uut|U|V|Xe|Yb|Y|Zn|Zr|Cn)+$"

for line in f:
   ll = line.strip()
   if re.match(pattern, ll, flags=re.IGNORECASE) and \
len(ll) > maxlen:
      maxlen = len(ll)
      maxword = ll

print maxlen, maxword
이 페이지에 나온 답은 22글자의 nonrepresentationalism이지만, 내가 가진 사전 파일에는 이 단어가 없다. 대신 19글자의 nonrepresentational이 걸린다. 이걸 매스매티카로 해보면?
FindMaxElementWord[dictFile_] :=
 Module[{maxlen = 0, maxword = "", elements, pattern, dict, word},
  elements = Table[ElementData[n, "Abbreviation"], {n, 118}];
  pattern =
   "^(" <> Drop[Flatten[Map[{#, "|"} &, elements]], -1] <> ")+$";
  dict = OpenRead[dictFile];
  word = Read[dict, Word];
  While[word =!= EndOfFile,
   If[StringMatchQ[word, RegularExpression[pattern],
      IgnoreCase -> True] &&
     StringLength[word] > maxlen, {maxlen,
      maxword} = {StringLength[word], word}];
   word = Read[dict, Word]];
  Close[dict];
  Return[{maxlen, maxword}]]
알고리듬은 위의 파이썬 코드와 같다. 다만, 원소기호를 자동으로 생성하도록 바꾸었다. FindMaxElementWord["/usr/share/dict/words"]를 실행해보면, 역시 19글자의 nonrepresentational이 걸린다.

2010년 9월 7일 화요일

상수 모으기

매스매티카를 쓰다 보면, 간단한 수식인데 깔끔하게 정리하기 어려울 때가 있다. 예를 들어, Collect[2/x - 2/y, 2]의 결과가


이렇게 나오면 좋겠지만, 결과는 2/x - 2/y이다. 2로 묶어주려면, 어떻게 해야 할까? 이런 어려움에 봉착했을 땐 우선 풀폼을 확인한다.
FullForm[2/x - 2/y]
 

풀폼에서 알 수 있듯이, 첫 번째 항은 2가 두 번째 항은 -2가 곱해져 있어서 2로 묶지 못한다. 답답하게도 -2에서 2를 빼내지 못하는군. 그럼, -2-1*2로 바꿔주면 되겠다 싶지만, 여기에도 문제가 있다. 매스매티카는 -1*2를 입력하면 바로 -2로 바꿔버리므로, 바꾸지 못하게 해야 한다.
2/x - 2/y
% /. -2 -> HoldForm[-1] 2
% // Collect[#, 2] & // ReleaseHold
이제 됐을까? 결과를 보면 알겠지만, 이번에도 실패다. Collect가 문제인데, Collect는 변수만을 모을 수 있기 때문이다. 그럼, 2는 변수가 아닌데 어떻게 해야 할까? 2HoldForm[2]로 치환해서 변수처럼 만들어주면 된다.
2/x - 2/y
% /. -2 -> HoldForm[-1] 2 /. 2 -> HoldForm[2]
% // Collect[#, HoldForm[2]] & // ReleaseHold
이제야 원하는 결과가 나오는군. 휴~

2010년 8월 18일 수요일

일부를 제외하고 치환하려면

예를 들어 {f[x], g[x], h[x]}이 있는데, xy로 치환한다고 하자. 이건 쉽다.
{f[x], g[x], h[x]}
% /. x -> y
이렇게 하면, {f[y], g[y], h[y]}를 얻을 수 있다. 그러면 h[x]x만 치환한다면? 물론 여기선 ReplaceAll[{f[x], g[x], h[x]}, h[x] -> h[y]]로 바꾸는 게 가장 쉽지만, 일반적으로는 아래처럼 하면 된다.
{f[x], g[x], h[x]}
% // MapAt[# /. x -> y &, #, 3] &
그럼 f[x]만을 제외하고 치환하려면? ReplaceAll은 한번 치환한 건 다시 치환하지 않으므로, 다음과 같이 쉽게 해결할 수 있다.
{f[x], g[x], h[x]}
% /. {f[x] -> f[x], x -> y}

2010년 8월 10일 화요일

회절 무늬

빛의 회절에는 프레넬 회절(Fresnel diffraction, near-field diffraction)프라운호퍼 회절(Fraunhofer diffraction, far-field diffraction)이 있는데, 흔히 회절이라 하면 프라운호퍼 회절을 일컫는다. 프라운호퍼 회절 무늬를 계산해보면 입사하는 빛의 2차원 푸리에 변환이 되는 것을 알 수 있다. 따라서, Fast Fourier Transform(FFT)을 이용해서 회절 무늬를 쉽게 그려볼 수 있다.

구멍에 들어가는 빛의 세기가 일정하다는 가정을 사용하면, 구멍의 모양이 바로 구멍을 통과하는 빛의 모양이므로 구멍의 모양을 바로 푸리에 변환하면 된다. 김프(GIMP)를 이용해서 구멍의 모양을 미리 만들어 두었다.
김프로 만든 임의의 슬릿 모양
이 이미지 파일을 불러들여, 수치 자료로 변환한다.
img = Import["spiral_aperture.png"]
data = img // ImageData;
이 자료의 모양을 확인해보면,
Dimensions[data]
{400, 400, 3}과 같이 3차원인 것을 알 수 있다. 마지막 차원은 RGB 채널 정보인데, 빛의 세기만 고려하므로 이 채널 중 하나만 뽑아 쓰면 된다.
data = img // ImageData // #[[All, All, 1]] &;
이제 자료에 FFT를 적용하면 된다. 다만, FFT에선 파수(wave number)가 0부터 2k까지로 정의되므로, RotateLeft를 이용해서 파수의 범위가 -k에서 k까지 되도록 결과 배열을 조정해줘야 올바른 회절 무늬를 볼 수 있다. 또한, ListDensityPlot은 이미지 자료와 y축 방향이 반대이므로 결과 배열을 y축에 대해서 거꾸로 그려야 한다.
data // Fourier // Abs // 
   RotateLeft[#, Ceiling[Dimensions[#]/2]] & // Reverse // 
 ListDensityPlot
꽈리 모양의 슬릿을 통과한 빛의 회절 무늬

2010년 8월 4일 수요일

변수 대입하기

다음과 같이 eq1eq2가 주어졌을 때, eq1eq2a를 대입하려면 어떻게 해야 할까?
F == m a
eq1 = %;
a == D[x[t], {t, 2}]
eq2 = %;
가장 일반적인 방법은 속 편하게 Eliminate 함수를 이용해서 a를 제거하는 것이다.
Eliminate[{eq1, eq2}, a]
강력한 방법이긴 하지만, 이 예와 같이 간단한 경우엔 닭 잡는 데 소 잡는 칼을 쓰는 격이다. 필요 이상으로 시간이 오래 걸리기도 하고, 때론 방정식의 형태를 보기 어렵게 만들어 놓기도 한다. 이럴 땐, 다음처럼 바로 대입하는 편이 더 낫다.
eq1 /. Rule @@ eq2

2010년 8월 3일 화요일

두 방정식의 양변을 더하라.

다음 두 방정식의 양변을 더하면?
A == B
C == D
%% + %
결과는 (A == B) + (C == D) 이다. 당연히 우리가 원하는 결과가 아니다. 매스매티카가 이 정도도 처리 못할까?
A == B
C == D
%% + % // Thread[#, Equal] &
이렇게 Thread를 이용해서 Plus를 각 변끼리 적용해주면 된다. 두 방정식이 목록으로 주어졌다면, ListPlus로 교체하는 것만으로도 더하는 효과를 줄 수 있다.
{A == B, C == D}
Plus @@ % // Thread[#, Equal] &
그럼, 양변을 빼려면 어떻게 해야 할까? 앞의 예를 이용해서,
A == B
C == D
%% - % // Thread[#, Equal] &
이렇게? 안타깝게도 결과는 A - (C == D) == B - (C == D) 이다. 빼기가 두 번째 방정식의 양변에 적용되지 않아서 이런 결과가 나온다. 그러므로 양변을 더하기 전에 C == D의 양변에에 각각 -1을 곱해주어야 한다.
A == B
C == D
%% + (-1 # &) /@ % // Thread[#, Equal] & 

2010년 8월 2일 월요일

변수의 값 맞바꾸기

C++매스매티카, 파이썬에서 변수의 값을 맞바꾸는 코드를 비교해보자. C++은 아래와 같다. 표준적인 swap 함수의 형태를 보여준다.
template <T>
void swap(T &x, T &y)
{
    T tmp(x);
    x = y;
    y = tmp;
}
매스매티카에선 좀 더 간단하다. 목록을 만들어 교환해주면 된다.
{x, y} = {y, x}
파이썬은? 변수를 나열하면 자동으로 튜플을 만들어 주므로, 코드가 더 간단해진다.
x, y = y, x

2010년 7월 29일 목요일

구 표면 위의 벡터 필드 그리기

먼저 1 C(쿨롱)과 -1 C의 전하가 각기 (0,0,-1)과 (0,0,1)의 위치에 있을 때, 이들이 생성하는 전기장을 구해보자. 이들 두 전하가 만드는 포텐셜을 구하고, 이 포텐셜의 음의 기울기를 구하면 전기장을 알 수 있다.
φ[x, y, z] == 1/(4 π Subscript[ε, 0])
(1/Norm[{x, y, z} - {0, 0, -1}] - 
  1/Norm[{x, y, z} - {0, 0, 1}])
% // Simplify[#, x_ \[Element] Reals] &
% // Map[-HoldForm@Grad[#, Cartesian[x, y, z]] &, #] & // 
  ReplaceAll[#, -HoldForm@
       Grad[φ[x, y, z], Cartesian[x, y, z]] -> 
     OverVector[Ε]] & // ReleaseHold
eq1 = %;


편의를 위해, 공통 계수를 없애면 아래와 같은 벡터 필드 방정식을 얻을 수 있다.
4 π Subscript[ε, 0] eq1[[2]]
eq2 = %;

이 수식을 VectorPlot3D 함수를 이용해서 필드를 그리면, 직육면체 영역 안에서 전기장을 나타내는 벡터들을 보여준다.
eq2
% // VectorPlot3D[#, {x, -1, 1}, {y, -1, 1}, {z, -1, 1},
   VectorScale -> {Automatic, Automatic, None},
   VectorColorFunction -> "Rainbow"] &

이제 원점에서 1의 거리에 있는 전기장만을 그리려면, 즉 반지름이 1인 원의 표면 위에 있는 벡터만을 그리려면 어떻게 해야 할까? ‘델타함수의 그래프 그리기’에서 한 것처럼 기본 Plot 계열의 함수가 처리해 주지 못할 때엔 ListPlot 계열의 함수를 이용하는 방법을 생각해본다.
Table[{r, θ, ф}, {r, 1, 1}, {θ, 0, π, π/
    10}, {ф, 0, 2 π, π/10}] // Flatten[#, 2] &;
% // Map[CoordinatesToCartesian[#, Spherical] &, #] &;
% // Map[{#, (4 π Subscript[ε, 0]
          eq1[[2]] /. {x -> #[[1]], y -> #[[2]],
         z -> #[[3]]})} &, #] &;
% // ListVectorFieldPlot3D[#, Axes -> True,
   AxesLabel -> {"x", "y", "z"}, VectorHeads -> True,
   ScaleFunction -> (0.2 &)] &
이 복잡한 명령어들이 하는 일은 다음과 같다. 우선, 첫 번째 줄에서 구 좌표계를 이용해서 구 표면 위의 일정한 좌표를 얻는다. 두 번째 줄에선 우리가 가진 식이 직교 좌표계의 식이므로 구 좌표계의 좌표를 직교 좌표계의 좌표로 바꾼다. 세 번째 줄에선 좌표를 식에 대입해서 그래프를 그릴 자료를 생성한다. 네 번째 줄에서는 ListVectorFieldPlot3D를 이용해서 전기장의 그래프를 그린다.



버전 7.0에선 ListVectorFieldPlot3D보다 ListVectorPlot3D를 사용하길 권하지만, ListVectorPlot3D에 아직 문제가 있는 듯이 보인다.

2010년 7월 23일 금요일

델타함수 그래프 그리기

코사인 함수의 푸리에 변환은 두 델타함수의 합으로 나타난다. 하지만, 그래프로 그리면 델타함수의 피크를 볼 수 없다.
FourierTransform[Cos[1.1 t], t, ω]
% // Plot[#, {ω, -3, 3}] &


코사인 함수의 푸리에 변환으로 얻은 함수에는 그래프로 그리기 어려운 두 가지 이유가 있다. 먼저, 델타함수는 인자를 0으로 만드는 지점에서 무한대로 발산하므로 그래프로 표현하기 어렵다. 관례적으로, 델타함수를 그래프로 그릴 땐 발산 점에서 델타함수의 값을 1로 대체해서 그래프를 그린다. 즉, DiracDeltaDiscreteDelta로 치환하면 된다. 또한, 델타함수는 연속함수가 아니어서 Plot이 발산 점을 찾아내어 그려주지도 못하는데, 이 문제는 발산 점을 포함하는 목록을 만들어서 함수 자료에 발산 점이 꼭 들어가게 하여 해결한다.
FourierTransform[Cos[1.1 t], t, ω]
% /. DiracDelta[x_] :> DiscreteDelta[x]
% // Table[{ω, #}, {ω, -3, 3, 0.001}] & //
 ListPlot[#, Joined -> True] &
이번에도 그래프엔 아무것도 나타나지 않는다. 진법 변환 오차 때문에 발생하는 문제로, DiracDelta[1.1 - (1.099 + 0.011)]를 실행해보면 1이 아닌 0이 나오는 것을 알 수 있다. 컴퓨터는 1.100과 1.099+0.001을 다른 수로 본다. 십진수로 입력한 수는 일단 이진수로 바뀌는데, 십진수 실수 중에는 이진수로 변환했을 때 무한소수가 되는 수가 있다. 예를 들어, 1.100은 이진수로 표현하면 소수점 아래 두 번째부터 다섯 번째까지가 반복하는 무한소수가 된다.
BaseForm[1.100, 2]

컴퓨터는 저장공간의 제약으로 무한소수를 일정 자리에서 버림하여 저장하는데, 이때 입력받은 십진수와 저장된 이진수 사이에 차이가 발생하게 된다. Rationalize를 이용해서 모든 수를 정수로 표현하면 이러한 문제를 없앨 수 있다.
FourierTransform[Cos[1.1 t], t, ω]
% /. DiracDelta[x_] :> 
  Hold@DiscreteDelta@Rationalize@Unevaluated@x
% // Table[{x, # /. ω -> x}, {x, -3, 3, 0.001}] & //
  ReleaseHold // ListPlot[#, Joined -> True] &

2010년 7월 22일 목요일

그래프의 특정 부분을 강조하려면

그래프에서 특정 부분을 강조하려면 PrologEpilog 옵션을 이용한다. 예를 들어 코사인 그래프에서 π부터 2π까지의 영역을 강조하려면 다음과 같이 Prolog 옵션을 준다.
Plot[Cos[x], {x, 0, 10}, 
 Prolog ->; {Green, Opacity[0.1], 
  Rectangle[{\[Pi], -10}, {2 \[Pi], 10}]}]

Epilog를 이용하면 그래프를 가리게 되는데, 이때엔 Opacity 명령어로 투명도를 조절하면 숨겨진 그래프를 볼 수 있다. 이 방법은 Graphics로 표현되는 모든 그래프에서 사용할 수 있다.

2010년 7월 21일 수요일

GIST의 위도와 경도

구글 지도가 제공하는 OpenAPI인 구글 Geocoding API를 이용하면, GIST의 위도와 경도를 찾을 수 있다. 웹브라우저의 주소 입력 칸에 아래 주소를 넣으면, XML 형태의 위치 정보를 받을 수 있다.
http://maps.google.com/maps/api/geocode
/xml?address=GIST,+Oryong-dong+1,+Buk-gu,+Gwangju&
sensor=false
아래 결과를 보면, geometry 태그 아래에 위도와 경도 정보가 나와 있는 것을 알 수 있다.


구글 Static Maps API를 이용해서 우리가 얻은 위도와 경도 정보가 정확한지 확인해 볼 수 있다.
http://maps.google.com/maps/api
/staticmap?center=35.2278792,126.8415491&zoom=15&
markers=35.2278792,126.8415491&size=400 x400&sensor=false

이상의 과정을 매스매티카에서도 쉽게 재현해볼 수 있다. 먼저, XML 패키지를 읽어들인다.
<< XML`
구글 지도에서 위치 정보를 XML로 받아온다. 매스매티카는 웹브라우저와 달리 언어 정보를 보내지 않으므로, 결과를 한글로 받아오려면 언어 정보를 명시해줘야 한다.
gistXML =
 XMLGet["http://maps.google.com/maps/api/geocode
/xml?address=GIST,+Oryong-dong+1,+Buk-gu,+Gwangju&
language=ko&sensor=false"]
받아온 자료에서 위도와 경도 정보를 빼낸다.
latlng = ToExpression@
  Flatten@Cases[gistXML,
    XMLElement[
      "location", _, {XMLElement["lat", _, {lat_}],
       XMLElement["lng", _, {lng_}]}] -> {lat, lng}, Infinity]
이렇게 얻은 위도와 경도 정보를 지도로 확인해 볼 수 있다.
Block[{url, loc},
 loc = ToString /@ latlng /. {x_, y_} :> x <> "," <> y;
 url = "http://maps.google.com/maps/api/staticmap?center=" <> loc <>
   "&zoom=15&markers=" <> loc <> "&size=400x400&sensor=false";
 Import[url]
 ]
참고자료
  1. The Google Geocoding API
  2. Static Maps API V2 Developer Guide

    2010년 7월 20일 화요일

    이맥스의 파이썬 모드에서 주석처리

    이맥스의 파이썬 모드(M-x python-mode)를 사용하다 보면, 중요한 기능 하나가 메뉴에 없는 것을 알 수 있다. 바로 주석 처리 기능인데, 사실 메뉴에만 없지 이미 모든 프로그램 모드에서 제공하는 기능이다. 단축키는 M-; (‘coent-dwim’)이다.

    일정 부분을 주석 처리하려면, 주석처리를 시작할 부분에서 C-SPC-SPC로 Transient-mark-mode를 켜고 끝 부분까지 커서를 이동한다. 다음으로, M-;을 누르면 해당 구역이 주석 처리된다. 이미 주석 처리된 부분에서 이렇게 하면 주석이 해제된다.


    임의의 줄에서 M-;을 누르면 줄의 맨 끝에서 주석을 시작한다.

    정적분 입력 서식의 단축키

    매스매티카에서 정적분(definite integral)을 입력할 때, 단번에 입력 서식을 만들 수 있는 단축키를 제공한다. Esc+dintt+Esc를 입력하면, 다음과 같은 입력 서식이 생성된다.

    2010년 7월 12일 월요일

    파이썬 스크립트에 한글 넣기

    파이썬 스크립트에 한글을 쓰려면 아래와 같이 인코딩 설정을 해 주어야 한다. 코드 부분뿐만 아니라 주석 부분의 한글 입력에도 인코딩 설정이 필요하다. 인코딩 설정은 인터프리터 지시어 바로 다음 줄에 와야 한다.
    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    ...
    

    2010년 7월 8일 목요일

    템플릿 프로그래밍에서 복소수를 실수 또는 복소수형 변수에 대입

    템플릿으로 생성한 클래스에 적합한 변수형을 인자로 받아서 내부에 저장된 복소수 값을 이용하여 인자를 변경하는 상황을 가정해보자. 아래의 ClassA 클래스에 있는 update 메서드는 객체에 적합한 변수형을 인자로 받지만, 내부 계산은 복소수로 처리한다.
    #include 
    
    template 
    class ClassA
    {
    public:
        ClassA(): cmplx(0,0) {}
        void update(T& out) { out = cmplx; }
    private:
        std::complex cmplx;
    };
    
    문제는 복소수를 인자에 대입하는 부분에서 발생한다. out이 복소수형일 때엔 문제가 안 되지만, float이나 double과 같은 실수형이라면 형변환 에러가 발생한다. STLstd::complex 타입은 실수형으로의 변환 연산을 제공하지 않기 때문이다. 즉, std::comlex<double> 형으로 생성한 ClassA는 별문제가 없지만,
    ClassA<std::complex<double> > obj;
    std::complex<double> var;
    
    obj.update(var);
    
    double 형으로 생성한 ClassA
    ClassA obj;
    double var;
    
    obj.update(var);
    
    컴파일하면, 다음과 같은 에러가 발생한다.

    error: cannot convert ‘std::complex<double>’ to ‘double’ in assignment

    이 문제는 복소수형 변수를 실수형 변수로 변환해주는 함수를 만들어 해결한다. ClassA::cmplx의  실수부에 원하는 값이 저장되어 있다고 한다면, std::complex.real()의 반환값을 실수형 변수에 대입하면 된다.
    template <typename S, typename T>
    static inline T& assign(const std::complex<S>& in, T& out)
    {
        return out = static_cast<T>(in.real());
    }
    
    하지만 이 함수를 사용하면, 오히려 복소수형 변수를 복소수형 변수에 대입하는 경우가 문제가 된다. 따라서 복소수형에 대해서는 다음과 같이 부분 템플릿 특수화(partial template specialization)를 이용하여 실수부와 허수부끼리 대입해주어야 한다.
    template <typename S, typename T>
    static inline std::complex<T>& assign(const 
    std::complex<S>& in, std::complex<T>& out)
    {
        out.real(static_cast<T>(in.real()));
        out.imag(static_cast<T>(in.imag()));
    return out;
    }
    
    이제 update 함수는 아래와 같이 바꾸면 형변환 문제가 해결된다.
    ...
        void update(T& out) { assign(cmplx, out); }
    ...