By 한동훈(traxacun@unitel.co.kr)
머신 입실론은 컴퓨터가 이해할 수 있는 가장 작은 숫자 단위를 말한다. 알다시피 컴퓨터는 실수를 이진수의 형태로 저장한다. 때문에 1/3과 같은 숫자를 저장하는 것은 불가능하다. 하지만 대부분의 경우에 여러분은 무한히 긴 0.333333333333.... 을 볼 수 있었을 것이다.
그러나 그 마지막 값은 일반적으로 3이 아니라... 2나 4가 된다. 이와 같이 컴퓨터가 다룰 수 있는 가장 작은 수, 즉 임계값을 머신 입실론이라한다.
다른 말로는 1보다 큰 가장 작은 숫자를 머신 입실론이라 한다.
그래서 종종 머신 입실론 값은 정확한 계산이 필요한 회계 분야나 공학 분야에서 중요하다. 그래서 여기서는 알고리즘으로 머신 입실론 값을 구해보고, C++과 C# 언어에서 지원하는 머신 입실론 관련 함수를 알아본다.
작업환경:- C Compiler : Microsoft 32bit C/C++ Optimization Compiler version 13.00.9254(80x86버전)
- C# Compiler : Microsoft Visual C# Compiler Version 7.00.9254[ CLR Version v 1.0.2914]
이름: machine_eps.cs
// machine epsilion
#include // 필요한 함수에 대한 헤더 파일 선언
int main() // main 함수 선언.
{
float ex, g = 1, eps; // float(단정도 실수) 변수 ex, g, eps 선언
do // do while loop 문 시작
{
g = g / 2; // g의 값을 2로 나눈후에 g에 저장
ex = g * 0.98 - 1; // 계산된 g 값에 0.98을 곱하고 1을 뺀다.
ex = ex - 1; // 계산된 ex에서 1을 뺀다.
printf("g = %15.8e ex = %15.8e₩n", g, ex);
// 형식 지정자 %15.8e를 사용해서 e 지수 타입으로 표시하며
// 각 자리수는 15자리와 8자리로 표현한다.
if ( ex > 0 ) eps = ex; // ex가 0보다 크다면 eps에 ex값을 저장한다.
}
while ( ex > 0 );
// ex가 0보다 크다면 계속 반복한다.
// Ex의 값이 0이거나 0보다 작으면 루프를 종료한다.
printf("₩n Machine epsilon = %16.8e₩n₩n", eps);
// machine epsilon 값을 출력한다.
return 0;
// main 함수 반환 타입을 int로 썼으므로 성공적인 숫자 0을 반환한다.
}
|
machine_eps.exe의 실행결과
E:₩works₩c>machine_eps.exe
g = 5.00000000e-001 ex = -1.51000000e+000
Machine epsilon = 5.60519386e-045
설명:
정확한 머신 입실론 값을 측정할 수 없다.
실제로 현재 쓰이고 있는 CPU에서 단정도의 머신 입실론 값은 1.401298E-45다.
C#에서는 머신 입실론을 알고리즘을 통하지 않고, 프로퍼티를 통해서 바로 알 수 있다. Float는 단정도 실수이며 4 바이트를 사용한다. 마찬가지로 C#에서는 System.Single 클래스에 대한 별칭으로 float 데이터 타입을 사용하며 4 바이트를 사용하는 단정도 실수이다.
이 소스에는 치명적인 단점이 있는데, integer 타입의 single 타입으로 암시적인 캐스팅이 이뤄지고 있어서 정확한 계산이 이뤄지지 않았다.
이름: machine_eps2.cs
using System;
public class MachineEps
{
public static void Main(string [] args)
{
Console.WriteLine(System.Single.Epsilon);
}
}
|
실행결과:
1.401298E-45
단정도 실수에 대한 C# 언어에서의 머신 입실론 값을 알 수 있다.
C++ 언어에서의 입실론 값은 다음과 같다.
이름: machine_eps3.cpp
// compile with: /EHsc
#include
#include
using namespace std;
int main( )
{
cout << "float objects is: "
<< numeric_limits::epsilon( )
<< endl;
cout << "for double objects is: "
<< numeric_limits::epsilon( )
<< endl;
cout << "long double objects is: "
<< numeric_limits::epsilon( )
<< endl;
return 0;
}
|
위 코드의 컴파일은 다음과 같이 해야한다.
Cl /EHsc machine_eps3.cpp
/EHsc는 /EHs와 /EHc를 뜻한다. EHs는 동기 예외 처리 모델을 사용한다는 것을 뜻하며, EHc는 C++의 예외 처리 모델을 사용하지 않는 다는 것을 뜻한다. 이와 같이 하지 않으면 컴파일은 되지만 예외 처리가 되지 않은 코드에서 예외가 발생하기에 에러를 만날 것이다.
실행결과:
float objects is: 1.19209e-007
for double objects is: 2.22045e-016
long double objects is: 2.22045e-016
이상으로 C, C++, C#에서 머신 입실론에 대해서 살펴보았다.
C++와 같은 전통적인 언어는 탄생된지 오래되었기 때문에 언어가 탄생되는 시점의 하드웨어를 반영하고 있기에 현대 프로그래밍 언어에 비하면 같이 정확하지 못하다.
C#과 같은 언어에서는 자체적으로 머신 입실론 값을 알 수 있는 프로퍼티를 제공하고 있으며, 별도의 데이터 타입에 대한 입실론 값을 구할 수 있는 epsilon 메소드를 제공한다. 또한 벡터 연산을 간단히 구현할 수 있고, 복소수 연산을 손쉽게 할 수 있으며, System.Decimal과 같은 12 바이트의 데이터 타입을 지원하여 보다 정확한 실수 값을 지원한다.