370 likes | 625 Views
부동소수점 (FLP). 사이버보안학과 김현성. 제안. FLP00-C 부동소수점 수의 제한을 이해하라 FLP01-C 부동소수점 표현식을 재배치할 때 주의하라 FLP02-C 정확한 계산이 필요할 때는 부동소수점 수를 배제할 수 있는지 고려하라 FLP03-C 부동소수점 에러를 발견하고 처리하라. 규칙. FLP30-C 부동소수점 변수를 루프 카운터로 사용하지 마라 FLP31-C 함수에 복소수를 사용하면서 실제 값을 얻을 거라 기대하지 마라
E N D
부동소수점(FLP) 사이버보안학과김현성
제안 • FLP00-C 부동소수점 수의 제한을 이해하라 • FLP01-C 부동소수점 표현식을 재배치할 때 주의하라 • FLP02-C 정확한 계산이 필요할 때는 부동소수점 수를 배제할 수 있는지 고려하라 • FLP03-C 부동소수점 에러를 발견하고 처리하라
규칙 • FLP30-C 부동소수점 변수를 루프 카운터로 사용하지 마라 • FLP31-C 함수에 복소수를 사용하면서 실제 값을 얻을 거라 기대하지 마라 • FLP32-C 수학 함수에서 도메인 에러나 영역 에러를 찾고 예방하라 • FLP33-C 부동소수점 연산용 정수는 먼저 부동소수점으로 바꿔라 • FLP34-C 부동소수점 변환이 새로운 타입의 범위 안에 들어가는지 확인하라
제안 • FLP00-C 부동소수점 수의 제한을 이해하라 • FLP01-C 부동소수점 표현식을 재배치할 때 주의하라 • FLP02-C 정확한 계산이 필요할 때는 부동소수점 수를 배제할 수 있는지 고려하라 • FLP03-C 부동소수점 에러를 발견하고 처리하라
부동소수점 수의 제한을 이해하라 부동소수점 14e2 123e-3 14x102=1400 123x10-3=0.123 • 실수를 부호, 지수, 소수의 세 부분으로 구분하여 표현 • 4바이트를 사용하는 부동 소수점 형식
부동소수점 수의 제한을 이해하라 부동소수점 • 어떤 시스템으로 구현되었든지 고정된 정밀도를 가짐 • 반올림과 관련된 에러 유발 가능성 있음 • 시스템에 따라 정밀도와 표현 가능한 값의 범위가 다름 => 컴퓨터는 유한한 개수의 숫자 표현 가능
부동소수점 수의 제한을 이해하라 FLP00-C 코드 예 #include <stdio.h> int main (void) { float f = 1.0f / 3.0f; printf(“Float is %.50f\n”, f); return 0; } => 0.33333333333333333333333333 => Linux GCC 0.33333334326744079843750000 XP Visual C++ 9.0 0.33333334326744080000000000
제안 • FLP00-C 부동소수점 수의 제한을 이해하라 • FLP01-C 부동소수점 표현식을 재배치할 때 주의하라 • FLP02-C 정확한 계산이 필요할 때는 부동소수점 수를 배제할 수 있는지 고려하라 • FLP03-C 부동소수점 에러를 발견하고 처리하라
부동소수점 표현식을 재배치할 때 주의하라 FLP01-C 코드 예 x *= y * z; z = x; z = x * (1.0 + y); y = x * 0.2; double x, y, z; /* ... */ x = (x * y) * z; z = (x – y) + y; z = x + x * y; y = x / 5.0; => 범위 한계 및 정밀도 한계로 인해서 문제 발생됨(Round off)
제안 • FLP00-C 부동소수점 수의 제한을 이해하라 • FLP01-C 부동소수점 표현식을 재배치할 때 주의하라 • FLP02-C 정확한 계산이 필요할 때는 부동소수점 수를 배제할 수 있는지 고려하라 • FLP03-C 부동소수점 에러를 발견하고 처리하라
정확한 계산이 필요할 때는 부동소수점 수를 배제할 수 있는지 고려하라 FLP02-C 부적절한코드 예 => mean is 10.1 => mean is 10.099999 64Linux with GCC 4.1 #include<stdio.h> float mean(float array[], int size) { float total = 0.0; int i; for (i=0; i<size; i++){ total += array[i]; printf(“array[%d] = %f and total is %f\n”, i, array[i], total); } if (size != 0) return total / size; else return 0.0; } enum {array_size = 10}; float array_value = 10.1; int main(void) { float array[array_size]; float avg; int i; for (i=0; i<array_size; i++) array[i] = array_value; avg = mean(array, array_size); printf(“mean is %f\n, avg); if (avg == array[0]) { printf(“array[0] is the mean\n”); } else { printf(“array[0] is not the mean\n”); } return 0; }
정확한 계산이 필요할 때는 부동소수점 수를 배제할 수 있는지 고려하라 FLP02-C 해결방법 #include<stdio.h> float mean(int array[], int size) { int total = 0; int i; for (i=0; i<size; i++){ total += array[i]; printf(“array[%d]=%f and total is %f\n”, i, array[i]/100.0, total/100.0); } if (size != 0) return total / size; else return 0.0; } enum {array_size = 10}; int array_value = 1010; int main(void) { int array[array_size]; float avg; int i; for (i=0; i<array_size; i++) array[i] = array_value; avg = mean(array, array_size); printf(“mean is %f\n, avg/100.0); if (avg == array[0]) { printf(“array[0] is the mean\n”); } else { printf(“array[0] is not the mean\n”); } return 0; }
제안 • FLP00-C 부동소수점 수의 제한을 이해하라 • FLP01-C 부동소수점 표현식을 재배치할 때 주의하라 • FLP02-C 정확한 계산이 필요할 때는 부동소수점 수를 배제할 수 있는지 고려하라 • FLP03-C 부동소수점 에러를 발견하고 처리하라
부동소수점 에러를 발견하고 처리하라 FLP03-C 부적절한코드 예 voidfpOper_noErrorChekin(void) { /* ... */ double a = 1e-40, b, c = 0.1; float x = 0, y; /* 부정확하며 언더플로우가 발생 */ y = a; /* 0으로 나누는 에러 */ b = y / x; /* 부정확함(정밀도를 잃어버림) */ c = sin(30) * a; /* ... */ }
부동소수점 에러를 발견하고 처리하라 pragma • 컴파일러에 직접 명령을 내리기 위한 지시자( #pragma STDC 로 시작 ) • 종류 #pragma once : 해당명령 한번만 컴파일 #pragma warning : 특정 경고 에러 띄우지 않음 #pragma comment : 라이브러리를 인클루드할 때 많이 사용 #pragma pack : 메모리 공간 최적화
부동소수점 에러를 발견하고 처리하라 fenv.h • 부동소수점 환경을 제어하기 위한 C99표준함수
부동소수점 에러를 발견하고 처리하라 FLP03-C 해결방법 #include <fenv.h> /* 부동소수점 에러 처리 표준 함수 */ #pragma STDC FENV_ACCESS ON voidfpOper_fenv(void) { double a = 1e-40, b, c = 0.1; float x = 0, y; int fpeRaised; /* ... */ feclearexcept(FE_ALL_EXCEPT); /* a를 y에 저장하면 값이 부정확해지고 언더블로우 발생 */ y = a; fpeRaised = fetestexcept(FE_ALL_EXCEPT); /* fpeRaised는FE_INEXACT와 FE_UNDERFLOW가짐 */ feclearexcept(FE_ALL_EXCEPT); /* 0으로 나누는 연산 */ b = y / x; fpeRaised = fetestexcept(FE_ALL_EXCEPT); /* fpeRaised는FE_DIVBYZERO가짐 */ feclearexcept(FE_ALL_EXCEPT); c = sin(30) * a; fpeRaised = fetestexcept(FE_ALL_EXCEPT); /* fpeRaised는FE_INEXACT가짐 */ feclearexcept(FE_ALL_EXCEPT); /* ... */ }
규칙 • FLP30-C 부동소수점 변수를 루프 카운터로 사용하지 마라 • FLP31-C 함수에 복소수를 사용하면서 실제 값을 얻을 거라 기대하지 마라 • FLP32-C 수학 함수에서 도메인 에러나 영역 에러를 찾고 예방하라 • FLP33-C 부동소수점 연산용 정수는 먼저 부동소수점으로 바꿔라 • FLP34-C 부동소수점 변환이 새로운 타입의 범위 안에 들어가는지 확인하라
부동소수점 변수를 루프 카운터로 사용하지 마라 FLP30-C 부적절한코드 예 for(float x = 0.1f; x <= 1.0f; x+= 0.1f) { /* ... */ } => for 루프 10회 실행 => IA-32머신 Window XP, Visual C++ 2005 v8.0 -> 9회 실행
부동소수점 변수를 루프 카운터로 사용하지 마라 FLP30-C 해결방법 for(size_t i = 1; i <= 10; i += 1) { float x = i/10.0f; /* ... */ }
규칙 • FLP30-C 부동소수점 변수를 루프 카운터로 사용하지 마라 • FLP31-C 함수에 복소수를 사용하면서 실제 값을 얻을 거라 기대하지 마라 • FLP32-C 수학 함수에서 도메인 에러나 영역 에러를 찾고 예방하라 • FLP33-C 부동소수점 연산용 정수는 먼저 부동소수점으로 바꿔라 • FLP34-C 부동소수점 변환이 새로운 타입의 범위 안에 들어가는지 확인하라
함수에 복소수를 사용하면서 실제 값을 얻을 거라 기대하지 마라 복소수로호출하면 안되는 함수
함수에 복소수를 사용하면서 실제 값을 얻을 거라 기대하지 마라 FLP31-C 부적절한코드 예 double complex c = 2.0 + 4.0 * I; /* ... */ double complex result = log2(c); => log2는 실수값 만을 허용하는 타입이므로 정의되지 않은 동작 초래
함수에 복소수를 사용하면서 실제 값을 얻을 거라 기대하지 마라 FLP31-C 해결방법 double complex c = 2.0 + 4.0 * I; /* ... */ double complex result = log2(creal(c)); 복소수의 실수부 계산
규칙 • FLP30-C 부동소수점 변수를 루프 카운터로 사용하지 마라 • FLP31-C 함수에 복소수를 사용하면서 실제 값을 얻을 거라 기대하지 마라 • FLP32-C 수학 함수에서 도메인 에러나 영역 에러를 찾고 예방하라 • FLP33-C 부동소수점 연산용 정수는 먼저 부동소수점으로 바꿔라 • FLP34-C 부동소수점 변환이 새로운 타입의 범위 안에 들어가는지 확인하라
수학 함수에서 도메인 에러나 영역 에러를 찾고 예방하라 도메인체크 • 수학 함수에 전달되는 인자 값이 함수 정의 시 지정된 도메인 안에 있음을 보장해 예방 if( /* 인자 값이 도메인 에러를 유발할 수 있음 */) { /* 도메인 에러 처리 */ } else { /* 계산수행 */ }
수학 함수에서 도메인 에러나 영역 에러를 찾고 예방하라 범위체크
수학 함수에서 도메인 에러나 영역 에러를 찾고 예방하라 범위체크
수학 함수에서 도메인 에러나 영역 에러를 찾고 예방하라 FLP32-C 부적절한코드 예 doublex; double result; /* x 초기화 */ result = sqrt(x); => x의 제곱근 구함 => x가 음수인 경우 에러 발생
수학 함수에서 도메인 에러나 영역 에러를 찾고 예방하라 FLP32-C 해결방법 doublex; double result; /* x 초기화 */ if (isless(x,0)) /* 범위 에러 처리 */ else result = sqrt(x);
규칙 • FLP30-C 부동소수점 변수를 루프 카운터로 사용하지 마라 • FLP31-C 함수에 복소수를 사용하면서 실제 값을 얻을 거라 기대하지 마라 • FLP32-C 수학 함수에서 도메인 에러나 영역 에러를 찾고 예방하라 • FLP33-C 부동소수점 연산용 정수는 먼저 부동소수점으로 바꿔라 • FLP34-C 부동소수점 변환이 새로운 타입의 범위 안에 들어가는지 확인하라
부동소수점 연산용 정수는 먼저 부동소수점으로 바꿔라 FLP33-C 부적절한코드 예 short a = 533; int b = 6789; long c = 466438237; float d = a / 7; double e = b / 30; double f = c * 789; => d=76.0 e=226.0 f=368019768993 => d, e, f가 부정확하게 초기화되어 값의 일부가 정수 근처에서 잘리거나 오버플로우 발생 가능
부동소수점 연산용 정수는 먼저 부동소수점으로 바꿔라 FLP33-C 해결방법 short a = 533; int b = 6789; long c = 466438237; float d = a / 7.0; double e = b / 30.0; double f = double(c) * 789;
규칙 • FLP30-C 부동소수점 변수를 루프 카운터로 사용하지 마라 • FLP31-C 함수에 복소수를 사용하면서 실제 값을 얻을 거라 기대하지 마라 • FLP32-C 수학 함수에서 도메인 에러나 영역 에러를 찾고 예방하라 • FLP33-C 부동소수점 연산용 정수는 먼저 부동소수점으로 바꿔라 • FLP34-C 부동소수점 변환이 새로운 타입의 범위 안에 들어가는지 확인하라
부동소수점 변환이 새로운 타입의 범위 안에 들어가는지 확인하라 FLP34-C 부적절한코드 예 float f1; int i1; /* f1 초기화 */ i1 = f1; => f1의정수 부분이 INT_MAX보다 큰 경우 정의되지 않음
부동소수점 변환이 새로운 타입의 범위 안에 들어가는지 확인하라 FLP34-C 해결방법 float f1; int i1; /* f1 초기화 */ if ( f1 > (float) INT_MAX || f1 < (float) INT_MIN) { else { i1 = f1; }
규칙 • FLP30-C 부동소수점 변수를 루프 카운터로 사용하지 마라 • FLP31-C 함수에 복소수를 사용하면서 실제 값을 얻을 거라 기대하지 마라 • FLP32-C 수학 함수에서 도메인 에러나 영역 에러를 찾고 예방하라 • FLP33-C 부동소수점 연산용 정수는 먼저 부동소수점으로 바꿔라 • FLP34-C 부동소수점 변환이 새로운 타입의 범위 안에 들어가는지 확인하라