부동소수점

카테고리 없음 2018. 12. 25. 16:38

1. 컴퓨터가 실수를 표현하는 방법


* 고정 소수점 : 정수부와 소수부로 나누어서 표현하는 방법

 - int와 다를게 없어서 연산속도가 빠르고 시스템이 간단함

 - 표현할 수 있는 수의 크기가 작음

 - 정밀도를 높이려면 필요한 비트 수가 커짐


* 부동 소수점 : 가수부와 지수부로 나누어서 표현하는 방법

 - 넓은 범위의 숫자를 표현할 수 있음

 - 상대적으로 정밀도가 높음

 - 연산이 복잡해짐







2. 2진법으로 된 부동소수점


IEEE 754 : IEEE에서 공표한 부동 소수점 방식의 표준안




s (부호) : 첫번째 비트, 수의 부호를 결정


m (가수) : 2진수에서는 1.xxxx.. 로 이루어짐

 - 단정도(32비트) : 23비트

 - 배정도(64비트) : 52비트


e (지수) : m을 정규화 하면 정해지는 값, IEEE 754에서는 비트로 표현하는경우 e + bias가 들어가게 된다

 - 단정도(32비트) : 8비트

 - 배정도(64비트) : 11비트




* 예시) -27.625


-27.625 (10진수) = 11011.101 (2진수)


s (부호) => 

 -1 이므로 비트는 1


m (가수) => 

 - 11011.101을 4칸 이동시킴 : 1.1011101

 - 소수 부분만 남김 : 1011101

 - 나머지는 0으로 채움 : 1011101000...


e (지수) : m을 정규화 하면 정해지는 값, IEEE 754에서는 비트로 표현하는경우 e + bias가 들어가게 된다

 - 4칸 이동이므로 2 ^ 4 : e는 4

 - IEEE 754에서는 bias값은 127 이므로 4 + 127 = 131

 - 이진법 변환 : 10000011


1100000111011101000...







3. 부동소수점 오류


* 0.1을 소수점 9자리까지 출력했을 때



float value = 0.1f;
Console.WriteLine("{0:G9}", value);  //0.100000001


=> 실제로 근사치를 갖고 있음



* 0.1과 0.100000001490116119384765625을 비교했을 때


float num = 0.1f;
if(num == 0.100000001490116119384765625)
{
     Console.WriteLine("True"); // 출력
}

=> 다음과 같이 정확한 값을 갖고 있지 않아서 연산에도 오류가 생긴다


* int형으로 캐스팅



float value = 43.3f - 43.2f;
 Console.WriteLine("{0:G9}", value); //0.0999984741

 value = value * 10;
 Console.WriteLine("{0:G9}", value); //0.999984741

 int valueInt = (int)value;
 Console.WriteLine(valueInt); //0


=> 원하는 값은 0.1, 1, 1 이어야하지만 실제로 갖고있는 실수값이 근사값이기 때문에 int로 형변환 시 의도하던 값과 다른 값이 나옴








4. 오류 해결 방법


* float보다는 double 사용

 - float의 상대오차 10^-7, double의 상대오차 10^-15 

 - C# decimal : 부동소수형이 아니고 29자리까지 지원


* 바로 캐스팅하지 말고 작은 숫자만큼 더한 후 캐스팅


* 등호사용 금지(내결함성 허용) : epsilon 사용



double value = 43.3f - 43.2f;

if(value >= 0.1)
{
    Console.WriteLine("Yes!");
}
else
{
    Console.WriteLine("No!"); // No! 출력
}

if (Math.Abs(value) <= 0.1f + double.Epsilon)
{
    Console.WriteLine("Yes!"); // Yes! 출력
}
else
{
    Console.WriteLine("No!");
}

=> 최대한 실수형 간 계산을 피하기

Posted by @히테
,