diff --git a/docs/chrono/time_point.md b/docs/chrono/time_point.md index 4b9680f8..94c60158 100644 --- a/docs/chrono/time_point.md +++ b/docs/chrono/time_point.md @@ -191,7 +191,7 @@ ETL_NOEXCEPT ``` **Description** Rounds a duration to the nearest precision. -If the duration is exactly halfway, it rounds away from zero. +If the duration is exactly halfway, it rounds to even. ## Casting ```cpp diff --git a/docs/getting-started/macros.md b/docs/getting-started/macros.md index 23a6f37d..89a75c3d 100644 --- a/docs/getting-started/macros.md +++ b/docs/getting-started/macros.md @@ -64,6 +64,7 @@ These may be defined in the project settings or the user created `etl_profile.h` | `ETL_MESSAGES_ARE_VIRTUAL` | `ETL_MESSAGES_ARE_VIRTUAL` is deprecated and may be removed.
Only valid before 19.4.1
Messages are virtual, by default, from 19.4.1| | `ETL_USE_TYPE_TRAITS_BUILTINS` | Forces the ETL to use calls compiler built-ins.
Sets all of them to be 1 if not already defined.
If not defined `ETL_USE_BUILTIN_IS_ASSIGNABLE` then
`ETL_USE_BUILTIN_IS_ASSIGNABLE = 1`

If not defined ETL_USE_BUILTIN_IS_CONSTRUCTIBLE then
`ETL_USE_BUILTIN_IS_CONSTRUCTIBLE = 1`

If not `ETL_USE_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE` then
`ETL_USE_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE = 1`

If not defined `ETL_USE_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE` then
`ETL_USE_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE = 1`

If not defined `ETL_USE_BUILTIN_IS_TRIVIALLY_COPYABLE` then
`ETL_USE_BUILTIN_IS_TRIVIALLY_COPYABLE = 1`

`ETL_TARGET_DEVICE_GENERIC`
Only `ETL_TARGET_DEVICE_ARM_CORTEX_M0` and `ETL_TARGET_DEVICE_ARM` and `ETL_TARGET_DEVICE_ARM_CORTEX_M0_PLUS` are currently used in the ETL code to disable `etl::atomic`.| | `ETL_NO_LIBC_WCHAR_H` | Define if the libc++ used has not been compiled for `wchar_t` support.| +| `ETL_FORCE_INCLUDE_MATH_H` | When `ETL_NO_STL` is defined and the compiler is GCC or clang, the ETL does not include ``, but uses the equivalent compiler built-ins instead (GCC's `` may drag in large parts of the C++ standard library).
Define this to always include the environment's `` instead.| ## ETL defined **Defined in platform.h** diff --git a/include/etl/correlation.h b/include/etl/correlation.h index f2ffff05..1aacc7ad 100644 --- a/include/etl/correlation.h +++ b/include/etl/correlation.h @@ -33,9 +33,9 @@ SOFTWARE. #include "platform.h" #include "functional.h" +#include "math.h" #include "type_traits.h" -#include #include namespace etl @@ -254,12 +254,12 @@ namespace etl if (variance1 > 0) { - stddev1 = sqrt(variance1); + stddev1 = etl::private_math::sqrt(variance1); } if (variance2 > 0) { - stddev2 = sqrt(variance2); + stddev2 = etl::private_math::sqrt(variance2); } covariance_value = ((n * inner_product) - (sum1 * sum2)) * adjustment; diff --git a/include/etl/format.h b/include/etl/format.h index f736d025..eb7c7db5 100644 --- a/include/etl/format.h +++ b/include/etl/format.h @@ -1753,7 +1753,7 @@ namespace etl const size_t fractional_decimals = 6; // default // Detect sign using signbit to correctly handle -0.0 - bool sign = signbit(value); + bool sign = etl::private_math::sign_bit(value); T abs_value = sign ? -value : value; // Use scientific notation for values that would overflow unsigned long long @@ -1801,7 +1801,7 @@ namespace etl long long int exponent_int = 0; // Detect sign using signbit to correctly handle -0.0 - bool sign = signbit(value); + bool sign = etl::private_math::sign_bit(value); T integral; T fractional = etl::math::modf(value, &integral); @@ -1866,7 +1866,7 @@ namespace etl long long int exponent_int = 0; // Detect sign using signbit to correctly handle -0.0 - bool sign = signbit(value); + bool sign = etl::private_math::sign_bit(value); T abs_value = sign ? -value : value; @@ -1930,7 +1930,7 @@ namespace etl const size_t fractional_decimals = 6; // default // Detect sign using signbit to correctly handle -0.0 - bool sign = signbit(value); + bool sign = etl::private_math::sign_bit(value); T integral; T fractional = etl::math::modf(value, &integral); @@ -2110,7 +2110,7 @@ namespace etl template void format_floating(OutputIt& it, T value, const format_spec_t& spec) { - if (isnan(value)) + if (etl::is_nan(value)) { if (spec.type.has_value() && (is_uppercase(spec.type.value()))) { @@ -2121,7 +2121,7 @@ namespace etl format_sequence(it, "nan"); } } - else if (isinf(value)) + else if (etl::is_infinity(value)) { if (spec.type.has_value() && (is_uppercase(spec.type.value()))) { @@ -2375,7 +2375,7 @@ namespace etl if (fmt_ctx.format_spec.zero && fmt_ctx.format_spec.align == spec_align_t::NONE) { // Output sign first, then zero-fill, then the unsigned part - bool sign = signbit(arg); + bool sign = etl::private_math::sign_bit(arg); if (sign || fmt_ctx.format_spec.sign != spec_sign_t::MINUS) { // Output the sign character diff --git a/include/etl/gamma.h b/include/etl/gamma.h index 4ad83ffb..65a46958 100644 --- a/include/etl/gamma.h +++ b/include/etl/gamma.h @@ -33,10 +33,9 @@ SOFTWARE. #include "platform.h" #include "functional.h" +#include "math.h" #include "type_traits.h" -#include - namespace etl { //*************************************************************************** @@ -64,7 +63,7 @@ namespace etl { // Calculate intermediate result because rounding + optimization // lead to wrong values when returning directly (test on i386) - const double result = maximum * pow(double(value) / maximum, one_over_gamma); + const double result = maximum * etl::math::pow(double(value) / maximum, one_over_gamma); return TInput(result); } @@ -100,7 +99,7 @@ namespace etl { // Calculate intermediate result because rounding + optimization // lead to wrong values when returning directly (test on i386) - const double result = maximum * pow(double(value) / maximum, gamma); + const double result = maximum * etl::math::pow(double(value) / maximum, gamma); return TInput(result); } diff --git a/include/etl/limits.h b/include/etl/limits.h index c274a337..7d739688 100644 --- a/include/etl/limits.h +++ b/include/etl/limits.h @@ -40,9 +40,23 @@ SOFTWARE. #define __USE_C99_MATH #endif +// GCC and clang supply the floating point infinity and NaN values as compiler builtins, so +// is not required at all. +// This matters for ETL_NO_STL builds: libstdc++'s (GCC 16) includes , which in +// turn drags in large parts of the standard library ( etc.), defeating the point of a +// no-STL build. clang picks up the same when using libstdc++. +// Define ETL_FORCE_INCLUDE_MATH_H to opt out and use the environment's . +#if ETL_NOT_USING_STL && (defined(ETL_COMPILER_GCC) || defined(ETL_COMPILER_CLANG)) && !defined(ETL_FORCE_INCLUDE_MATH_H) + #define ETL_LIMITS_USING_BUILTIN_FLOAT_VALUES 1 +#else + #define ETL_LIMITS_USING_BUILTIN_FLOAT_VALUES 0 +#endif + #include #include -#include +#if !ETL_LIMITS_USING_BUILTIN_FLOAT_VALUES + #include +#endif #include "private/minmax_push.h" @@ -68,16 +82,34 @@ SOFTWARE. #define LDBL_MAX_10_EXP DBL_MAX_10_EXP #endif - #if !defined(HUGE_VAL) - // Looks like we don't have these macros defined. - // They're compiler implementation dependent, so we'll make them the same as - // the max values. - #define HUGE_VALF FLT_MAX - #define HUGE_VAL DBL_MAX - #define HUGE_VALL LDBL_MAX + #if ETL_LIMITS_USING_BUILTIN_FLOAT_VALUES + // was not included, so use the compiler builtins directly. + // HUGE_VAL etc. are deliberately not defined, as they would clash with a included later. + #define ETL_HUGE_VALF (__builtin_huge_valf()) + #define ETL_HUGE_VAL (__builtin_huge_val()) + #define ETL_HUGE_VALL (__builtin_huge_vall()) + #else + #if !defined(HUGE_VAL) + // Looks like we don't have these macros defined. + // They're compiler implementation dependent, so we'll make them the same as + // the max values. + #define HUGE_VALF FLT_MAX + #define HUGE_VAL DBL_MAX + #define HUGE_VALL LDBL_MAX + #endif + + #define ETL_HUGE_VALF HUGE_VALF + #define ETL_HUGE_VAL HUGE_VAL + #define ETL_HUGE_VALL HUGE_VALL #endif - #if defined(ETL_NO_CPP_NAN_SUPPORT) + #if ETL_LIMITS_USING_BUILTIN_FLOAT_VALUES + // The builtins need no library support, so ETL_NO_CPP_NAN_SUPPORT is irrelevant here. + #define ETL_NANF __builtin_nanf("") + #define ETL_NAN __builtin_nan("") + #define ETL_NANL __builtin_nanl("") + #define ETL_HAS_NAN true + #elif defined(ETL_NO_CPP_NAN_SUPPORT) #if defined(NAN) #include "private/diagnostic_useless_cast_push.h" #define ETL_NANF NAN @@ -87,9 +119,9 @@ SOFTWARE. #include "private/diagnostic_pop.h" #else #include "private/diagnostic_useless_cast_push.h" - #define ETL_NANF HUGE_VALF - #define ETL_NAN HUGE_VAL - #define ETL_NANL HUGE_VALL + #define ETL_NANF ETL_HUGE_VALF + #define ETL_NAN ETL_HUGE_VAL + #define ETL_NANL ETL_HUGE_VALL #define ETL_HAS_NAN false #include "private/diagnostic_pop.h" #endif @@ -1570,7 +1602,7 @@ namespace etl } static ETL_CONSTEXPR float infinity() { - return HUGE_VALF; + return ETL_HUGE_VALF; } static float round_error() { @@ -1617,7 +1649,7 @@ namespace etl } static ETL_CONSTEXPR double infinity() { - return HUGE_VAL; + return ETL_HUGE_VAL; } static double round_error() { @@ -1664,7 +1696,7 @@ namespace etl } static ETL_CONSTEXPR long double infinity() { - return HUGE_VALL; + return ETL_HUGE_VALL; } static long double round_error() { diff --git a/include/etl/math.h b/include/etl/math.h index 079b51fe..d8888cdf 100644 --- a/include/etl/math.h +++ b/include/etl/math.h @@ -38,8 +38,35 @@ SOFTWARE. #define __USE_C99_MATH #endif +// The ETL only needs floating point classification and a few elementary functions +// (sqrt, pow, floor, ceil, round, log10, modf) from . +// GCC and clang provide all of them as compiler builtins, so is not required at all. +// This matters for ETL_NO_STL builds: libstdc++'s (GCC 16) includes , which in +// turn drags in large parts of the standard library ( etc.), defeating the point of a +// no-STL build. clang picks up the same when using libstdc++. +// Define ETL_FORCE_INCLUDE_MATH_H to opt out and use the environment's . +#if ETL_NOT_USING_STL && (defined(ETL_COMPILER_GCC) || defined(ETL_COMPILER_CLANG)) && !defined(ETL_FORCE_INCLUDE_MATH_H) + #define ETL_MATH_USING_BUILTINS 1 +#else + #define ETL_MATH_USING_BUILTINS 0 +#endif + +// STL builds use , which only guarantees the functions in namespace std. +// C++03 lacks round, signbit and fpclassify, so C++03 keeps using . +#if !ETL_MATH_USING_BUILTINS && ETL_USING_STL && ETL_USING_CPP11 + #define ETL_MATH_USING_STD_CMATH 1 +#else + #define ETL_MATH_USING_STD_CMATH 0 +#endif + #include -#include +// When using the builtins, is not included and its macros (NAN, INFINITY, HUGE_VAL etc.) +// are deliberately not defined here, as they would clash with a included later. +#if ETL_MATH_USING_STD_CMATH + #include +#elif !ETL_MATH_USING_BUILTINS + #include +#endif #include "limits.h" #include "type_traits.h" @@ -49,11 +76,21 @@ namespace etl //*************************************************************************** // is_nan //*************************************************************************** -#if ETL_USING_CPP11 && !defined(ETL_NO_CPP_NAN_SUPPORT) +#if ETL_MATH_USING_BUILTINS template ETL_CONSTEXPR typename etl::enable_if::value, bool>::type is_nan(T value) { + return __builtin_isnan(value); + } +#elif ETL_USING_CPP11 && !defined(ETL_NO_CPP_NAN_SUPPORT) + template + ETL_CONSTEXPR typename etl::enable_if::value, bool>::type is_nan(T value) + { + #if ETL_MATH_USING_STD_CMATH + return std::fpclassify(value) == FP_NAN; + #else return fpclassify(value) == FP_NAN; + #endif } #else #include "private/diagnostic_float_equal_push.h" @@ -74,11 +111,21 @@ namespace etl //*************************************************************************** // is_infinity //*************************************************************************** -#if ETL_USING_CPP11 && !defined(ETL_NO_CPP_NAN_SUPPORT) +#if ETL_MATH_USING_BUILTINS template ETL_CONSTEXPR typename etl::enable_if::value, bool>::type is_infinity(T value) { + return __builtin_isinf(value); + } +#elif ETL_USING_CPP11 && !defined(ETL_NO_CPP_NAN_SUPPORT) + template + ETL_CONSTEXPR typename etl::enable_if::value, bool>::type is_infinity(T value) + { + #if ETL_MATH_USING_STD_CMATH + return std::fpclassify(value) == FP_INFINITE; + #else return fpclassify(value) == FP_INFINITE; + #endif } #else #include "private/diagnostic_float_equal_push.h" @@ -99,11 +146,24 @@ namespace etl //*************************************************************************** // is_zero //*************************************************************************** -#if ETL_USING_CPP11 && !defined(ETL_NO_CPP_NAN_SUPPORT) +#if ETL_MATH_USING_BUILTINS + // FP_ZERO means 'exactly zero', which is precisely what '== 0' tests for. + #include "private/diagnostic_float_equal_push.h" template ETL_CONSTEXPR typename etl::enable_if::value, bool>::type is_zero(T value) { + return value == 0; + } + #include "private/diagnostic_pop.h" +#elif ETL_USING_CPP11 && !defined(ETL_NO_CPP_NAN_SUPPORT) + template + ETL_CONSTEXPR typename etl::enable_if::value, bool>::type is_zero(T value) + { + #if ETL_MATH_USING_STD_CMATH + return std::fpclassify(value) == FP_ZERO; + #else return fpclassify(value) == FP_ZERO; + #endif } #else #include "private/diagnostic_float_equal_push.h" @@ -132,12 +192,31 @@ namespace etl } #include "private/diagnostic_pop.h" + //*************************************************************************** + // Selects the implementation of a C math function for float, double and long double. + // Either the compiler builtins, the overloads from or the C functions from . + //*************************************************************************** +#if ETL_MATH_USING_BUILTINS + #define ETL_MATH_FUNCTION_F(name) __builtin_##name##f + #define ETL_MATH_FUNCTION_D(name) __builtin_##name + #define ETL_MATH_FUNCTION_L(name) __builtin_##name##l +#elif ETL_MATH_USING_STD_CMATH + #define ETL_MATH_FUNCTION_F(name) std::name + #define ETL_MATH_FUNCTION_D(name) std::name + #define ETL_MATH_FUNCTION_L(name) std::name +#else + #define ETL_MATH_FUNCTION_F(name) ::name##f + #define ETL_MATH_FUNCTION_D(name) ::name + #define ETL_MATH_FUNCTION_L(name) ::name##l +#endif + //*************************************************************************** // These functions wrap the C math.h functions. // The functions are overloaded for the different floating point types. // They provide a consistent interface for float, double and long double. // They are in the `math` namespace to avoid conflicts with the C library and ETL functions. // These take the place of std::floor, std::ceil etc which may not be available `No STL` environments. + // For No-STL GCC/clang builds they use the compiler builtins, so is not required. // Avoids unpredictable behaviour for global calls of ::floor, ::ceil etc when both and are included. //*************************************************************************** namespace math @@ -148,14 +227,14 @@ namespace etl ETL_NODISCARD inline float floor(float value) ETL_NOEXCEPT { - return ::floorf(value); + return ETL_MATH_FUNCTION_F(floor)(value); } //********************************* ETL_NODISCARD inline double floor(double value) ETL_NOEXCEPT { - return ::floor(value); + return ETL_MATH_FUNCTION_D(floor)(value); } #if ETL_USING_LONG_DOUBLE_MATH @@ -163,14 +242,14 @@ namespace etl ETL_NODISCARD inline long double floor(long double value) ETL_NOEXCEPT { - return ::floorl(value); + return ETL_MATH_FUNCTION_L(floor)(value); } #else //********************************* ETL_NODISCARD inline long double floor(long double value) ETL_NOEXCEPT { - return static_cast(::floor(static_cast(value))); + return static_cast(ETL_MATH_FUNCTION_D(floor)(static_cast(value))); } #endif @@ -180,14 +259,14 @@ namespace etl ETL_NODISCARD inline float ceil(float value) ETL_NOEXCEPT { - return ::ceilf(value); + return ETL_MATH_FUNCTION_F(ceil)(value); } //********************************* ETL_NODISCARD inline double ceil(double value) ETL_NOEXCEPT { - return ::ceil(value); + return ETL_MATH_FUNCTION_D(ceil)(value); } #if ETL_USING_LONG_DOUBLE_MATH @@ -195,14 +274,14 @@ namespace etl ETL_NODISCARD inline long double ceil(long double value) ETL_NOEXCEPT { - return ::ceill(value); + return ETL_MATH_FUNCTION_L(ceil)(value); } #else //********************************* ETL_NODISCARD inline long double ceil(long double value) ETL_NOEXCEPT { - return static_cast(::ceil(static_cast(value))); + return static_cast(ETL_MATH_FUNCTION_D(ceil)(static_cast(value))); } #endif @@ -212,14 +291,14 @@ namespace etl ETL_NODISCARD inline float log10(float value) ETL_NOEXCEPT { - return ::log10f(value); + return ETL_MATH_FUNCTION_F(log10)(value); } //********************************* ETL_NODISCARD inline double log10(double value) ETL_NOEXCEPT { - return ::log10(value); + return ETL_MATH_FUNCTION_D(log10)(value); } #if ETL_USING_LONG_DOUBLE_MATH @@ -227,14 +306,14 @@ namespace etl ETL_NODISCARD inline long double log10(long double value) ETL_NOEXCEPT { - return ::log10l(value); + return ETL_MATH_FUNCTION_L(log10)(value); } #else //********************************* ETL_NODISCARD inline long double log10(long double value) ETL_NOEXCEPT { - return static_cast(::log10(static_cast(value))); + return static_cast(ETL_MATH_FUNCTION_D(log10)(static_cast(value))); } #endif @@ -244,14 +323,14 @@ namespace etl ETL_NODISCARD inline float round(float value) ETL_NOEXCEPT { - return ::roundf(value); + return ETL_MATH_FUNCTION_F(round)(value); } //********************************* ETL_NODISCARD inline double round(double value) ETL_NOEXCEPT { - return ::round(value); + return ETL_MATH_FUNCTION_D(round)(value); } #if ETL_USING_LONG_DOUBLE_MATH @@ -259,14 +338,14 @@ namespace etl ETL_NODISCARD inline long double round(long double value) ETL_NOEXCEPT { - return ::roundl(value); + return ETL_MATH_FUNCTION_L(round)(value); } #else //********************************* ETL_NODISCARD inline long double round(long double value) ETL_NOEXCEPT { - return static_cast(::round(static_cast(value))); + return static_cast(ETL_MATH_FUNCTION_D(round)(static_cast(value))); } #endif @@ -276,14 +355,14 @@ namespace etl ETL_NODISCARD inline float pow(float base, float exponent) ETL_NOEXCEPT { - return ::powf(base, exponent); + return ETL_MATH_FUNCTION_F(pow)(base, exponent); } //********************************* ETL_NODISCARD inline double pow(double base, double exponent) ETL_NOEXCEPT { - return ::pow(base, exponent); + return ETL_MATH_FUNCTION_D(pow)(base, exponent); } #if ETL_USING_LONG_DOUBLE_MATH @@ -291,14 +370,14 @@ namespace etl ETL_NODISCARD inline long double pow(long double base, long double exponent) ETL_NOEXCEPT { - return ::powl(base, exponent); + return ETL_MATH_FUNCTION_L(pow)(base, exponent); } #else //********************************* ETL_NODISCARD inline long double pow(long double base, long double exponent) ETL_NOEXCEPT { - return static_cast(::pow(static_cast(base), static_cast(exponent))); + return static_cast(ETL_MATH_FUNCTION_D(pow)(static_cast(base), static_cast(exponent))); } #endif @@ -307,33 +386,81 @@ namespace etl //*************************************************************************** inline float modf(float value, float* intpart) ETL_NOEXCEPT { - return ::modff(value, intpart); + return ETL_MATH_FUNCTION_F(modf)(value, intpart); } //********************************* inline double modf(double value, double* intpart) ETL_NOEXCEPT { - return ::modf(value, intpart); + return ETL_MATH_FUNCTION_D(modf)(value, intpart); } #if ETL_USING_LONG_DOUBLE_MATH //********************************* inline long double modf(long double value, long double* intpart) ETL_NOEXCEPT { - return ::modfl(value, intpart); + return ETL_MATH_FUNCTION_L(modf)(value, intpart); } #else //********************************* inline long double modf(long double value, long double* intpart) ETL_NOEXCEPT { double d_iptr; - double result = ::modf(static_cast(value), &d_iptr); + double result = ETL_MATH_FUNCTION_D(modf)(static_cast(value), &d_iptr); *intpart = static_cast(d_iptr); return static_cast(result); } #endif } // namespace math + + namespace private_math + { + //*************************************************************************** + // Functions used internally by the ETL. + //*************************************************************************** + inline float sqrt(float value) + { + return ETL_MATH_FUNCTION_F(sqrt)(value); + } + + //********************************* + inline double sqrt(double value) + { + return ETL_MATH_FUNCTION_D(sqrt)(value); + } + +#if ETL_USING_LONG_DOUBLE_MATH + //********************************* + inline long double sqrt(long double value) + { + return ETL_MATH_FUNCTION_L(sqrt)(value); + } +#else + //********************************* + inline long double sqrt(long double value) + { + return static_cast(ETL_MATH_FUNCTION_D(sqrt)(static_cast(value))); + } +#endif + + //********************************* + template + bool sign_bit(T value) + { +#if ETL_MATH_USING_BUILTINS + return __builtin_signbit(value); +#elif ETL_MATH_USING_STD_CMATH + return std::signbit(value); +#else + return signbit(value); +#endif + } + } // namespace private_math + +#undef ETL_MATH_FUNCTION_F +#undef ETL_MATH_FUNCTION_D +#undef ETL_MATH_FUNCTION_L } // namespace etl #endif diff --git a/include/etl/numeric.h b/include/etl/numeric.h index 7e740839..b5c4f67c 100644 --- a/include/etl/numeric.h +++ b/include/etl/numeric.h @@ -32,6 +32,7 @@ SOFTWARE. #define ETL_NUMERIC_INCLUDED #include "platform.h" +#include "absolute.h" #include "iterator.h" #include "limits.h" #include "type_traits.h" @@ -74,10 +75,10 @@ namespace etl T lo = etl::numeric_limits::min() * T(2); T hi = etl::numeric_limits::max() * T(2); - return ((abs(a) <= hi) && (abs(b) <= hi)) ? (a + b) / T(2) - : (abs(a) < lo) ? a + (b / T(2)) - : (abs(b) < lo) ? ((a / T(2)) + b) - : (a / T(2)) + (b / T(2)); + return ((etl::absolute(a) <= hi) && (etl::absolute(b) <= hi)) ? (a + b) / T(2) + : (etl::absolute(a) < lo) ? a + (b / T(2)) + : (etl::absolute(b) < lo) ? ((a / T(2)) + b) + : (a / T(2)) + (b / T(2)); } //*************************************************************************** diff --git a/include/etl/private/chrono/duration.h b/include/etl/private/chrono/duration.h index fc0b6cb3..dd53a856 100644 --- a/include/etl/private/chrono/duration.h +++ b/include/etl/private/chrono/duration.h @@ -372,6 +372,79 @@ namespace etl return TToDuration(static_cast((ct_count * ct_num) / ct_den)); } } + + //*********************************************************************** + /// Rounds down a duration to the nearest lower precision. + //*********************************************************************** + template + ETL_NODISCARD ETL_CONSTEXPR14 typename etl::enable_if::value, TToDuration>::type + floor(const etl::chrono::duration& d) ETL_NOEXCEPT + { + TToDuration result = etl::chrono::duration_cast(d); + + if (result > d) + { + --result; + } + + return result; + } + + //*********************************************************************** + /// Rounds up a duration to the nearest higher precision. + //*********************************************************************** + template + ETL_NODISCARD ETL_CONSTEXPR14 typename etl::enable_if::value, TToDuration>::type + ceil(const etl::chrono::duration& d) ETL_NOEXCEPT + { + TToDuration result = etl::chrono::duration_cast(d); + + if (result < d) + { + ++result; + } + + return result; + } + + //*********************************************************************** + /// Rounds a duration to the nearest precision. + /// If the duration is exactly halfway, it rounds to even. + //*********************************************************************** + template + ETL_NODISCARD ETL_CONSTEXPR14 typename etl::enable_if::value, TToDuration>::type + round(const etl::chrono::duration& d) ETL_NOEXCEPT + { + TToDuration lower = etl::chrono::floor(d); + + if (lower == d) + { + return lower; + } + + TToDuration upper = lower + TToDuration(1); + + typename etl::common_type >::type lower_diff = d - lower; + typename etl::common_type >::type upper_diff = upper - d; + + if ((lower_diff < upper_diff) || ((lower_diff == upper_diff) && etl::is_even(lower.count()))) + { + return lower; + } + else + { + return upper; + } + } + + //*********************************************************************** + /// Returns the absolute value of a duration. + //*********************************************************************** + template ::is_signed> > + ETL_NODISCARD ETL_CONSTEXPR14 etl::chrono::duration abs(etl::chrono::duration d) ETL_NOEXCEPT + { + return d.count() >= 0 ? +d : -d; + } } // namespace chrono //************************************************************************* @@ -651,74 +724,6 @@ namespace etl return common_duration(lhs_converted.count() % rhs_converted.count()); } - - //*********************************************************************** - /// Rounds down a duration to the nearest lower precision. - //*********************************************************************** - template - ETL_CONSTEXPR14 typename etl::enable_if< etl::is_specialization::value, TToDuration>::type - floor(const etl::chrono::duration& d) ETL_NOEXCEPT - { - TToDuration result = etl::chrono::duration_cast(d); - - if (result > d) - { - --result; - } - - return result; - } - - //*********************************************************************** - /// Rounds up a duration to the nearest higher precision. - //*********************************************************************** - template - ETL_CONSTEXPR14 typename etl::enable_if< etl::is_specialization::value, TToDuration>::type - ceil(const etl::chrono::duration& d) ETL_NOEXCEPT - { - TToDuration result = etl::chrono::duration_cast(d); - - if (result < d) - { - ++result; - } - - return result; - } - - //*********************************************************************** - /// Rounds a duration to the nearest precision. - /// If the duration is exactly halfway, it rounds away from zero. - //*********************************************************************** - template - ETL_CONSTEXPR14 typename etl::enable_if< etl::is_specialization::value, TToDuration>::type - round(const etl::chrono::duration& d) ETL_NOEXCEPT - { - // Convert the input duration to the target duration type - TToDuration lower = floor(d); - TToDuration upper = ceil(lower + TToDuration(1)); - - auto lower_diff = d - lower; - auto upper_diff = upper - d; - - if ((lower_diff < upper_diff) || ((lower_diff == upper_diff) && etl::is_even(lower.count()))) - { - return lower; - } - else - { - return upper; - } - } - - //*********************************************************************** - /// Returns the absolute value of a duration. - //*********************************************************************** - template ::is_signed>> - ETL_CONSTEXPR14 etl::chrono::duration abs(etl::chrono::duration d) ETL_NOEXCEPT - { - return d.count() >= 0 ? +d : -d; - } } // namespace etl #if ETL_HAS_CHRONO_LITERALS_DURATION diff --git a/include/etl/private/chrono/time_point.h b/include/etl/private/chrono/time_point.h index f90f1c61..95a00265 100644 --- a/include/etl/private/chrono/time_point.h +++ b/include/etl/private/chrono/time_point.h @@ -224,7 +224,7 @@ namespace etl //*********************************************************************** /// Rounds a duration to the nearest precision. - /// If the duration is exactly halfway, it rounds away from zero. + /// If the duration is exactly halfway, it rounds to even. //*********************************************************************** template ETL_NODISCARD ETL_CONSTEXPR14 etl::chrono::time_point round(const etl::chrono::time_point& tp) diff --git a/include/etl/private/to_string_helper.h b/include/etl/private/to_string_helper.h index 4baaaf76..f19f58dd 100644 --- a/include/etl/private/to_string_helper.h +++ b/include/etl/private/to_string_helper.h @@ -406,7 +406,7 @@ namespace etl uworkspace_t integral = static_cast(f_integral); // Find the fractional part of the floating point. - uworkspace_t fractional = static_cast(::round((etl::absolute(value) - f_integral) * multiplier)); + uworkspace_t fractional = static_cast(etl::math::round((etl::absolute(value) - f_integral) * multiplier)); // Check for a rounding carry to the integral. if (fractional == multiplier) @@ -434,9 +434,9 @@ namespace etl iterator start = str.end(); - if (isnan(value) || isinf(value)) + if (etl::is_nan(value) || etl::is_infinity(value)) { - etl::private_to_string::add_nan_inf(isnan(value), isinf(value), etl::is_negative(value), str, format); + etl::private_to_string::add_nan_inf(etl::is_nan(value), etl::is_infinity(value), etl::is_negative(value), str, format); } else { diff --git a/include/etl/rms.h b/include/etl/rms.h index a6b3997e..d43a99fe 100644 --- a/include/etl/rms.h +++ b/include/etl/rms.h @@ -33,9 +33,9 @@ SOFTWARE. #include "platform.h" #include "functional.h" +#include "math.h" #include "type_traits.h" -#include #include namespace etl @@ -162,7 +162,7 @@ namespace etl if (mean_of_squares > 0) { - rms_value = sqrt(mean_of_squares); + rms_value = etl::private_math::sqrt(mean_of_squares); } } diff --git a/include/etl/standard_deviation.h b/include/etl/standard_deviation.h index ef600560..641e2270 100644 --- a/include/etl/standard_deviation.h +++ b/include/etl/standard_deviation.h @@ -33,9 +33,9 @@ SOFTWARE. #include "platform.h" #include "functional.h" +#include "math.h" #include "type_traits.h" -#include #include namespace etl @@ -242,7 +242,7 @@ namespace etl if (variance_value > 0) { - standard_deviation_value = sqrt(variance_value); + standard_deviation_value = etl::private_math::sqrt(variance_value); } } diff --git a/include/etl/to_arithmetic.h b/include/etl/to_arithmetic.h index bba59f88..2f4b44b7 100644 --- a/include/etl/to_arithmetic.h +++ b/include/etl/to_arithmetic.h @@ -46,8 +46,6 @@ SOFTWARE. #include "string_view.h" #include "type_traits.h" -#include - namespace etl { //*************************************************************************** @@ -847,7 +845,7 @@ namespace etl TValue value = static_cast(accumulator.value()); int exponent = accumulator.exponent(); - value *= pow(static_cast(10.0), static_cast(exponent)); + value *= etl::math::pow(static_cast(10.0), static_cast(exponent)); // Check that the result is a valid floating point number. if (etl::is_infinity(value)) diff --git a/test/test_chrono_duration.cpp b/test/test_chrono_duration.cpp index 1372d6f6..5f10d169 100644 --- a/test/test_chrono_duration.cpp +++ b/test/test_chrono_duration.cpp @@ -1099,40 +1099,40 @@ namespace //************************************************************************* TEST(test_floor) { - Chrono::milliseconds ms(1234); // 1234 milliseconds - Chrono::seconds s = floor(ms); // Floor to seconds + Chrono::milliseconds ms(1234); // 1234 milliseconds + Chrono::seconds s = Chrono::floor(ms); // Floor to seconds CHECK_EQUAL(1, s.count()); - Chrono::milliseconds negative_ms(-1234); // -1234 milliseconds - Chrono::seconds negative_s = floor(negative_ms); // Floor to seconds + Chrono::milliseconds negative_ms(-1234); // -1234 milliseconds + Chrono::seconds negative_s = Chrono::floor(negative_ms); // Floor to seconds CHECK_EQUAL(-2, negative_s.count()); } //************************************************************************* TEST(test_ceil) { - Chrono::milliseconds ms(1234); // 1234 milliseconds - Chrono::seconds s = ceil(ms); // Ceil to seconds + Chrono::milliseconds ms(1234); // 1234 milliseconds + Chrono::seconds s = Chrono::ceil(ms); // Ceil to seconds CHECK_EQUAL(2, s.count()); - Chrono::milliseconds negative_ms(-1234); // -1234 milliseconds - Chrono::seconds negative_s = ceil(negative_ms); // Ceil to seconds + Chrono::milliseconds negative_ms(-1234); // -1234 milliseconds + Chrono::seconds negative_s = Chrono::ceil(negative_ms); // Ceil to seconds CHECK_EQUAL(-1, negative_s.count()); } //************************************************************************* TEST(test_round) { - Chrono::milliseconds ms(1500); // 1500 milliseconds - Chrono::seconds s = round(ms); // Round to seconds + Chrono::milliseconds ms(1500); // 1500 milliseconds + Chrono::seconds s = Chrono::round(ms); // Round to seconds CHECK_EQUAL(2, s.count()); - Chrono::milliseconds ms_halfway(2500); // 2500 milliseconds - Chrono::seconds s_halfway = round(ms_halfway); // Round to seconds + Chrono::milliseconds ms_halfway(2500); // 2500 milliseconds + Chrono::seconds s_halfway = Chrono::round(ms_halfway); // Round to seconds CHECK_EQUAL(2, s_halfway.count()); - Chrono::milliseconds negative_ms(-1500); // -1500 milliseconds - Chrono::seconds negative_s = round(negative_ms); // Round to seconds + Chrono::milliseconds negative_ms(-1500); // -1500 milliseconds + Chrono::seconds negative_s = Chrono::round(negative_ms); // Round to seconds CHECK_EQUAL(-2, negative_s.count()); } diff --git a/test/test_chrono_time_point.cpp b/test/test_chrono_time_point.cpp index 89a00227..42e2341e 100644 --- a/test/test_chrono_time_point.cpp +++ b/test/test_chrono_time_point.cpp @@ -399,11 +399,11 @@ namespace using TimePoint = Chrono::time_point; TimePoint tp(Chrono::milliseconds(1234)); // 1234 milliseconds - auto floored_tp = floor(tp); + auto floored_tp = Chrono::floor(tp); CHECK_EQUAL(1, floored_tp.time_since_epoch().count()); TimePoint negative_tp(Chrono::milliseconds(-1234)); // -1234 milliseconds - auto floored_negative_tp = floor(negative_tp); + auto floored_negative_tp = Chrono::floor(negative_tp); CHECK_EQUAL(-2, floored_negative_tp.time_since_epoch().count()); } @@ -413,11 +413,11 @@ namespace using TimePoint = Chrono::time_point; TimePoint tp(Chrono::milliseconds(1234)); // 1234 milliseconds - auto ceil_tp = ceil(tp); + auto ceil_tp = Chrono::ceil(tp); CHECK_EQUAL(2, ceil_tp.time_since_epoch().count()); TimePoint negative_tp(Chrono::milliseconds(-1234)); // -1234 milliseconds - auto ceil_negative_tp = ceil(negative_tp); + auto ceil_negative_tp = Chrono::ceil(negative_tp); CHECK_EQUAL(-1, ceil_negative_tp.time_since_epoch().count()); } @@ -426,16 +426,16 @@ namespace { using TimePoint = Chrono::time_point; - TimePoint tp1(Chrono::milliseconds(1500)); // 1500 milliseconds - auto round1 = round(tp1); // Round to seconds + TimePoint tp1(Chrono::milliseconds(1500)); // 1500 milliseconds + auto round1 = Chrono::round(tp1); // Round to seconds CHECK_EQUAL(2, round1.time_since_epoch().count()); - TimePoint tp2(Chrono::milliseconds(2500)); // 2500 milliseconds - auto round2 = round(tp2); // Round to seconds + TimePoint tp2(Chrono::milliseconds(2500)); // 2500 milliseconds + auto round2 = Chrono::round(tp2); // Round to seconds CHECK_EQUAL(2, round2.time_since_epoch().count()); - TimePoint tp3(Chrono::milliseconds(-1500)); // -1500 milliseconds - auto round3 = round(tp3); // Round to seconds + TimePoint tp3(Chrono::milliseconds(-1500)); // -1500 milliseconds + auto round3 = Chrono::round(tp3); // Round to seconds CHECK_EQUAL(-2, round3.time_since_epoch().count()); } diff --git a/test/test_format.cpp b/test/test_format.cpp index bfd4c848..50750647 100644 --- a/test/test_format.cpp +++ b/test/test_format.cpp @@ -32,6 +32,8 @@ SOFTWARE. #include "etl/iterator.h" +#include + #if ETL_USING_CPP11 namespace diff --git a/test/test_limits.cpp b/test/test_limits.cpp index 36cff19f..b6c9a82c 100644 --- a/test/test_limits.cpp +++ b/test/test_limits.cpp @@ -29,6 +29,7 @@ SOFTWARE. #include "unit_test_framework.h" #include "etl/limits.h" +#include #include namespace @@ -675,6 +676,16 @@ namespace CHECK_EQUAL(STD_NL::min_exponent10, ETL_NL::min_exponent10); CHECK_EQUAL(STD_NL::radix, ETL_NL::radix); CHECK_EQUAL(STD_NL::round_error(), ETL_NL::round_error()); + CHECK_EQUAL(STD_NL::has_infinity, ETL_NL::has_infinity); + CHECK_EQUAL(STD_NL::has_quiet_NaN, ETL_NL::has_quiet_NaN); + CHECK_EQUAL(STD_NL::has_signaling_NaN, ETL_NL::has_signaling_NaN); + CHECK_EQUAL(STD_NL::infinity(), ETL_NL::infinity()); + CHECK_EQUAL(-STD_NL::infinity(), -ETL_NL::infinity()); + CHECK_TRUE(ETL_NL::infinity() > ETL_NL::max()); + CHECK_TRUE(std::isinf(ETL_NL::infinity())); + CHECK_FALSE(std::signbit(ETL_NL::infinity())); + CHECK_TRUE(std::isnan(ETL_NL::quiet_NaN())); + CHECK_TRUE(std::isnan(ETL_NL::signaling_NaN())); } //************************************************************************* @@ -702,6 +713,16 @@ namespace CHECK_EQUAL(STD_NL::min_exponent10, ETL_NL::min_exponent10); CHECK_EQUAL(STD_NL::radix, ETL_NL::radix); CHECK_EQUAL(STD_NL::round_error(), ETL_NL::round_error()); + CHECK_EQUAL(STD_NL::has_infinity, ETL_NL::has_infinity); + CHECK_EQUAL(STD_NL::has_quiet_NaN, ETL_NL::has_quiet_NaN); + CHECK_EQUAL(STD_NL::has_signaling_NaN, ETL_NL::has_signaling_NaN); + CHECK_EQUAL(STD_NL::infinity(), ETL_NL::infinity()); + CHECK_EQUAL(-STD_NL::infinity(), -ETL_NL::infinity()); + CHECK_TRUE(ETL_NL::infinity() > ETL_NL::max()); + CHECK_TRUE(std::isinf(ETL_NL::infinity())); + CHECK_FALSE(std::signbit(ETL_NL::infinity())); + CHECK_TRUE(std::isnan(ETL_NL::quiet_NaN())); + CHECK_TRUE(std::isnan(ETL_NL::signaling_NaN())); } //************************************************************************* @@ -729,6 +750,16 @@ namespace CHECK_EQUAL(STD_NL::min_exponent10, ETL_NL::min_exponent10); CHECK_EQUAL(STD_NL::radix, ETL_NL::radix); CHECK_EQUAL(STD_NL::round_error(), ETL_NL::round_error()); + CHECK_EQUAL(STD_NL::has_infinity, ETL_NL::has_infinity); + CHECK_EQUAL(STD_NL::has_quiet_NaN, ETL_NL::has_quiet_NaN); + CHECK_EQUAL(STD_NL::has_signaling_NaN, ETL_NL::has_signaling_NaN); + CHECK_EQUAL(STD_NL::infinity(), ETL_NL::infinity()); + CHECK_EQUAL(-STD_NL::infinity(), -ETL_NL::infinity()); + CHECK_TRUE(ETL_NL::infinity() > ETL_NL::max()); + CHECK_TRUE(std::isinf(ETL_NL::infinity())); + CHECK_FALSE(std::signbit(ETL_NL::infinity())); + CHECK_TRUE(std::isnan(ETL_NL::quiet_NaN())); + CHECK_TRUE(std::isnan(ETL_NL::signaling_NaN())); } } } // namespace diff --git a/test/test_math.cpp b/test/test_math.cpp index 2592d7db..772c16b8 100644 --- a/test/test_math.cpp +++ b/test/test_math.cpp @@ -30,11 +30,162 @@ SOFTWARE. #include "etl/math.h" +#include +#include #include #include namespace { + //*************************************************************************** + template + void check_classification_of_special_values() + { + typedef std::numeric_limits STD_NL; + + const T nan = STD_NL::quiet_NaN(); + const T negative_nan = std::copysign(STD_NL::quiet_NaN(), T(-1)); + const T inf = STD_NL::infinity(); + const T zero = T(0); + const T negative_zero = -T(0); + const T denorm = STD_NL::denorm_min(); + const T min_value = STD_NL::min(); + const T max_value = STD_NL::max(); + const T lowest_value = STD_NL::lowest(); + + // is_nan + CHECK_TRUE(etl::is_nan(nan)); + CHECK_TRUE(etl::is_nan(negative_nan)); + CHECK_TRUE(etl::is_nan(STD_NL::signaling_NaN())); + CHECK_FALSE(etl::is_nan(inf)); + CHECK_FALSE(etl::is_nan(-inf)); + CHECK_FALSE(etl::is_nan(zero)); + CHECK_FALSE(etl::is_nan(negative_zero)); + CHECK_FALSE(etl::is_nan(denorm)); + CHECK_FALSE(etl::is_nan(max_value)); + CHECK_FALSE(etl::is_nan(lowest_value)); + + // is_infinity + CHECK_TRUE(etl::is_infinity(inf)); + CHECK_TRUE(etl::is_infinity(-inf)); + CHECK_FALSE(etl::is_infinity(nan)); + CHECK_FALSE(etl::is_infinity(negative_nan)); + CHECK_FALSE(etl::is_infinity(zero)); + CHECK_FALSE(etl::is_infinity(denorm)); + CHECK_FALSE(etl::is_infinity(max_value)); + CHECK_FALSE(etl::is_infinity(lowest_value)); + + // is_zero + CHECK_TRUE(etl::is_zero(zero)); + CHECK_TRUE(etl::is_zero(negative_zero)); + CHECK_FALSE(etl::is_zero(denorm)); + CHECK_FALSE(etl::is_zero(-denorm)); + CHECK_FALSE(etl::is_zero(min_value)); + CHECK_FALSE(etl::is_zero(nan)); + CHECK_FALSE(etl::is_zero(inf)); + CHECK_FALSE(etl::is_zero(-inf)); + } + + //*************************************************************************** + template + void check_math_functions() + { + typedef std::numeric_limits STD_NL; + + const T inf = STD_NL::infinity(); + const T tolerance = T(1e-5); + + // The overload for the exact floating point type must be selected. + CHECK_TRUE((std::is_same::value)); + CHECK_TRUE((std::is_same::value)); + CHECK_TRUE((std::is_same::value)); + CHECK_TRUE((std::is_same::value)); + CHECK_TRUE((std::is_same::value)); + CHECK_TRUE((std::is_same::value)); + CHECK_TRUE((std::is_same(ETL_NULLPTR)))>::value)); + + // sqrt + CHECK_EQUAL(T(2), etl::private_math::sqrt(T(4))); + CHECK_CLOSE(T(1.41421356), etl::private_math::sqrt(T(2)), tolerance); + CHECK_TRUE(etl::private_math::sign_bit(etl::private_math::sqrt(-T(0)))); + CHECK_TRUE(etl::is_nan(etl::private_math::sqrt(T(-1)))); + CHECK_TRUE(etl::is_infinity(etl::private_math::sqrt(inf))); + + // pow + CHECK_EQUAL(T(1024), etl::math::pow(T(2), T(10))); + CHECK_EQUAL(T(1), etl::math::pow(T(123.456), T(0))); + CHECK_CLOSE(T(0.01), etl::math::pow(T(10), T(-2)), tolerance); + CHECK_CLOSE(T(2), etl::math::pow(T(4), T(0.5)), tolerance); + + // floor + CHECK_EQUAL(T(1), etl::math::floor(T(1.5))); + CHECK_EQUAL(T(2), etl::math::floor(T(2))); + CHECK_EQUAL(T(-2), etl::math::floor(T(-1.5))); + CHECK_EQUAL(T(-1), etl::math::floor(T(-0.5))); + CHECK_TRUE(etl::private_math::sign_bit(etl::math::floor(-T(0)))); + + // round: halfway cases round away from zero. + CHECK_EQUAL(T(3), etl::math::round(T(2.5))); + CHECK_EQUAL(T(-3), etl::math::round(T(-2.5))); + CHECK_EQUAL(T(1), etl::math::round(T(0.5))); + CHECK_EQUAL(T(-1), etl::math::round(T(-0.5))); + CHECK_EQUAL(T(1), etl::math::round(T(1.4999))); + CHECK_TRUE(etl::is_zero(etl::math::round(T(-0.4)))); + CHECK_TRUE(etl::private_math::sign_bit(etl::math::round(T(-0.4)))); + + // log10 + CHECK_EQUAL(T(0), etl::math::log10(T(1))); + CHECK_CLOSE(T(3), etl::math::log10(T(1000)), tolerance); + CHECK_CLOSE(T(-3), etl::math::log10(T(0.001)), tolerance); + CHECK_TRUE(etl::is_infinity(etl::math::log10(T(0)))); + CHECK_TRUE(etl::private_math::sign_bit(etl::math::log10(T(0)))); + CHECK_TRUE(etl::is_nan(etl::math::log10(T(-1)))); + + // modf + T integral = T(0); + T fractional = etl::math::modf(T(3.75), &integral); + CHECK_EQUAL(T(3), integral); + CHECK_EQUAL(T(0.75), fractional); + + fractional = etl::math::modf(T(-1.25), &integral); + CHECK_EQUAL(T(-1), integral); + CHECK_EQUAL(T(-0.25), fractional); + + fractional = etl::math::modf(T(5), &integral); + CHECK_EQUAL(T(5), integral); + CHECK_TRUE(etl::is_zero(fractional)); + CHECK_FALSE(etl::private_math::sign_bit(fractional)); + + fractional = etl::math::modf(-inf, &integral); + CHECK_TRUE(etl::is_infinity(integral)); + CHECK_TRUE(etl::private_math::sign_bit(integral)); + CHECK_TRUE(etl::is_zero(fractional)); + CHECK_TRUE(etl::private_math::sign_bit(fractional)); + + // sign_bit + CHECK_FALSE(etl::private_math::sign_bit(T(0))); + CHECK_TRUE(etl::private_math::sign_bit(-T(0))); + CHECK_FALSE(etl::private_math::sign_bit(T(1))); + CHECK_TRUE(etl::private_math::sign_bit(T(-1))); + CHECK_FALSE(etl::private_math::sign_bit(inf)); + CHECK_TRUE(etl::private_math::sign_bit(-inf)); + CHECK_FALSE(etl::private_math::sign_bit(STD_NL::denorm_min())); + CHECK_TRUE(etl::private_math::sign_bit(-STD_NL::denorm_min())); + CHECK_FALSE(etl::private_math::sign_bit(std::copysign(STD_NL::quiet_NaN(), T(1)))); + CHECK_TRUE(etl::private_math::sign_bit(std::copysign(STD_NL::quiet_NaN(), T(-1)))); + } + +#if ETL_MATH_USING_BUILTINS + // The builtin based classification functions must remain usable in constant expressions. + static_assert(etl::is_nan(__builtin_nan("")), "is_nan must be constexpr"); + static_assert(!etl::is_nan(1.0), "is_nan must be constexpr"); + static_assert(etl::is_infinity(etl::numeric_limits::infinity()), "is_infinity must be constexpr"); + static_assert(etl::is_infinity(-etl::numeric_limits::infinity()), "is_infinity must be constexpr"); + static_assert(!etl::is_infinity(etl::numeric_limits::max()), "is_infinity must be constexpr"); + static_assert(etl::is_zero(-0.0), "is_zero must be constexpr"); + static_assert(!etl::is_zero(etl::numeric_limits::min()), "is_zero must be constexpr"); +#endif + SUITE(test_math) { //************************************************************************* @@ -245,5 +396,41 @@ namespace CHECK_CLOSE((double)3.0L, (double)ld_intpart, 0.0001); CHECK_CLOSE((double)0.75L, (double)ld_frac, 0.0001); } + + //************************************************************************* + TEST(test_classification_of_special_values_float) + { + check_classification_of_special_values(); + } + + //************************************************************************* + TEST(test_classification_of_special_values_double) + { + check_classification_of_special_values(); + } + + //************************************************************************* + TEST(test_classification_of_special_values_long_double) + { + check_classification_of_special_values(); + } + + //************************************************************************* + TEST(test_math_functions_float) + { + check_math_functions(); + } + + //************************************************************************* + TEST(test_math_functions_double) + { + check_math_functions(); + } + + //************************************************************************* + TEST(test_math_functions_long_double) + { + check_math_functions(); + } } } // namespace