728x90
300x250

[C, C++] double의 비교

 

float, double의 경우, 비교 자체가 소수 점이라는 것이 있어서 어렵습니다.

단순 비교를 해버리면 안되는 게 1.xxxxxxxx 의 경우, 1로 절삭 처리됩니다.

컴파일러가 멍청해서 그런 것도 있지만, 소수 점은 Science에선 중요한 거지만, 단순한 명령을 처리하는 컴퓨터 입장에선 엄밀한 것과 정확성을 보장해주는 자료형이 더 좋은 것입니다.

 

예를 들면, 스위치 On, Off와 같이 1, 0이 컴퓨터 입장에선 더 직관적이고 엄밀한 자료가 될 수 있습니다.

 

float, double형의 경우, IEEE 754 규약에 의해 부동소수점의 원칙을 기반으로 한 별도의 코딩을 통해 비교를 처리해야 합니다.

 


아래의 코드는 구글에 근무하는 brucedawson씨가 소개한 개념을 바탕으로 Ulps기반의 Double형 비교를 위한 코드를 DevMachine님이 개발한 코드입니다.

 

int CompareDoubleAbsoulteAndUlps(double x,
                                 double y,
                                 double absTolerance = (1.0e-8),
                                 int ulpsTolerance = 4)
{
    double diff = x - y;
    if (fabs(diff) <= absTolerance)
        return 0;

    __int64 nx = *((__int64*)&x);
    __int64 ny = *((__int64*)&y);

    if ((nx & 0x8000000000000000) != (ny & 0x8000000000000000))
        return (diff > 0) ? 1 : -1;

    __int64 ulpsDiff = nx - ny;
    if ((ulpsDiff >= 0 ? ulpsDiff : -ulpsDiff) <= ulpsTolerance)
        return 0;

    return (diff > 0) ? 1 : -1;
}

 


1. 참고자료(Reference)

  

1. Comparing floating point numbers - Bruce Dawson

2. Comparing Floating Point Numbers, 2012 Edition 

3. http://devmachine.blog.me/220119534107

 

정확히 이해하려면, 여기에 설명하는 것보단 IEEE 754의 부동소수점에 대해 공부해보시는 게 훨씬 빠를 거 같다는 생각을 해봅니다.

저는 참고 인용 문구를 통해 코드 배포 목적으로 이 글을 정리하고자 합니다.

 

반응형
728x90
300x250

[C, C++] Header와 템플릿의 명시적 특수화

 

C, C++에서 Template라는 개념은 <int>, <string>, <char> 등의 다양한 자료형의 함수를 두 번 생산하지 않고, 재사용을 한다는 장점을 통해, 개발 인력의 최소화로 긍정적인 부분을 보여준다고 할 수 있습니다.

이러한 Template는

 

#include < iostream >

 

using namespace std;

 

template <typename T>

class dd{


}

 

int main(){

 

 

이같은 꼴로 사용할 수 있습니다.

 

이러한 템플릿에서 명시적 특수화에 대해 잠시 소개하려고 합니다.

Explicit Specialization은 전체 특수화를 기본 특징으로 갖는 언어를 말합니다.

 

어려운 개념은 아닌데, 잘못 사용하면, 어려워지는 개념이 이 부분이 아닐까 싶습니다.

 

 template <typename T> class Invalid { 
 }; 

InVaild<double> x1;    // Invalid<double> 인스턴스화 시킴

template<> 
class Invalid<double>; // 에러: Invalid<double> 이미 인스턴스화 됨

 

위험하게 구성된 코드입니다. 흔히들 작업하다보면, 이와 같은 쓰레기 코드를 만들 수 있는데, 참조수준의 문제로 시스템에 중대한 오류를 발생시킬 수 있습니다.

 

기본적인 원칙을 구하고 사용하자.

 

template <typename T>

 class Invalid { 

       void aa(); 
 }; 

(정의)

 

template <typename T>

void Invalid<T>::aa()
{

}

(선언)

 

 

이의 경우, void 형의 aa() 함수를 선언하고 정의한 예시입니다.

기본적인 이의 구조는 당연한 Template를 생성하는 기본 원칙입니다.

 

template <typename T>

 class Invalid { 

       void aa(T data); 
 }; 

(정의)

 

template <typename T>

void Invalid<T>::aa(T data)
{

}

(선언)

 

template <>

void Invalid<char>::aa(char data)
{

}

(명시적 특수화)

 

 

T보다 특수화가 앞서 선언될 수 없다는 점을 명확히 할 필요가 있습니다.

아래는 가능한 사례를 몇 개 소개해드리고자 합니다.

 

template <typename T, typename D>

 class Invalid { 

       void aa(T data1, D data2); 
 }; 

(정의)

 

template <typename T, typename D>

void Invalid<T>::aa(T data1, D data2)
{

}

(선언)

 

template <char, int>

void Invalid<char, int>::aa(char data1, int data2)
{

}

(명시적 특수화)

 

 

이의 경우에는 명시적 특수화에서 오류가 날 수밖에 없습니다.

template <char, int>라고 쓴 부분은 template 함수를 생성하는 자료형이 와야 맞는데 General Data Type이 오기 때문에 오류가 날 수밖에 없습니다.

 

#include <iostream>
template <typename T, typename D>
class test{
public:
 void aa(T data1, D data2);
};
template <typename T, typename D>
void test<T, D>::aa(T data1, D data2){
 std::cout << "T, D";
 std::cout << std::endl;
 std::cout << data1 << "," << data2;
 std::cout << std::endl;
}
template <>
void test<char, int>::aa(char data1, int data2)
{
 std::cout << "T, D";
 std::cout << std::endl;
 std::cout << data1 << "," << data2;
 std::cout << std::endl;
}
int main(){
 test<double, int> aaaa;
 aaaa.aa(1.22, 1);
 test<char, int> bbbb;
 bbbb.aa('a', 1);
}

 

출력

T, D
1.22,1
T, D
a,1

 

 


1. 추천 사이트


1. https://wikidocs.net/488

 

반응형

+ Recent posts