diff --git a/README.md b/README.md index 99e223e258790c69d6fcc1e97229f9d635fb59ea..dca62b99d911b17ae3ba36d53f3e371c8688b733 100644 --- a/README.md +++ b/README.md @@ -527,3 +527,130 @@ int main() >>> * 같은 코드여도 함수의 call을 줄이거나 늘리면 시간 계산이 또 달라진다. >>> * 또한 오버플로우를 방지하기 위해 long long으로 a,b를 받아 곱하고 두 수의 곱을 int로 변환하여 받은 다음 gprof를 하여 시간계산 한 것을 확인하면 시간이 더 걸린 것을 볼 수 있다. >>> * 위와 같은 것들은 오차가 넓기 때문에 5번 이상 돌려서 통계를 내어 사용하는 것이 좋다. + + +## lesson 11 + +1. call by address 와 call by value +>* &a 와 같은 것을 Call by address라 한다. (= call by reference) +>* c언어에서 기본은 automatic 으로 선언된다. +>* call by address는 주소값(*a)으로 가져오며 main에서 가져온 것과 같은 주소를 가진다. (즉, 연동되어 있다.) 따라서 이때 함수실행시 바뀐 값들은 main에서도 바뀌게 된다. +>* call by value는 변수값(a)으로 가져오며 main에서 가져온 것과 다른 주소를 사용하고 있게 된다. +>> 즉, 아예 다른 공간에서 동작하다가 함수 종료시 공간이 사라지게 되어 함수 실행시 변했던 값이 main에서도 바뀌지는 않는다. +* 함수 호출시 생기는 공간은 딱 맞춰 생성하는 것이 아니라 넉넉히 생성을 시킨다. + +2. gprof 관련 +>* $gprof를 쓰지 않으면 기본으로 a.out과 gmon을 비교해서 보여준다. +>* $gprof -A : 소스코드 함수에 Annitation을 달아준다. +>* $gprof -b : 간단하게 보게해주는 명령어이다. + +3. optimization 관련 +>* 사용하는 cpu에 따라서 optimization을 하여 어떤 type(int, long long, short, ...)으로 코드를 짜야 성능이 제일 좋은지 골라야 한다. +>* optimization은 꼭 필요할 때만 하는 것이 좋다. + +4. 프로젝트(고정소수점) 관련 +>* 맨앞의 비트는 signed 와 unsigned를 구분 하는 비트로 signed=1 이고, unsigned=2 이다. +> 1. (RGB로 보는 예) 4byte(unsigned int) 인 색을 나타내는 비트들에 대하여 +>> * red(8bit) green(8bit) blue(8bit) a(8bit) 가 있다고 하자. +>> * 각각은 총 256개의 색을 (0~255) 나타낼 수 있으므로 총 256^3 개의 색상을 나타낼 수 있다. +>> * 0 = 0.0 , 255= = 1.0 으로 나타내므로 중간의 x번째는 x/255 로 표현한다. +> * 아래는 RGB 색상을 비트로 나타내는 코드이다. +```C +#include <stdio.h> + +typedef unsigned int t_rgba; +#define fromRGBA(r,g,b,a) ((((r)&0xff)<<24)|(((g)&0xff)<<16)|(((b)&0xff)<<8)|((a)&0xff)); + +#define F_NUM_1_255 (1.0f/255.0f) + +t_rgba mul_float(t_rgba c1, t_rgba c2) +{ + float r1,g1,b1,a1; + float r2,g2,b2,a2; + int ir,ig,ib,ia; + r1 = (float) ((c1 >> 24) ) * F_NUM_1_255; + g1 = (float) ((c1 >> 16) & 0xff) * F_NUM_1_255; + b1 = (float) ((c1 >> 8) & 0xff) * F_NUM_1_255; + a1 = (float) ((c1 ) & 0xff) * F_NUM_1_255; + + r2 = (float) ((c2 >> 24) ) * F_NUM_1_255; + g2 = (float) ((c2 >> 16) & 0xff) * F_NUM_1_255; + b2 = (float) ((c2 >> 8) & 0xff) * F_NUM_1_255; + a2 = (float) ((c2 ) & 0xff) * F_NUM_1_255; + + ir = (int) ((r1 * r2) * 255.0f); + ig = (int) ((g1 * g2) * 255.0f); + ib = (int) ((b1 * b2) * 255.0f); + ia = (int) ((a1 * a2) * 255.0f); + + return fromRGBA(ir,ig,ib,ia); +} + +t_rgba mul_int(t_rgba c1, t_rgba c2) +{ + unsigned int r1,g1,b1,a1; + unsigned int r2,g2,b2,a2; + int r,g,b,a; + r1 = c1 >> 24 ; r2 = c2 >> 24; + g1 = (c1 >> 16) & 0xff ; g2 = (c2 >> 16) & 0xff; + b1 = (c1 >> 8) & 0xff ; b2 = (c2 >> 8) & 0xff; + a1 = c1 & 0xff ; a2 = c2 & 0xff; + r = (r1*r2) >> 8; + g = (g1*g2) >> 8; + b = (b1*b2) >> 8; + a = (a1*a2) >> 8; + return fromRGBA(r,g,b,a); +} + +//unsigned int fromRGBA(int r, int g, int b, int a) +//{ + // return r*256*256*256 + g*256*256 + b*256 + a; + //return ((r<<24) + (g<<16) + (b<<8) + a); +// return (((r&0xff)<<24) | ((g&0xff)<<16) | ((b&0xff)<<8) | (a&0xff)); +//} + +int main() +{ + int red, green, blue, alpha; + t_rgba rgba_1, rgba_2; + // input value must be in 0~255 : 0.0 ~ 1.0 으로 해석 + // rgba_1 [rrrrrrrr][gggggggg][bbbbbbbb][aaaaaaaa] + printf("Input 4 values with 0~255 "); + scanf("%d %d %d %d", &red, &green, &blue, &alpha); + rgba_1 = fromRGBA(red, green, blue, alpha); + printf("%d %d %d %d : %u 0x%8x\n", red,green,blue,alpha,rgba_1,rgba_1); + rgba_2 = mul_float(rgba_1, rgba_1); + printf("%d %d %d %d : %u 0x%8x\n", red,green,blue,alpha,rgba_2,rgba_2); +} +``` +* 위의 코드에서 rgba 에 대한 비트를 16진수로 [rrrrrrrr][gggggggg][bbbbbbbb][aaaaaaaa]형태로 짰다. +* 또한 처음에는 fromRGBA함수를 짰지만 성능상 define을 이용할 수 있다면 이용하는 것이 더 좋으므로 + +* #define fromRGBA(r,g,b,a) ((((r)&0xff)<<24)|(((g)&0xff)<<16)|(((b)&0xff)<<8)|((a)&0xff)); 로 정의 하였다. +>* 위에서 | 대신 +를 사용하여도 되지만 + 기호는 shift보다 우선순위가 높으므로 괄호를 잘 사용하여야만 한다!!! +>* 또한 r, g, b, a모두에 괄호를 사용하여 (r),(g),(b),(a)로 나타내었는데 이렇게 메크로엔 괄호를 하는 이유는 #define사용시에는 문자그대로 전달되기 때문에 r+2와 같은 값을 받아 들일때에 r+2&0xff 가 되어 계산이 꼬이는 경우가 생기기 쉽기 때문이다. + +* 또한 조건문은 성능을 나빠지게 하므로 위의 코드에서 0~255사이 범위를 넘어가는 input을 받았을 때 처리해 주는 과정을 if문을 사용하지 않고 &0xff를 하여 처리해 주었다. +>> * 위에서의 "&" (and operation)은 각 자리수를 & 연산 한 것과 같다. (즉 0&0=0 1&0=0 0&1=0 1&1=1) +>> * 따라서 r,g,b,a에 각각 &0xff를 하면 r,g,b,a의 input 값과 0xff를 비교하여 둘 다 1인것만 1로 반환하므로 범위를 넘어가는 input은 모두 0으로 반환하여 잘 처리 할 수 있다. + +* 위에서 fromRGBA를 정의한 것을 다시 살펴보면 +> * 범위 처리를 위하여 각각의 r,g,b,a에 0xff 를 and operation 해주어 0~255범위가 넘어가는 것을 방지하고 +> * 각각의 비트 위치에 따라 24번째 자리 부터 시작하는 red는 24번 왼쪽 shift 를 하였고(***왼쪽 shift 한번은 곱하기 2와 같다.) +> * green은 16번째 자리부터 시작하므로 16번 왼쪽 shift를 하였고 +> * blue는 8번째 자리부터 시작하므로 8번 왼쪽 shift를 하여 자리수를 맞추어 주었다. +> * 마지막으로 a는 0~7번째 자리를 차지하는 비트이므로 0xff와 and operation만을 해주었다. + +(cf) +* 16진수로 1자리는 2진수로 4자리 이다. +>> 16진수로 2자리는 2진수로 8자리 +* 왼쪽 shift n이 곱하기 2^n 과 같듯이 오른쪽 shift는 나누기 2^n 의 몫과 같다. +* 보통은 역수를 구해야 하는 나누기가 곱하기보다 4배 정도 느리므로 나누기를 먼저 #define을 통해 곱하기로 처리하는게 성능에 더 좋다. + +mul_float 코드 +* 위의 mul_float는 두 개의 rgb를 나타내는 bit의 곱을 연산하는 코드이다. +* 먼저 두 rgb값의 각각의 r,g,b,a는 오른쪽 shift를 통해서 r, g, b, a로 각각을 나누어 준다. +* 그 다음 255로 나누어 (255번째 bit 가 1이므로) 각각의 r,g,b,a 로 쪼갠것에 대해 r1*r2, g1*g2, b1*b2, a1*a2 를 해준다. +* 그리고는 다시 255를 곱해주고 int로 변환하여 두 rgb의 곱한 rgb값을 return 하는 형태이다. + +