. 미리 계산된 값

앞의 실습에서 폰트의 폭을 미리 계산해 둠으로써 많은 속도상의 이득을 보았는데 이 기법은 아주 일반적이고 쉬운 최적화 기법 중의 하나이다. 미리 구해놓을 수 있는 값을 배열로 작성함으로써 공간을 좀 더 소모하는 대신 속도가 증가되었는데 이 기법은 다음의 간단한 명제에 기초한다.

 

코드의 크기와 속도는 반비례한다.

 

이 명제는 제품의 품질과 저렴도의 관계에 비유될 수 있는데 제품의 품질은 저렴도와 반비례 관계에 있으며 더 쉽게 표현하자면 제품의 품질과 가격은 비례한다. 싼 게 비지떡이고 비싼 가격을 치르면 품질이 좋다는 것은 경제의 기본 원리를 아는 사람이라면 누구나 이해할 수 있는 이론이다. 그렇다면 이 법칙이 모든 제품에 대해 항상 성립한다고 할 수 있을까?

시장에 나와 있는 제품들을 보면 가격이 비싸면서 품질이 좋은 것들과 싸지만 품질이 좀 떨어지는 것들로 크게 양분되고 소비자들은 자신의 주머니 사정에 따라 품질 또는 저렴한 가격 중 하나를 선택하게 된다. 그래서 두 부류의 제품은 항상 시장에 사이 좋게 존재하게 되며 이 제품들간에는 반비례 법칙이 분명히 성립된다.

만약 가격은 비싼데 품질이 별로 좋지 못한 제품이 있다면 이 제품은 소비자들에게 외면당하게 되고 얼마 후 시장에서 사라지게 될 것이다. 품질이 떨어지면 가격이라도 저렴하거나 아니면 비싼 대신 품질이라도 좋아야 하는데 법칙을 어겼기 때문에 생존할 수 없다. 반면 가격도 싸면서 품질도 좋은 제품이 개발 되었다면 이런 제품을 혁신(Innovation)이라고 한다. 기술상의 혁신이 발생하면 시장에는 일대의 변화가 유발되는데 혁신 제품보다 동일한 품질의 더 비싼 제품과 동일한 가격의 저품질 제품은 제고 정리나 반값 세일로 처분되어 사라질 것이다.

결국 시장에서 품질과 저렴도의 반비례 관계는 거의 유지되며 이 법칙을 벗어난 제품들은 일시적으로만 시장에 존재할 수 있을 뿐이다. 따라서 이 법칙은 모든 제품에 대해 항상 성립한다고 할 수 있다. 물론 이것은 어디까지나 품질과 가격의 관계만을 규정하는 법칙이며 브랜드 가치나 개인의 특수한 기호 등은 배제한 것이다. 품질과 저렴도의 반비례 법칙은 실존하는 법칙이며 우리들은 이 법칙을 무의식적으로 깨닫고 있고 우리의 소비 생활은 알게 모르게 이 법칙의 지배를 받고 있는 것이다.

코드에 대한 크기와 속도의 반비례 관계도 동일한 이치대로 항상 성립한다. 만약 메모리는 많이 소모하면서 느린 알고리즘이 있다면 이 알고리즘은 아무도 사용하지 않을 것이며 자연 도태되어 역사 속으로 사라질 것이다. 반면 메모리 소모도 작고 속도도 빠른 새로운 기술이 개발되었다면 이 기술은 혁신이라고 불려지며 기존의 다른 알고리즘을 빠른 속도로 대체해 나간다. 결국 존재하는 모든 알고리즘은 작고 느리거나 아니면 크고 빠르거나 두 부류 중 하나에 속하게 된다. 물론 이 법칙도 유지 보수의 편의성이나 개발 기간 등은 고려되지 않고 단순히 속도와 크기만의 관계를 규정할 뿐이다.

속도(Speed)와 코드의 크기(Size)를 규정하는 이 일반적인 법칙을 이해한다면 보통의 지혜로운 개발자는 상황에 따라 둘 중 하나를 선택할 수 있다. , 속도를 빠르게 하고 싶으면 메모리를 좀 더 쓰면 되고 프로그램의 크기를 줄이고 싶다면 속도를 조금 희생하면 된다는 것이다. 여기서 보통의 지혜로운 개발자라는 단서를 분명히 달았다. 지혜롭지 못한 개발자는 이 법칙과 상관없이 원래부터 크고 느린 코드를 쓰고 있기 때문에 이 법칙을 적용할 자격이 안되며 보통 수준을 넘는 탁월한 개발자는 스스로 혁신을 창조하기 때문에 역시 이 법칙의 적용을 받지 않는다.

그렇다면 이 예제에서 사용한 최적화 기법과 비슷한 예를 한 가지 들어 보자. 만약 삼각함수 사인(Sine)값을 코드의 곳곳에서 사용하는 프로그램을 작성하고 있다고 하자. 사인값은 sin 런타임 함수로 구하는데 알다시피 실수 연산은 굉장히 느려 프로그램의 속도를 저하시키는 주범이다. 프로그램을 작성해 본 결과 속도가 너무 느리다면 메모리를 좀 더 쓸 각오를 하고 다음과 같은 함수를 작성한다.

 

double arSine[91];

void PrepareSine()

{

     int r;

 

     for (r=0;r<=90;r++) {

          arSine[r]=sin(r*3.14/180);

     }

}

 

arSine 배열을 미리 선언하고 이 배열에 0~90도까지의 사인값을 미리 구해놓았다. 이후부터는 sin 함수를 쓰는 대신 이 배열과 각도값을 첨자로 쓰면 신속하게 사인값을 구할 수 있다. 속도 향상을 위해 728바이트를 더 사용한 결과 대충 5배 정도 속도가 빨라지는 것을 확인할 수 있다. ApiEdit arChWidth 배열을 도입한 것은 이 법칙을 적용한 예라 할 수 있다.