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