Numeric traits

Defined in header <Kokkos_NumericTraits.hpp> which is included from <Kokkos_Core.hpp>

Note

Numeric traits implement a facility originally proposed for the C++ standard library in P1841, following the clarifications made in P2551. Neither proposal has been adopted into the C++ standard, and there is no standard library equivalent to switch to at this time. The Kokkos namespace traits are intended for use in device code, where std::numeric_limits may not be usable.

Usage

constexpr auto inf = Kokkos::infinity<float>::value;
auto x = Kokkos::finite_min_v<float>;

Provides a replacement for std::numeric_limits from the standard library header <limits> that also works in device code, breaking the monolithic numeric_limits class template apart into individual trait templates.

Numeric traits are defined in the Kokkos namespace since Kokkos 5.2, and in the Kokkos::Experimental namespace for earlier versions.

Individual Traits

The following traits are class templates with a static constexpr value member. Each trait is only defined for the argument type(s) for which it is meaningful (floating-point or arithmetic in the tables below).

Numeric Distinguished Value Traits

Trait name

Description

Valid for

infinity

Value representing positive infinity

floating-point types

finite_min

Lowest finite value

arithmetic types

finite_max

Largest finite value

arithmetic types

epsilon

Difference between 1 and the next representable value greater than 1

floating-point types

round_error

Maximum rounding error

floating-point types

norm_min

Smallest positive normalized value

floating-point types

denorm_min

Smallest positive subnormal value, or smallest positive normalized value if subnormals are not supported

floating-point types

quiet_NaN

A quiet (non-signaling) NaN value

floating-point types

signaling_NaN

A signaling NaN value

floating-point types

Numeric Characteristics Traits

Trait name

Description

Valid for

digits

Number of radix digits that can be represented without change

arithmetic types

digits10

Number of decimal digits that can be represented without change

arithmetic types

max_digits10

Number of decimal digits needed to represent all distinct values

floating-point types

radix

Base (radix) used by the representation

arithmetic types

min_exponent

Lowest negative exponent such that radix raised to that power is a normalized value

floating-point types

min_exponent10

Lowest negative exponent such that 10 raised to that power is a normalized value

floating-point types

max_exponent

Largest positive exponent such that radix raised to that power is a representable finite value

floating-point types

max_exponent10

Largest positive exponent such that 10 raised to that power is a representable finite value

floating-point types

Variable Templates

For each trait listed above, Kokkos provides a variable template with a _v suffix. These are shorthand for the trait’s value member.

  • Kokkos::epsilon_v<T> is equivalent to Kokkos::epsilon<T>::value

  • Kokkos::infinity_v<T> is equivalent to Kokkos::infinity<T>::value

Standard Library Equivalence

Each trait mirrors a corresponding member of std::numeric_limits.

Note

Arithmetic denotes any integral or floating-point type (i.e. any type for which std::is_arithmetic_v is true), while FloatingPoint denotes any floating-point type (i.e. any type for which std::is_floating_point_v is true). These match the “Valid for” column in the tables above: the Kokkos trait is only specialized for those types. This is a deliberate difference from std::numeric_limits, which is defined for every type and silently returns a meaningless value outside its intended domain (e.g. std::numeric_limits<int>::infinity() returns 0), a source of bugs that the Kokkos traits are designed to avoid.


Notes

Important

Portability: Passing numeric traits by reference or taking their address in device code is not supported by some toolchains and hence not portable. (See known issues)

Note

Detecting specialization: Because each trait is only specialized for the types listed in its “Valid for” column, generic code can detect whether a specialization exists for a given type before using it, rather than silently falling back to a meaningless value the way std::numeric_limits does.

With C++14, the minimum standard required when numeric traits were first introduced in Kokkos, this detection takes the form of expression SFINAE against the trait’s value member, e.g.:

template <class T>
constexpr auto has_infinity(T)
        -> decltype(Kokkos::infinity<T>::value, std::true_type{}) {
    return {};
}

constexpr std::false_type has_infinity(...) { return {}; }

The Example section below builds on has_infinity to implement a device-compatible replacement for std::numeric_limits<T>::infinity().

With C++20, a requires clause combined with if constexpr offers a more direct alternative, without needing a separate detection function.


Example

template <class T>
KOKKOS_FUNCTION constexpr std::enable_if_t<has_infinity(T{}), T>
legacy_std_numeric_limits_infinity() {
    return Kokkos::infinity<T>::value;
}

template <class T>
KOKKOS_FUNCTION constexpr std::enable_if_t<!has_infinity(T{}), T>
legacy_std_numeric_limits_infinity() {
    return T();
}

With C++20:

template <class T>
KOKKOS_FUNCTION constexpr T legacy_std_numeric_limits_infinity() {
    if constexpr (requires { Kokkos::infinity<T>::value; }) {
        return Kokkos::infinity_v<T>;
    } else {
        return T();
    }
}

See also