2022.02.14 - memcpy() 계열 최적화? 1년 반 쯤 전에 쓴 글에서 memcpy() 계열을 굳이 더 최적화할 필요가 없다는 글을 썼었다. 그런데, 스택 오버플로우에서 재미있는 글타래(faster alternative to memcpy?)를 발견했다. 댓글들의 요지는 AVX2 레지스터를 활용하면 더 빠른 복사를 할 수 있고, 이를 병렬수행하면 더 효과가 높아진다는 것. 전자의 경우 기존의 memcpy()에서도 활용할 것 같지만, 후자는 효과가 있을지 여부가 좀 궁금해졌다. 메모리 대역폭이 명령어 실행 사이클보다 충분히 크다면 효과가 없지는 않을 것 같았다. 위 글의 코드들을 대폭 참조한 코드를 만들어 돌려봤다. 코드의 구성들은 대략 아래와 같았고, 동작환경은 AMD Ryzen 9 5900X,..
파이썬은 굉장히 파워풀한 언어다. 특히 Numpy와 Pandas를 활용하면 기존 언어에선 어렵게 처리할 문제를 손쉽게 해결할 수 있다. 하지만, 파이썬의 특성상 멀티코어를 활용하거나 SIMD를 자유롭게 활용하기 어렵다. 그래서 C/C++로 dll을 만들어 파이썬에서 이를 불러 사용하는 방식을 종종 사용한다. 파이썬(Numpy)은 기본적으로 배열을 C언어와 동일한 순서로 저장한다. 하지만 연산을 처리하는 과정에서 더 효율적이라 판단되면 이 저장 순서를 바꿔버린다. 대표적으로 볼 수 있는 것은 전치행렬. 이렇게 저장된 데이터를 그대로 C/C++에서 접근하면 기대와 전혀 다른 동작을 하게 된다. 일단 아래와 같이 입력해서 2×3 크기의 int 배열(행렬)을 만들어보자. >>> a = np.array([[1,2..
C/C++를 포함한 거의 대부분의 언어에서는 부동소수점의 제곱근 함수를 지원하고 있다. 그리고, 정수 범위에서 제곱근을 구할 때는 보통 이 제곱근 함수를 활용하여 간단히 구현한다. 그런데, 순수하게 정수 범위에서 동작하는 제곱근 함수가 있다면 조금은 더 빠르게 동작할 것 같다. 파이썬의 경우 아예 이러한 함수를 stdlib에서 지원한다. 정수 범위에서 제곱근을 구하는 아이디어에는 몇 가지 방식이 있다. 1. 뉴턴의 근사법 활용 unsigned ISqrtByNewton32(const unsigned n) { unsigned x = n; unsigned y = (x + 1) / 2; while (y < x) { x = y; y = (x + n / x) / 2; } return x; } 2. 곱하기 연산 없이..
주어진 수보다 크거나 같은 최소의 2의 제곱수를 찾아야 될 경우가 있다. 대표적으로 FFT를 기반으로 하는 신호처리의 준비단계. 적절한 개수를 지정해놓고 DFT를 할 수도 있지만, 역시 미친듯한 속도를 내려면 2의 제곱수가 짱짱맨이다. 사실, 요즘 컴퓨팅 환경에서는 이를 위한 가장 빠른 방법[...] 따윈 알아볼 의미가 크게는 없다. x86/x64 환경이라면 어셈블리 단위에서 LZCNT(Count Leading Zeros) 명령을 지원하기 때문이다. Visual C++라면 __lzcnt64() 등의 함수로, GCC라면 __builtin_ia32_lzcnt_u64() 등의 함수로 사용할 수 있다. 하지만, 세상은 언제나 그렇게 만만하진 않은 법. 파이썬이나 매틀랩 같은 언어에서는 이런 계열의 함수를 지원하..
C++의 자료 구조 중에 map이라는 것이 있다. key와 value를 한 쌍으로 저장하며, key의 중복을 허용하지 않고 정렬하여 저장하는 자료구조이다. 아는 사람은 다 아는 내용이니 map에 대한 설명은 여기까지만 하고... MFC에서는 이러한 경우를 처리하기 위해 CMap이라는 클래스를 만들어두었다. 또한 STL에서는 map과 unordered_map을 구현하여 유사한 기능을 수행하게 해두었다. 여기서 Windows 환경에서 어느 쪽의 구현이 더 빠른가 하는 점이 궁금해졌다. 그런데, 구글링을 해보니 이미 거의 답이 나와있었다. Does MFC CMap have a good performance compared to std::unordered_map or std::map MFC의 CMap 쪽이 근소..
정리 차원에서 간단히 기록... 유닉스/리눅스와 윈도우는 근본적으로 다른 점들이 꽤 있다. 그 중 하나가 시간을 계산하는 기준. 유닉스/리눅스의 Epoch time은 1970년 1월 1일 00:00:00GMT부터 누적된 시간(초)이다. 윈도우 환경에서도 이 Epoch time을 읽는 함수가 있다. 밀리초 이하의 단위를 사용하지 않고, 단순하게 초 단위에서만 계산하려면 아래와 같이 사용하면 된다. #include #include #ifdef _MSC_VER #include #elif __GNUC__ #include #include #endif int main() { #ifdef _MSC_VER time_t ltime; time(<ime); unsigned long long ullEpoch = (unsi..
프로그램을 하나 만들면서 최초 실행부터 난수를 생성하도록 할 일이 생겼다. 당연히도 수많은 강좌에서 사용하라고 강요(?)하는 방식으로 시작했다. srand((unsigned)(time(NULL))); int r = rand(); 물론 프로그램은 정상적으로(?) 동작했고, 특별한 문제는 없었다. 단지 생성된 난수가 너무 규칙적이란 부분 하나만 빼면... C/C++언어에 포함된 rand() 함수가 그다지 품질도 좋지 않고, 속도도 빠르지 않다는 얘긴 많았다. MT(메르센 트위스터)나 WELL을 사용하란 글도 쉽게 찾을 수 있다. 그래도 개인 용도로 사용할 때는 간단하고 편하게 쓸 수 있는 rand()를 사용해왔다. 낌새가 이상해서 VS2022에서 프로그램 하나를 간단히 만들어 돌려봤다. #include #i..
깃헙 zlib-ng 라이브러리에 아래와 같은 내용이 반영된 수정이 올라왔다. unaligned access를 허용하지 않는 환경에서는 memcpy(), memcmp()를 사용하고, 허용된다면 직접 비교한다는 것. /* Force compiler to emit unaligned memory accesses if unaligned access is supported on the architecture, otherwise don't assume unaligned access is supported. Older compilers don't optimize memcpy and memcmp calls to unaligned access instructions when it is supported on the arc..
프로젝트 오일러의 71~73번 문제는 비슷하게 생겼는데, 실제로는 서로 상당히 다른 문제들이다. 서로 비교해보면 많은 생각을 하게 하는 문제들이다. 71번 주어진 범위의 기약분수 중에서 \( \frac {3}{7} \)보다 작으면서 가장 큰 분수의 분자를 찾는 문제다. 주어진 범위가 무려 백만까지므로 무식하게 보면 백만(Mega)×백만=1Tera번 루프를 돌리면 답을 찾을 수 있다. 하지만, 조금만 생각해보면 각 분모별로 \( \frac {3}{7} \)에 가까운 기약분수 하나씩만 비교해보면 된다. 간단하게 만들어보면 아래와 같다. 최대공약수 코드는 앞 포스팅의 코드를 활용. #include #include #include size_t GCDfast(size_t x, size_t y) { if (!x |..
학교 수학 시간에 안 가르치는 것 같은데, 최대공약수를 구하는 알고리즘이 유클리드 호제법이다. 인류 최초의 알고리즘이라고도 알려져있기도 하다. 개념은 단순하다. 서로를 나누어 나머지를 계속 구하는 것. 좀 더 원시적(?)으로 구현하려면 나머지(나누기) 대신 빼기로 구현해도 된다. 보통은 아래와 같은 코드를 사용한다. size_t GCD(size_t x, size_t y) { while (y) { x %= y; if (!x) { return y; } y %= x; } return x; } 그런데, 조금 뒤져보니 Binary GCD라는 알고리즘이 있다. 짝수인 경우 2로 계속 나누어 나눈 횟수를 미리 세어둔 뒤 유클리드 호제법을 사용하는 방식이다. 이 알고리즘은 CPU 명령을 활용하는 _BitScanForw..
앞의 문제와 유사하지만, 한 번 더 꼬아 난이도가 살짝 올라간 문제. 사실, 이 문제를 풀기 위해 좀 더 공부를 하고 앞의 포스팅을 수정했다. \( \phi (n) \) 함수를 오일러가 정리한 대로 제대로 구현하지 않아도 앞의 문제는 풀 수 있었지만, 이 문제는 아니다. 일단 천만이라는 수도 무시무시한데다, 그 뒤에 \( n \)과 \( \phi (n) \)이 순열인지 여부까지 확인해야 된다. 코드의 기본은 앞의 내용을 (대폭 수정한 뒤에) 거의 그대로 가져왔다. 에라토스테네스의 체를 활용해서 소인수 테이블을 먼저 만드는 것도 동일하다. 순열(permutation) 여부를 확인하는 코드와 아주 약간 바뀐 규칙 외엔 거의 동일하다. #include #include using namespace std; #i..
그간 도저히 포스팅할 시간이 나지 않았다. 정말이지 오랜만의 포스팅. 오랜만에 오일러 프로젝트를 하나 풀어봤다. 오일러의 \( \phi(n) \) 함수는 주어진 숫자보다 작은 수 중에 서로소인 수의 개수이다. 수학 쪽 분들께는 아래와 같이 정의될 수 있다고 한다. \( \phi(n) = n {\prod _{p|n}^{}} \left (1- \frac{1}{p} \right ) \) 그리고, 저 정의를 활용하면 \( n / \phi(n) \)가 최대가 되는 경우를 좀 더 손쉽게 알 수 있다고 한다. 그런데, 저 식을 제대로 이해하지 못하면서 코드를 만들고 싶지는 않아서 그냥 정공법으로 풀어보기로 했다. 첫번째 시도 모든 것을 무식하게 돌려보기로 했다. 백만 이하의 모든 수 각각에 대해 그 이하의 모든 수들..
대부분의 컴퓨터 언어에서 16진수 문자열을 숫자로 변환해주는 HEX2DEC() 함수를 지원한다. 엑셀이나 매틀랩 등은 물론이고, PHP에서도 지원된다. 윈도우10에 내장된 계산기에선 더욱 손쉽게 이를 처리해준다. 그런데, 막상 C언어에서 이를 사용하려면 아주 쉽게는 되지 않는다. 기능이 없는 것은 아닌데, 위에서 언급한 언어/환경에 비해선 뭔가 손이 좀 더 간다. 1. sscanf() 물론, C언어의 표준 함수인 sscanf() 함수로 이를 처리할 수 있다. 깔끔하게 처리가 가능하다. char hex_text[] = "1A2B"; int val; sscanf(hex_text, "%X", &val); printf("%d\n", val); 2. 직접 작성-1 그런데, 여러가지 이유로 직접 이 기능을 구현해야..
나머지는 산술에서 두 정수의 나눗셈 이후, 온전한 정수 몫으로 표현할 수 없이 남은 양을 가리킨다. 선형 등식의 일반적인 형태는 \( a=q\times d+r\)로 표현할 수 있다. 이 등식에서 \( 0 \leq r < d \)이면 \( q\)는 몫이고 \(r\)은 나머지이다. 0과 자연수 범위에서의 나누기와 나머지는 단순하다. 굳이 엄밀한 정의를 얘기를 하지 않아도 직관적으로 알 수 있다. 그런데, 음수의 영역에 들어가면 얘기가 달라진다. -5를 3으로 나누었을 때 나머지는 얼마가 되어야 되는 걸까? -2가 맞을까? 아니면 1이 되어야 되는 걸까? 직관적으로 보면 -2가 맞을 것 같지만, 정의에 따르면 1이 되어야 한다. 음수로 나누는 것을 생각하면 더욱 복잡해진다. 5를 -3으로 나누었을 때 나머지는..
풀어보는 김에 오일러 프로젝트를 하나 더 풀어보기로 했다. 이전 문제랑 비슷해보이지만, 실은 훨씬 간결한 문제다. 문제에서 자연대수 e의 연분수 전개를 설명해줬고, 특정 자리까지 계산했을 때의 수렴값만 계산하면 된다. \( a + \frac {1}{ \frac {c} {b} } = \frac {a c + b} {c} \)를 반복해서 계산하기만 하면 된다는 뜻임. 이걸 C++ 코드로 작성하면 아래와 같다. void ConvFraction(const unsigned a, const unsigned b, const unsigned c, unsigned& bN, unsigned& cN) { if (!b) { bN = 1; cN = a; } else { bN = c; cN = a * c + b; } } 이걸 반복..
오랜만에 풀어보는 오일러 프로젝트 하나. 제곱근을 연분수로 전개하면 나오는 값은 순환하게 되는데, 이 값이 홀수 개인 경우를 찾는 문제다. 이 문제는 프로그래밍 난이도 보다는 수학적인 의미를 이해하는 쪽이 더 어려운 문제. \( \frac { denom } { \sqrt {N} - minuend } \) 형태의 항의 다음 항을 계산하는 식만 찾으면 다음은 간단하다. \( \frac {denom} { \sqrt {N} - minuend } = \frac {denom ( \sqrt{N} + minuend ) } { N - minuend ^ 2 } = \frac { \sqrt {N} + minuend } {(N - minuend ^ 2) / denom} \)가 되는데, 이 식의 정수해가 다음 항이 된다. 즉,..
들어가기에 앞서... Endianness 라는 개념이 있다. 보통 Big-endian과 Little-endian 두 가지가 있는데, 메모리에 여러 바이트 연속된 자료가 저장되는 순서를 말한다. 다른 표현으로는 바이트 오더(Byte Order)라고도 한다. Cortex-M4에서의 Endianness // Reverses the byte order in unsigned integer value. // For example, 0x12345678 becomes 0x78563412. __STATIC_FORCEINLINE uint32_t __REV(uint32_t value) { #if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) return __builti..
짧고 간결한 프로젝트 오일러 문제 하나. 제목에서도 적었듯이 n제곱 해서 나온 숫자의 자릿수가 n인 모든 경우를 묻는 것이다. 다른 문제도 그렇지만, 이 문제는 일일이 제곱을 해가며 풀 수도 있다. 제곱의 결과가 64비트 범위를 넘어설 수도 있으니 이 부분을 해결할 아이디어만 있으면 된다. 하지만 그런 무식한(?) 방법보다는 로그를 활용하는 것이 훨씬 더 좋다. 일단 10진수 D의 자릿수가 n이라는 건 \(n-1 \leq log _{10} D \lt n\) 이라고 쓸 수 있다. 또한, 문제의 특성상 지수의 밑은 오로지 1~9 까지만 가능하다. 다시 말해서 \(1 \leq d \leq 9\) 인 자연수 d에 대해서 \(n-1 \leq log _{10} d ^ {n} \lt n\) 인 자연수 n의 개수를 세..
앞 포스팅에서도 짧게 언급했는데, 소수 여부를 판별하는 가장 빠른 방법은 에라토스테네스의 체다. 수의 범위가 정해져있다면 그 범위까지의 소수를 모두 식별하는데 이것보다 빠른 방법은 없다. 하지만, 반대로 이 방식은 임의의 한 수가 소수인지 식별할 때는 오히려 느린 편이다. 일일이 숫자를 나눠서 확인하는 경우 더 빠른 방법이 어느쪽인지 테스트해봤다. 테스트 환경은 그냥 개인용 PC(AMD Ryzen 5 3600X)인데, 다른 환경이라고 큰 차이는 없을 듯. 0. 에라토스테네스의 체 그냥 지나치긴 뭐해서 일단은 간단히 구현해봤다. bool IsPrime_0(unsigned num) { switch (num) { case 0: case 1: case 9: return false; case 2: case 3: ..
간만에 풀어보는 프로젝트 오일러. 이 문제는 복잡하게 생각하지 않아도 된다. 간단한 규칙만 찾으면 된다. 오히려 진짜 문제는 소수의 판별을 빠르게 하는 방법을 찾는 것. 에라토스테네스의 체를 활용하기 힘든 문제라 오히려 이 쪽이 성능에 영향을 미칠 수 있다. 1. 소수 식별 앞에서도 썼듯이, 소수를 식별하는 방법 중 에라토스테네스의 체보다 더 빠른 방식은 없다. 충분한 메모리만 확보할 수 있으면 이 방법이 최고다. 하지만, 이 문제에선 왠지 이 방식을 쓰는 게 어색하다. 대체 얼마만큼의 메모리를 확보해야 하는지를 알 수 없기 때문이다. 그래서 여기선 정공법을 선택했다. 정공법으로 풀 때 나누어지는지의 여부는 3 ~ \(\sqrt {n}\)까지만 확인하면 된다. 정수 범위에서 제곱근을 빠르게 구하는 방법은..
앞 포스팅들을 다시 읽어보니 뭔가 마무리가 되지 않은 느낌이 들었다. pow() 함수가 없기 때문인 것 같아서 이것까지 마저 만들기로 했다. 이미 ln()과 exp() 함수가 있기 때문에 구현 자체는 어려운 게 없다. 아래 적힌 관계만 이용하면 된다. 여기서 유의해야 될 점은 몇 가지 예외조건이 있다는 것이다. 이런 점을 고려한 코드는 아래와 같다. double EXP(const double x, const double limit) { double result = 1 + x; double x0 = x; int count = 1; while (true) { ++count; x0 = x0 * x / count; if (isinf(x0)) { break; } result += x0; if (fabs(x0) <..
이전 블로그에서 적었듯, ln()을 구현한 김에 sin()도 함께 구현해봤고, 원주율 계산도 간단하게 구현해봤다. 1. sin(x)의 구현 물론, 이번에도 테일러 급수다. sin(x)는 아래와 같이 전개된다. 이번에도 역시 구현 자체는 그리 어렵지 않지만 적절한 횟수를 정하는 것이 필요하다. const static double PI = 3.141592653589796323846; void SIN_v1(double x, double limit, double& result, int& count) { result = 0; count = 0; while (x > 2 * PI) { x -= 2 * PI; } while (x < 0) { x += 2 * PI; } double xxxx = x * x * x * x;..
2020/03/19 - 온도 센서의 출력 저항값으로 원래 온도값 계산 삽질기 이전 포스팅에서 로그와 간단한 식을 이용해서 센서 데이터를 처리하는 방식들을 얘기했다. 그런데, 새로운 문제가 제기되었다. 구현하는 환경에서 log() 함수가 지원되지 않으면 어떻게 하지? 쿼드코어 CPU가 발길에 채이는 세상이지만, 놀랍게도 이런 문제는 상존한다. 예컨데, Cortex 시리즈의 경우 M0는 물론 M3까지도 HW 부동소수점 기능이 제공되지 않는다. 1. 로그(ln(x))의 구현 방안 로그의 계산은 당연하게도(!) 테일러 급수에서 시작된다. 자연로그는 아래 두 가지 형태로 기술된다. 뭔가 좀 복잡해보이니 간단하게(?) 전개하면 아래와 같다. 그런데, 이 두 식은 조금만 생각해보면 홀수차 항만 남기도록 정리가 가능하..
부동소수점 값이 정상 범위가 아닌지 확인하는 것은 은근히 손이 가고 신경이 쓰이는 작업이다. NaN과 Infinite를 구분해야 하는 분야도 있지만, 사실 대부분의 경우에선 구분할 필요까진 없는데, 내장 함수들은 이를 구분하게 되어있다. C++ 11에 와서야 isfinite() 함수가 추가되어 편하게 쓸 수 있는 수준이 되었지만, 그 전까진 뭔가 2% 부족한 느낌이었다. isnormal()은 0도 false를 리턴하는 기염을 토했으며, isnan()과 ininf()를 따로 확인해야 했었다. C#은 아직 isfinite()에 해당하는 함수가 없어서 이런 얘기 자체가 사치스럽게(?) 들리는 상황이다. 그런데, 값이 정상 범위인지를 확인하는 것은 의외로 간단하다. 이는 부동소수점의 구조를 보면 쉽게 이해할 수..
오랜만에 머리도 식힐(?) 겸 프로젝트 오일러를 하나 풀어봤다. 문제의 골자는 세제곱수 중에 순열을 이루는 것이 다섯 개 있는 것을 찾아내는 것. 이 문제는 사실 unsigned long long을 사용하면 그닥 어렵지 않게 만들 수 있다. 몇 가지 포인트만 잡으면 꽤 빠르게 동작하는 프로그램을 만들 수 있다. 1. 모든 자릿수의 모든 숫자를 대상으로 계산하면 너무 복잡해짐 2. 세제곱수의 자릿수를 결정한 뒤 그 범위에 해당되는 세제곱근들만 계산 #include #include #include using namespace std; bool ArePermutated(unsigned long long b1, unsigned long long b2) { int cnt[10]; memset(cnt, 0, siz..
잘 알려져있다시피 컴퓨터에서 이미지 및 동영상을 저장할 때는 RGB 그대로 저장하는 것보다 YCbCr로 변환해서 저장하는 것이 일반적이다. RGB는 특성상 중복되는 값이 많이 들어가며, 이러한 중복을 최소화하기 위해 변환 및 서브샘플링을 하는 것이다. 그런데, YCbCr 또는 YUV의 표기법을 읽다보면 헷갈리는 경우가 많다. YCbCr, YUV, Y'CbCr, YPbPr 등등… 일단, 간단히 이 용어들을 정리해보면 다음과 같다. 1. Y? Y'? 결론부터 간략히 얘기하자면, Y와 Y'는 사실은 정확히 같은 값은 아니다. Y는 Color Science에서 다루는 RGB의 가중치 합인 휘도를 의미한다. 반면, Y'는 Luma라 불리우며, 감마 변환된 RGB 즉, R' G' B'의 가중치 합이다. 2. UV ..
2016/04/01 - 연산 결과를 0~255 이내로 하는 가장 빠른 방법은? 무어의 법칙이 사실상 깨진 것이나 다름 없고, 수년 전부터 CPU 성능의 향상은 클럭 속도 향상보다는 병렬처리 쪽에 더 힘이 실리고 있다. 이를 위해 다중 코어 프로세서가 일반화되었고, 다양한 SIMD 기술들이 적용되고 있다. 또한, 컴파일러에서도 지시자를 통한 OpenMP, 자동 병렬화 및 SIMD의 intrinsic 함수를 원활히 지원하는 추세이다. 이미지 리샘플링을 구현하면서 다중 코어 활용 기술과 SIMD를 모두 적용해서 최대한의 성능을 발휘하도록 해뒀다. 그런데, 이 구현 방식들 간에 어느 정도나 성능 차이가 발생하는지 확인을 해보고 싶어졌다. 구현한 리샘플링은 Lanczos3 및 Mitchell-Netravali 두..
인터넷에서 "문과는 집에 들어가지 말란 거냐"는 비난(?)을 받는 "미래네 집 현관 비밀번호" 문제. 심심해서(?) 이 문제를 풀어봤다. 1. 정석으로 풀기 \(ab\)월 \(cd\)일이라고 하니 각 값의 범위는 아래와 같다. \(a = 1\) \(0 \leq b \leq 2 \quad (\because 10월 \sim 12월만 있음)\) \(1 \leq c \leq 3\) \(0 \leq d \leq 9 \) 풀어야 할 두 개의 식은 아래와 같다. \((x^2 -2x)^2 +x^2 -2x-2=(x^2 -2x-a)(x^2 -2x+b) \quad : \quad A\) \(2x^2 +xy-7x-3y+3=(x-3)(cx+y-d) \quad : \quad B\) \(A\)에서 상수항을 보면 \(a \times ..
excel에서 두 날짜 간의 연도가 차지하는 비율을 계산하는 함수는 YEARFRAC()이다. 그런데, 이 함수가 정확히 어떻게 동작하는지를 찾아보니 제대로 설명된 곳이 별로 없다. YEARFRAC(, , ) 앞의 두 인자는 날짜이고, 세번째 인자인 basis는 계산 유형을 지정하는 것이다. basis에는 0~4가 지정될 수 있고, 생략시는 0. 그런데, 0일 때의 동작방식이 뭔가 모호하다. 한 달을 30일로 가정하고 계산한다는데, 보통 아래와 같은 식으로 표현한다. \(yearfrac = \frac{360 \times(Y_2-Y_1)+30 \times (M_2-M_1)+(D_2-D_1)}{360}\) 즉, 1년을 360일, 한 달을 30일로 가정하고 계산하는 것이다. 그런데… 실제로 해보면 다른 결과가 ..
멀티미디어 특히 비디오 데이터를 처리하려면 굉장히 빈번하게 사용되는 함수가 바로 clamping이다.각종 변환 결과 애매하게 이 범위를 벗어나는 경우가 발생할 수 있기 때문에 모든 픽셀에 대해 이 연산을 돌려야 하기 때문이다. 1. SSE2를 사용하지 않는 경우-1 기본적으로는 아래와 같이 작성하면 된다. (1A: if #1) inline unsigned char Clamp(float f) { int n = (int)f; if (n 255) return 255; return (unsigned char)n;} 그런데, if문이 두 개 씩이나 들어있어 뭔가 보기 좋지 않다.if문 대신 삼항연산자를 둘 사용하면 아래와 같이 좀 더 간결하게 쓸 수 있다. (1B..