limits


Header <limits>

The <limits> header is part of the C++ Standard Library that provides information about the properties and limitations of arithmetic types in C++. It defines the std::numeric_limits class template, which offers a standardized way to query various properties of arithmetic types, such as their minimum and maximum values, precision, and other characteristics.

Key Characteristics

Example 1: Basic Usage of std::numeric_limits

#include <iostream>
#include <limits>
#include <iomanip>

int main() {
    std::cout << "Properties of int:" << std::endl;
    std::cout << "Min value: " << std::numeric_limits<int>::min() << std::endl;
    std::cout << "Max value: " << std::numeric_limits<int>::max() << std::endl;
    std::cout << "Is signed: " << std::numeric_limits<int>::is_signed << std::endl;
    std::cout << "Digits: " << std::numeric_limits<int>::digits << std::endl;

    std::cout << "\nProperties of double:" << std::endl;
    std::cout << "Min value: " << std::numeric_limits<double>::min() << std::endl;
    std::cout << "Max value: " << std::numeric_limits<double>::max() << std::endl;
    std::cout << "Epsilon: " << std::numeric_limits<double>::epsilon() << std::endl;
    std::cout << "Digits10: " << std::numeric_limits<double>::digits10 << std::endl;

    return 0;
}

Explanation:

Example 2: Checking for Special Values

#include <iostream>
#include <limits>
#include <cmath>

int main() {
    // Infinity
    if (std::numeric_limits<float>::has_infinity) {
        float pos_inf = std::numeric_limits<float>::infinity();
        float neg_inf = -std::numeric_limits<float>::infinity();
        std::cout << "Positive infinity: " << pos_inf << std::endl;
        std::cout << "Negative infinity: " << neg_inf << std::endl;
    }

    // NaN (Not a Number)
    if (std::numeric_limits<double>::has_quiet_NaN) {
        double nan = std::numeric_limits<double>::quiet_NaN();
        std::cout << "NaN: " << nan << std::endl;
        std::cout << "Is NaN: " << std::isnan(nan) << std::endl;
    }

    // Checking if a type is integer
    std::cout << "Is int integer: " << std::numeric_limits<int>::is_integer << std::endl;
    std::cout << "Is float integer: " << std::numeric_limits<float>::is_integer << std::endl;

    return 0;
}

Explanation:

Example 3: Using numeric_limits for Robust Numeric Algorithms

#include <iostream>
#include <limits>
#include <vector>
#include <algorithm>

template<typename T>
T safe_average(const std::vector<T>& numbers) {
    if (numbers.empty()) {
        return T(0);
    }

    T sum = 0;
    size_t count = 0;

    for (const T& num : numbers) {
        // Check for overflow before adding
        if (num > 0 && sum > std::numeric_limits<T>::max() - num) {
            throw std::overflow_error("Sum would overflow");
        }
        if (num < 0 && sum < std::numeric_limits<T>::min() - num) {
            throw std::underflow_error("Sum would underflow");
        }
        sum += num;
        ++count;
    }

    return sum / count;
}

int main() {
    try {
        std::vector<int> ints = {1, 2, 3, 4, 5};
        std::cout << "Average of ints: " << safe_average(ints) << std::endl;

        std::vector<double> doubles = {1.1, 2.2, 3.3, 4.4, 5.5};
        std::cout << "Average of doubles: " << safe_average(doubles) << std::endl;

        std::vector<int> large_ints = {std::numeric_limits<int>::max(), 1};
        std::cout << "Average of large ints: " << safe_average(large_ints) << std::endl;
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
    }

    return 0;
}

Explanation:

Example 4: Comparing Precision of Floating-Point Types

#include <iostream>
#include <limits>
#include <iomanip>

template<typename T>
void print_float_info() {
    std::cout << "Type: " << typeid(T).name() << std::endl;
    std::cout << "Digits10: " << std::numeric_limits<T>::digits10 << std::endl;
    std::cout << "Max exponent: " << std::numeric_limits<T>::max_exponent10 << std::endl;
    std::cout << "Epsilon: " << std::numeric_limits<T>::epsilon() << std::endl;
    std::cout << "Round error: " << std::numeric_limits<T>::round_error() << std::endl;
    std::cout << std::endl;
}

int main() {
    std::cout << std::setprecision(std::numeric_limits<long double>::digits10 + 1);

    std::cout << "Float info:" << std::endl;
    print_float_info<float>();

    std::cout << "Double info:" << std::endl;
    print_float_info<double>();

    std::cout << "Long double info:" << std::endl;
    print_float_info<long double>();

    return 0;
}

Explanation:

Example 5: Using numeric_limits for Type Traits and Compile-Time Checks

#include <iostream>
#include <limits>
#include <type_traits>

template<typename T>
void check_type_properties() {
    std::cout << "Type: " << typeid(T).name() << std::endl;
    std::cout << "Is signed: " << std::numeric_limits<T>::is_signed << std::endl;
    std::cout << "Is integer: " << std::numeric_limits<T>::is_integer << std::endl;
    std::cout << "Is exact: " << std::numeric_limits<T>::is_exact << std::endl;
    std::cout << "Has infinity: " << std::numeric_limits<T>::has_infinity << std::endl;
    std::cout << "Has quiet NaN: " << std::numeric_limits<T>::has_quiet_NaN << std::endl;
    std::cout << std::endl;
}

template<typename T>
constexpr bool is_safe_integer_cast(long long value) {
    return value >= std::numeric_limits<T>::min() && value <= std::numeric_limits<T>::max();
}

int main() {
    check_type_properties<int>();
    check_type_properties<float>();
    check_type_properties<double>();

    constexpr long long test_value = 1000000;
    std::cout << "Is " << test_value << " safely castable to int? " 
              << is_safe_integer_cast<int>(test_value) << std::endl;
    std::cout << "Is " << test_value << " safely castable to short? " 
              << is_safe_integer_cast<short>(test_value) << std::endl;

    return 0;
}

Explanation:

Additional Considerations

  1. Portability: numeric_limits provides a portable way to query type properties across different platforms and compilers.

  2. Compile-Time Constants: Most numeric_limits properties are available as compile-time constants, enabling their use in template metaprogramming and constexpr contexts.

  3. Custom Types: You can specialize numeric_limits for your own types if needed.

  4. Performance: Using numeric_limits typically has no runtime cost as most values are compile-time constants.

  5. C Compatibility: For C compatibility, you might still encounter macros from <climits> and <cfloat> in some codebases.

Summary

The <limits> header in C++ provides the std::numeric_limits class template, offering a standardized way to query the properties of arithmetic types:

Understanding and using <limits> is crucial for writing numeric algorithms that are both efficient and correct across different platforms and types. It's particularly valuable in scientific computing, financial applications, and any scenario where precise control over numeric behavior is required.

By leveraging numeric_limits, C++ programmers can write more robust, portable, and self-documenting code when dealing with arithmetic types and their limitations. This header is an essential tool for anyone working on numeric processing, low-level system programming, or any application where understanding the exact behavior of numeric types is critical.

Related

Previous Page | Course Schedule | Course Content