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 |
|---|---|---|
|
Value representing positive infinity |
floating-point types |
|
Lowest finite value |
arithmetic types |
|
Largest finite value |
arithmetic types |
|
Difference between 1 and the next representable value greater than 1 |
floating-point types |
|
Maximum rounding error |
floating-point types |
|
Smallest positive normalized value |
floating-point types |
|
Smallest positive subnormal value, or smallest positive normalized value if subnormals are not supported |
floating-point types |
|
A quiet (non-signaling) NaN value |
floating-point types |
|
A signaling NaN value |
floating-point types |
Numeric Characteristics Traits¶
Trait name |
Description |
Valid for |
|---|---|---|
|
Number of radix digits that can be represented without change |
arithmetic types |
|
Number of decimal digits that can be represented without change |
arithmetic types |
|
Number of decimal digits needed to represent all distinct values |
floating-point types |
|
Base (radix) used by the representation |
arithmetic types |
|
Lowest negative exponent such that |
floating-point types |
|
Lowest negative exponent such that 10 raised to that power is a normalized value |
floating-point types |
|
Largest positive exponent such that |
floating-point types |
|
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 toKokkos::epsilon<T>::valueKokkos::infinity_v<T>is equivalent toKokkos::infinity<T>::value
Standard Library Equivalence¶
Each trait mirrors a corresponding member of std::numeric_limits.
Trait name |
Equivalent to |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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();
}
}