Skip to main content

math Namespace

Internal mathematical utilities for the µTest++ testing framework. More...

Definition​

namespace micro_os_plus::micro_test_plus::detail::math { ... }

Classes Index​

structinteger_literal

The result of parsing the characters of an integer literal. More...

Functions Index​

template <class T>
constexpr Tabs (const T t) noexcept

Computes the absolute value of a given comparable value. More...

template <class T, class Value_T>
constexpr Tcount_decimals (Value_T value)

Computes the number of decimal places of a value, with a precision of about seven digits. More...

template <bool Fraction, char... Cs>
std::size_tcount_literal_digits (void)

Counts the decimal digits of a floating-point literal, before or after the decimal point. More...

template <class Value_T>
constexpr Value_Tdecimal_epsilon (Value_T value)

Computes the default comparison tolerance of a floating-point value, one unit of its last decimal. More...

template <class T, char... Cs>
Tden (void)

Computes the decimal part of a number represented as an array of characters. More...

template <class T, char... Cs>
Tden_size (void)

Counts the decimal places of a number represented as an array of characters. More...

template <class T, char... Cs>
unsigned long longinteger_magnitude (void)

Computes the value of an integer literal of type T, before any negation. More...

template <class T>
constexpr const T &min_value (const T &lhs, const T &rhs) noexcept

Computes the minimum of two comparable values. More...

template <class T, char... Cs>
Tnum (void)

Computes the integral part of a decimal floating-point number represented as an array of characters. More...

template <char... Cs>
integer_literalparse_integer_literal (void)

Parses the characters of an integer literal. More...

template <class T, class Exp_T>
constexpr Tpow (const T base, const Exp_T exp) noexcept

Generic exponentiation function to compute the power of a base raised to an exponent. More...

Description​

Internal mathematical utilities for the µTest++ testing framework.

The detail::math namespace offers a suite of constexpr mathematical function templates and utilities, used by the literals and by the floating-point comparisons of the µTest++ framework.

These functions include generic implementations for absolute value, minimum value, exponentiation, and compile-time parsing of numeric values from character arrays. The utilities are designed to be lightweight and suitable for embedded environments, where standard library alternatives may be unavailable, less efficient, or not constexpr.

The names of these functions suggest general mathematical functions, but their scope is limited to the needs of the framework (for example, pow() accepts only integral exponents); like everything in detail, they are not part of the public API and may be modified without prior notice.

Functions​

abs()​

template <class T>
T micro_os_plus::micro_test_plus::detail::math::abs (const T t)
nodiscard constexpr noexcept

Computes the absolute value of a given comparable value.

This function template provides a generic, constexpr implementation for obtaining the absolute value of any type that supports comparison and unary negation.

The function returns the non-negative value of the input. If the input is less than the default-constructed value of its type (typically zero), the negated value is returned; otherwise, the original value is returned.

Template Parameters
T

The type of the input value. Must support comparison and unary negation.

Parameters
t

The value for which the absolute value is to be computed.

Returns

The absolute value of the input.

Definition at line 88 of file math-inlines.h.

88 abs (const T t) noexcept -> T
89 {
90 return t < T{} ? -t : t;
91 }

Reference abs.

Referenced by abs, count_decimals, micro_os_plus::micro_test_plus::detail::differ_by_at_most and micro_os_plus::micro_test_plus::detail::within_tolerance.

count_decimals()​

template <class T, class Value_T>
T micro_os_plus::micro_test_plus::detail::math::count_decimals (Value_T value)
nodiscard constexpr

Computes the number of decimal places of a value, with a precision of about seven digits.

Template Parameters
T

The integral type for the result.

Value_T

The type of the input value, a floating-point type.

Parameters
value

The value whose decimal precision is to be determined; it may be negative, infinite, or a NaN.

Returns

The number of decimal places, as a value of type T, at least one, or zero for a zero value; the leading zeros of a value below one are counted; it is limited by the magnitude from which Value_T represents only integers.

This function template determines the number of decimal (fractional) digits present in a floating-point value, with a precision of about seven digits. Being constexpr, it can also be evaluated at compile time.

The function repeatedly multiplies the absolute value by ten, incrementing a counter until the distance to the nearest integer is at most a defined precision threshold (1e-7). Using the distance to the nearest integer, not the fractional part, prevents the rounding noise of a value just below an integer (e.g. 2674.9999999999995) from being taken as more decimals.

The nearest integer is never zero: while the scaled value is below one, its distance to one is used, so that the leading zeros of a small value are counted as decimals, as in its notation (12 for 1e-12), instead of the count stopping as soon as the scaled value is below the threshold. A zero value has no significant digit, and the result is zero.

The loop also stops when the value reaches the magnitude from which the type can represent only integers (2^23 for float, 2^52 for double), limited to 2^63 so that the conversion to unsigned long long is always defined. This bounds the number of steps for large values, infinities, and NaNs, for which the result is one; for small values, the number of steps is bounded by the decimal exponent of the smallest value of the type.

Definition at line 258 of file deprecated-inlines.h.

258 count_decimals (Value_T value) -> T
259 {
260 constexpr auto precision = Value_T (1e-7);
261 // From this magnitude upwards all values are integers.
262 constexpr auto integral_limit
263 = min_value (Value_T (1) / std::numeric_limits<Value_T>::epsilon (),
264 Value_T (1ULL << 63));
265
266 value = abs (value);
267
268#if defined(__GNUC__)
269#pragma GCC diagnostic push
270#pragma GCC diagnostic ignored "-Wfloat-equal"
271#endif // defined(__GNUC__)
272 if (value == Value_T (0))
273 {
274 // A zero has no decimals.
275 return T{};
276 }
277#if defined(__GNUC__)
278#pragma GCC diagnostic pop
279#endif // defined(__GNUC__)
280
281 T result{};
282 for (;;)
283 {
284 value *= 10;
285 ++result;
286
287 // Also true for infinities and NaNs.
288 if (not(value < integral_limit))
289 {
290 break;
291 }
292
293 const auto fraction = value
294 - static_cast<Value_T> (
295 static_cast<unsigned long long> (value));
296 // Below one, the distance is to one, not to zero, so that the
297 // leading zeros of a small value are counted.
298 const auto distance
299 = (value < Value_T (1))
300 ? Value_T (1) - fraction
301 : min_value (fraction, Value_T (1) - fraction);
302 if (distance <= precision)
303 {
304 break;
305 }
306 }
307
308 return result;
309 }

References abs, count_decimals and min_value.

Referenced by count_decimals and decimal_epsilon.

count_literal_digits()​

template <bool Fraction, char... Cs>
std::size_t micro_os_plus::micro_test_plus::detail::math::count_literal_digits (void)
nodiscard

Counts the decimal digits of a floating-point literal, before or after the decimal point.

The digit separators (') are not counted.

Template Parameters
Fraction

true to count the digits after the decimal point, false to count those before it.

Cs

The characters of the literal.

Parameters

None.

Returns

The number of digits.

Walks the characters once, counting the decimal digits before the first decimal point (Fraction false) or after it (Fraction true); the digit separators are skipped.

Definition at line 101 of file deprecated-inlines.h.

101 count_literal_digits (void) -> std::size_t
102 {
103 std::size_t count = 0;
104 bool is_fraction = false;
105 for (const char c : { Cs... })
106 {
107 if (c == '.')
108 {
109 is_fraction = true;
110 }
111 else if (c >= '0' and c <= '9' and is_fraction == Fraction)
112 {
113 ++count;
114 }
115 }
116 return count;
117 }

Reference count_literal_digits.

Referenced by count_literal_digits, den, den_size and num.

decimal_epsilon()​

template <class Value_T>
Value_T micro_os_plus::micro_test_plus::detail::math::decimal_epsilon (Value_T value)
nodiscard constexpr

Computes the default comparison tolerance of a floating-point value, one unit of its last decimal.

Template Parameters
Value_T

The type of the value, a floating-point type.

Parameters
value

The value whose tolerance is to be determined; it may be negative, infinite, or a NaN.

Returns

Ten raised to minus the number of decimal places returned by count_decimals() (0.01 for 1.25, 1e-12 for 1e-12), or zero, which means an exact comparison, for a zero value and for a value whose tolerance would be below the range of Value_T.

The number of decimal places is computed by count_decimals(), and the tolerance is one divided by ten raised to that number, as for the floating-point literals, which use the decimals written.

A zero value has no decimals, and gets a zero tolerance, so that it is compared exactly; a tolerance of one unit of an arbitrary decimal would make the zero equal to unrelated small values. A zero tolerance is also returned when ten raised to the number of decimals would exceed the range of Value_T (values below about 1e-308 for double), instead of computing an infinite power.

Definition at line 326 of file deprecated-inlines.h.

326 decimal_epsilon (Value_T value) -> Value_T
327 {
328 const auto decimals = count_decimals<unsigned long long> (value);
329 if (decimals == 0
330 or decimals > static_cast<unsigned long long> (
331 std::numeric_limits<Value_T>::max_exponent10))
332 {
333 return Value_T{};
334 }
335 return Value_T (1) / pow (Value_T (10), decimals);
336 }

References count_decimals, decimal_epsilon and pow.

Referenced by decimal_epsilon.

den()​

template <class T, char... Cs>
T micro_os_plus::micro_test_plus::detail::math::den (void)
nodiscard

Computes the decimal part of a number represented as an array of characters.

Template Parameters
T

The target integral type for the result.

Cs

The character pack representing the numeric value; it must contain a decimal point.

Parameters

None.

Returns

The digits after the decimal point, as an integral value of type T (e.g. 25 for 1.25), to be divided by ten raised to the power returned by den_size().

This function template performs compile-time extraction of the decimal (fractional) part from a sequence of characters, typically provided as a template parameter pack.

The function expects the character sequence to represent a numeric value, where all characters are either digits, a dot (.), or an apostrophe ('). Parsing begins after the first dot, accumulating the decimal digits as an integer value and skipping the digit separators (e.g. 1.25 yields 25), so that den() / 10^den_size() gives the fraction. If the result could exceed T, the compilation fails with an explicit message.

Definition at line 177 of file deprecated-inlines.h.

177 den (void) -> T
178 {
179 static_assert ((... || (Cs == '.')),
180 "den(): no decimal point in literal");
181 // The result has as many digits as the decimals, and it must fit in
182 // `T`.
183 static_assert (
184 count_literal_digits<true, Cs...> ()
185 <= static_cast<std::size_t> (std::numeric_limits<T>::digits10),
186 "µTest++: the floating-point literal has too many "
187 "decimals");
188 T result{};
189 bool is_fraction = false;
190 for (const char c : { Cs... })
191 {
192 if (c == '.')
193 {
194 is_fraction = true;
195 }
196 else if (is_fraction and c >= '0' and c <= '9')
197 {
198 // The digit separators are skipped.
199 result = static_cast<T> (result * static_cast<T> (10)
200 + static_cast<T> (c - '0'));
201 }
202 }
203 return result;
204 }

References count_literal_digits and den.

Referenced by den, micro_os_plus::micro_test_plus::literals::operator""_d, micro_os_plus::micro_test_plus::literals::operator""_f and micro_os_plus::micro_test_plus::literals::operator""_ld.

den_size()​

template <class T, char... Cs>
T micro_os_plus::micro_test_plus::detail::math::den_size (void)
nodiscard

Counts the decimal places of a number represented as an array of characters.

Template Parameters
T

The integral type for the result.

Cs

The character pack representing the numeric value; it must contain a decimal point.

Parameters

None.

Returns

The number of decimal places (e.g. 2 for 1.25), as a value of type T; it is the scale of the value returned by den().

This function template determines, at compile time, the number of decimal (fractional) digits present in a numeric value represented by a character sequence, typically provided as a template parameter pack.

The function expects the character sequence to represent a numeric value, where all characters are either digits, a dot (.), or an apostrophe ('). It returns the number of digits that follow the first dot (the digit separators are not counted; e.g. 2 for 1.25), which is the scale of the value returned by den().

Definition at line 220 of file deprecated-inlines.h.

220 den_size (void) -> T
221 {
222 static_assert ((... || (Cs == '.')),
223 "den_size(): no decimal point in literal");
224 return static_cast<T> (count_literal_digits<true, Cs...> ());
225 }

References count_literal_digits and den_size.

Referenced by den_size, micro_os_plus::micro_test_plus::literals::operator""_d, micro_os_plus::micro_test_plus::literals::operator""_f and micro_os_plus::micro_test_plus::literals::operator""_ld.

integer_magnitude()​

template <class T, char... Cs>
unsigned long long micro_os_plus::micro_test_plus::detail::math::integer_magnitude (void)
nodiscard

Computes the value of an integer literal of type T, before any negation.

Template Parameters
T

The integral type of the literal.

Cs

The characters of the literal, as received by a literal operator template.

Parameters

None.

Returns

The value of the literal, up to max() of T, or, for the signed types, up to max () + 1, the absolute value of the minimum.

The literal must be an integer literal, in any of the C++ forms (decimal, hexadecimal, binary, or octal, with digit separators), and its value must fit in T; otherwise the compilation fails with an explicit message.

Negative values are obtained with the unary minus, so the literal itself is never negative. For the signed types, the limit is the absolute value of the minimum, max () + 1, so that the minimum can be written (e.g. -128_i8); the caller allows this magnitude only when it is negated.

When a check fails, zero is returned, so that the callers report no further errors.

Definition at line 448 of file deprecated-inlines.h.

448 integer_magnitude (void) -> unsigned long long
449 {
450 constexpr integer_literal literal = parse_integer_literal<Cs...> ();
451 constexpr unsigned long long max_magnitude
452 = static_cast<unsigned long long> (std::numeric_limits<T>::max ())
453 + (std::numeric_limits<T>::is_signed ? 1u : 0u);
454 constexpr bool fits = literal.is_integer && !literal.is_too_large
455 && literal.value <= max_magnitude;
456
457 static_assert (literal.is_integer,
458 "µTest++: an integer literal must not have a decimal "
459 "point or an exponent");
460 static_assert (!literal.is_integer || !literal.is_too_large,
461 "µTest++: the integer literal is too large");
462 static_assert (!literal.is_integer || literal.is_too_large || fits,
463 "µTest++: the integer literal value does not fit in the "
464 "type of the literal");
465
466 return fits ? literal.value : 0;
467 }

References integer_magnitude, micro_os_plus::micro_test_plus::detail::math::integer_literal::is_integer, micro_os_plus::micro_test_plus::detail::math::integer_literal::is_too_large, parse_integer_literal and micro_os_plus::micro_test_plus::detail::math::integer_literal::value.

Referenced by integer_magnitude and micro_os_plus::micro_test_plus::detail::integral_literal.

min_value()​

template <class T>
const T & micro_os_plus::micro_test_plus::detail::math::min_value (const T & lhs, const T & rhs)
nodiscard constexpr noexcept

Computes the minimum of two comparable values.

This function template provides a generic, constexpr implementation for determining the minimum of two values of any type that supports comparison.

The function returns a reference to the lesser of the two input values, as determined by the < operator. If the second argument is less than the first, it is returned; otherwise, the first argument is returned.

Template Parameters
T

The type of the input values. Must support comparison via the < operator.

Parameters
lhs

The first value to compare.

rhs

The second value to compare.

Returns

A reference to the minimum of the two input values.

Definition at line 106 of file math-inlines.h.

106 min_value (const T& lhs, const T& rhs) noexcept -> const T&
107 {
108 return (rhs < lhs) ? rhs : lhs;
109 }

Reference min_value.

Referenced by count_decimals, min_value and micro_os_plus::micro_test_plus::detail::within_tolerance.

num()​

template <class T, char... Cs>
T micro_os_plus::micro_test_plus::detail::math::num (void)
nodiscard

Computes the integral part of a decimal floating-point number represented as an array of characters.

Used by the floating-point literal operators; the integer literals use integer_magnitude(), which also accepts the C++ prefixes and checks the range.

Template Parameters
T

The target integral type for the result.

Cs

The character pack representing the numeric value.

Parameters

None.

Returns

The parsed integral value of type T.

This function template performs compile-time parsing of a numeric value from a sequence of characters, typically provided as a template parameter pack.

The characters must be decimal digits, a dot (.), or digit separators ('), which are skipped; otherwise (e.g. an exponent) the compilation fails with an explicit message, as it does if the integral part has more digits than T can always hold. Parsing stops at the first dot, allowing the function to extract only the integral part of the number.

Definition at line 134 of file deprecated-inlines.h.

134 num (void) -> T
135 {
136 static_assert (
137 ((Cs == '.' or Cs == '\'' or (Cs >= '0' and Cs <= '9')) and ...),
138 "µTest++: a floating-point literal must be written with decimal "
139 "digits and a decimal point, without an exponent");
140 static_assert (
141 count_literal_digits<false, Cs...> ()
142 <= static_cast<std::size_t> (std::numeric_limits<T>::digits10),
143 "µTest++: the floating-point literal has too many "
144 "digits before the decimal point");
145 T result{};
146 for (const char c : { Cs... })
147 {
148 if (c == '.')
149 {
150 break;
151 }
152 if (c >= '0' and c <= '9')
153 {
154 result = static_cast<T> (result * static_cast<T> (10)
155 + static_cast<T> (c - '0'));
156 }
157 }
158 return result;
159 }

References count_literal_digits and num.

Referenced by num, micro_os_plus::micro_test_plus::literals::operator""_d, micro_os_plus::micro_test_plus::literals::operator""_f and micro_os_plus::micro_test_plus::literals::operator""_ld.

parse_integer_literal()​

template <char... Cs>
integer_literal micro_os_plus::micro_test_plus::detail::math::parse_integer_literal (void)
nodiscard

Parses the characters of an integer literal.

Template Parameters
Cs

The characters of the literal, as received by a literal operator template.

Parameters

None.

Returns

The value, and whether the characters form an integer literal and whether its value fits in unsigned long long.

The characters are those of a valid C++ literal, already checked by the compiler (digits valid for the base, digit separators in valid positions). The base is given by the prefix: 0x or 0X for hexadecimal, 0b or 0B for binary, a leading 0 for octal, and none for decimal. The digit separators (') are skipped.

Any other character (a decimal point, an exponent, or a digit not valid for the base, as in the floating-point literal 09.5) marks the literal as not an integer. The value is accumulated in unsigned long long, and the accumulation stops if it would overflow.

Definition at line 354 of file deprecated-inlines.h.

355 {
356 constexpr std::array<char, sizeof...(Cs)> cs{ Cs... };
357 constexpr unsigned long long max_value
358 = std::numeric_limits<unsigned long long>::max ();
359
360 integer_literal result{ 0, true, false };
361
362 unsigned long long base = 10;
363 std::size_t i = 0;
364 if (cs.size () > 1 && cs[0] == '0')
365 {
366 if (cs[1] == 'x' || cs[1] == 'X')
367 {
368 base = 16;
369 i = 2;
370 }
371 else if (cs[1] == 'b' || cs[1] == 'B')
372 {
373 base = 2;
374 i = 2;
375 }
376 else
377 {
378 base = 8;
379 i = 1;
380 }
381 }
382
383 for (; i < cs.size (); ++i)
384 {
385 const char c = cs[i];
386 if (c == '\'')
387 {
388 continue;
389 }
390
391 unsigned long long digit = 0;
392 if (c >= '0' && c <= '9')
393 {
394 digit = static_cast<unsigned long long> (c - '0');
395 }
396 else if (base == 16 && c >= 'a' && c <= 'f')
397 {
398 digit = static_cast<unsigned long long> (c - 'a' + 10);
399 }
400 else if (base == 16 && c >= 'A' && c <= 'F')
401 {
402 digit = static_cast<unsigned long long> (c - 'A' + 10);
403 }
404 else
405 {
406 // A decimal point, an exponent, or a suffix character.
407 result.is_integer = false;
408 return result;
409 }
410
411 if (digit >= base)
412 {
413 // Possible only in a floating-point literal, like `09.5`.
414 result.is_integer = false;
415 return result;
416 }
417
418 if (result.value > (max_value - digit) / base)
419 {
420 result.is_too_large = true;
421 return result;
422 }
423
424 result.value = result.value * base + digit;
425 }
426
427 return result;
428 }

Reference parse_integer_literal.

Referenced by integer_magnitude and parse_integer_literal.

pow()​

template <class T, class Exp_T>
T micro_os_plus::micro_test_plus::detail::math::pow (const T base, const Exp_T exp)
nodiscard constexpr noexcept

Generic exponentiation function to compute the power of a base raised to an exponent.

Template Parameters
T

The type of the base value. Must support multiplication assignment and construction from an integer.

Exp_T

The type of the exponent. Must be default-constructible (to zero), and support the < and prefix ++ operators.

Parameters
base

The base value to be raised to the power of exp.

exp

The exponent value.

Returns

The result of raising base to the power of exp.

This function template provides a constexpr implementation for raising a base value to a given exponent, supporting any types that allow multiplication.

The function starts from one and multiplies the result by the base exp times. If the exponent is zero (or negative), the function returns one (the multiplicative identity for the type).

Definition at line 85 of file deprecated-inlines.h.

85 pow (const T base, const Exp_T exp) noexcept -> T
86 {
87 T result{ 1 };
88 for (Exp_T i{}; i < exp; ++i)
89 result *= base;
90 return result;
91 }

Reference pow.

Referenced by decimal_epsilon and pow.


The documentation for this namespace was generated from the following files:


Generated via doxygen2docusaurus 2.2.8 by Doxygen 1.18.0.