References
- C++ Standard Library 2nd
- cppreference (link)
숫자 타입(numeric types)는 일반적으로 플랫폼에 따라서 한계값이 다릅니다. C++ 표준 라이브러리에서는 이러한 한계값을 numeric_limits 라는 템플릿으로 제공합니다. 이렇게 제공되는 numeric limit은 일반적인 전처리 C 상수를 대체하고 보완하는데 사용될 수 있습니다. 물론, 정수 타입에 대해서는 <climits>와 <limits.h>를 통해, 부동소수점 타입에 대해서는 <cfloat>와 <float.h>를 통해 기존에 사용되던 C 상수도 여전히 지원됩니다.
하지만, C++에서 제공하는 numeric limits를 사용하면 데이터 타입에 안전하다는 것과 프로그래머가 이러한 한계값을 처리하는 템플릿을 작성할 수 있다는 장점을 얻을 수 있습니다.
이번 포스팅에서는 numeric limits에 대해서 간단히 살펴볼텐데, 항상 타입에서 보장하는 최소한의 정밀도만을 사용해서 플랫폼에 독립적인 코드를 작성하는 것이 더 낫다는 점을 기억해둡시다. 아래 표는 최소한으로 보장되는 값들을 나타냅니다.
numeric_limits<> 클래스
일반적으로 어떤 기능을 어떠한 데이터 타입에 대해서라도 사용하고 싶을 때 템플릿을 사용합니다. 하지만, 모든 데이터 타입에 대해서 공통 인터페이스를 제공할 때도 템플릿을 사용할 수 있습니다. 이러한 기법을 사용한 예제가 바로 numeric_limits이며, 동작 방식은 다음과 같습니다 (<limits> 헤더에 정의되어 있습니다).
- 일반 템플릿은 어떠한 타입에 대해서라도 default numeric values를 제공합니다.
namespace std {
// general numeric limits as default for any type
template<typename T>
class numeric_limits {
public:
// by default no specialization for any type T exists
static constexpr bool is_specialized = false;
... // other members are meaningless for the general template
};
}
numeric limits에 대한 일반 템플릿(general template)은 T 타입에 대해서 어떠한 numeric limits도 사용할 수 없다는 것을 알려줍니다 (is_specialized 멤버에 false를 할당하여).
- 템플릿 특수화(specialization)은 각 numeric type에 대해 다음과 같이 numeric limits를 정의합니다.
namespace std {
// numeric limits for int
// - implementation defined
template<> class numeric_limits<int> {
public:
// a specialization for numeric limits of int does exist
static constexpr bool is_specialized = true;
static constexpr int min() noexcept {
return -2147483648;
}
static constexpr int max() noexcept {
return 2147483647;
}
static constexpr int digits = 31;
...
};
}
여기서 is_specialized는 true로 설정되고, 다른 모든 멤버들은 특정 데이터 타입에 대한 numeric limits의 값을 갖습니다.
이러한 특수화는 숫자 값을 갖는 모든 기본 타입(bool, char, signed char, unsigned char, char16_t, char32_t, wchar_t, short, unsigned short, int, unsigned int, long, unsigned long, long long, unsigned long long, float, double, long double)에 대해 정의되어 있습니다. 또한, 커스텀 숫자 타입에 대해서도 쉽게 추가할 수 있습니다.
클래스에는 여러 멤버들이 제공되는데, 자세히 나열하지는 않도록 하겠습니다. 제공되는 멤버들은 link를 참조바랍니다.
아래 코드는 실제 <limits>에 정의된 numeric_limits<float> 입니다.
C++11부터는 모든 멤버에 대해 constexpr로 선언될 수 있는데, numeric_limits<>의 멤버들은 모두 cosntexpr로 선언되어 있는 것을 볼 수 있습니다. 따라서, 컴파일 시간 표현식이므로 이를 사용하여 배열을 선언할 수 있습니다.
static const int ERROR_VALUE = std::numeric_limits<int>::max();
float a[std::numeric_limits<short>::max()];
C++11 이전에는 함수가 아닌 멤버에 대해서만 const이면서 static일 수 있었기 때문에 이 값들을 컴파일 시간에 결정할 수 있었습니다. 하지만 멤버 함수는 static만 가능하여 위 예제와 같은 표현식을 사용할 수 없었습니다.
클래스 멤버 중에는 반올림 스타일이나 비정규화(denormalization) 스타일에 대한 정보도 제공합니다.
반올림 스타일은 rount_style 멤버를 통해 제공되며, 가질 수 있는 값은 아래와 같습니다.
비정규화 스타일은 has_denorm 멤버로 제공되며, 가능한 값은 아래와 같습니다.
Example of Using numeric_limits<>
numeric_limits<>는 특정 데이터 타입을 위한 최댓값이나 char가 부호를 갖는지 확인하는지 등의 작업을 수행할 수 있습니다.
#include <iostream>
#include <string>
#include <limits>
using namespace std;
int main()
{
// use textual representation for bool
cout << boolalpha;
// print maximum of integral types
cout << "max(short): " << numeric_limits<short>::max() << endl;
cout << "max(int): " << numeric_limits<int>::max() << endl;
cout << "max(long): " << numeric_limits<long>::max() << endl;
cout << endl;
// print maximum of floating-point types
cout << "max(float): "
<< numeric_limits<float>::max() << endl;
cout << "max(double): "
<< numeric_limits<double>::max() << endl;
cout << "max(long double): "
<< numeric_limits<long double>::max() << endl;
cout << endl;
// print whether char is signed
cout << "is_signed(char): "
<< numeric_limits<char>::is_signed << endl;
cout << endl;
// print whether numeric limits for type string exist
cout << "is_specialized(string): "
<< numeric_limits<string>::is_specialized << endl;
}
출력은 플랫폼에 따라 다르겠지만, 대부분 위와 같을 것 입니다.
마지막 구문은 string이라는 데이터 타입에는 numeric limits가 없다는 것을 보여줍니다.
'프로그래밍 > C & C++' 카테고리의 다른 글
[C++] Clocks and Timers (0) | 2022.12.08 |
---|---|
[C++] Type Traits와 Type Utilities (0) | 2022.12.07 |
[C++] Pairs and Tuples (0) | 2022.12.06 |
[C++] C++11에서 추가된 기능 (2) (0) | 2022.12.04 |
[C++] C++11에서 추가된 기능 (1) (0) | 2022.12.03 |
댓글