본문 바로가기
프로그래밍/C & C++

[C++] Numeric Limits

by 별준 2022. 12. 6.

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의 값을 갖습니다.

numeric_limits<int> definition in <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> 입니다.

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

댓글