WPILibC++ 2024.3.2
math.h
Go to the documentation of this file.
1// Copyright (c) FIRST and other WPILib contributors.
2// Open Source Software; you can modify and/or share it under the terms of
3// the WPILib BSD license file in the root directory of this project.
4
5// Copyright (c) 2016 Nic Holthaus
6//
7// The MIT License (MIT)
8//
9// Permission is hereby granted, free of charge, to any person obtaining a copy
10// of this software and associated documentation files (the "Software"), to deal
11// in the Software without restriction, including without limitation the rights
12// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13// copies of the Software, and to permit persons to whom the Software is
14// furnished to do so, subject to the following conditions:
15//
16// The above copyright notice and this permission notice shall be included in
17// all copies or substantial portions of the Software.
18//
19// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25// SOFTWARE.
26
27#pragma once
28
29#include <cmath>
30
31#include "units/angle.h"
32#include "units/base.h"
33#include "units/dimensionless.h"
34
35//----------------------------------
36// UNIT-ENABLED CMATH FUNCTIONS
37//----------------------------------
38
39/**
40 * @brief namespace for unit-enabled versions of the `<cmath>` library
41 * @details Includes trigonometric functions, exponential/log functions,
42 * rounding functions, etc.
43 * @sa See `unit_t` for more information on unit type containers.
44 */
45namespace units::math {
46//----------------------------------
47// TRIGONOMETRIC FUNCTIONS
48//----------------------------------
49
50/**
51 * @ingroup UnitMath
52 * @brief Compute cosine
53 * @details The input value can be in any unit of angle, including radians or
54 * degrees.
55 * @tparam AngleUnit any `unit_t` type of `category::angle_unit`.
56 * @param[in] angle angle to compute the cosine of
57 * @returns Returns the cosine of <i>angle</i>
58 */
59#if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS)
60template <class AngleUnit>
61dimensionless::scalar_t cos(const AngleUnit angle) noexcept {
62 static_assert(
63 traits::is_angle_unit<AngleUnit>::value,
64 "Type `AngleUnit` must be a unit of angle derived from `unit_t`.");
66 std::cos(angle.template convert<angle::radian>()()));
67}
68#endif
69
70/**
71 * @ingroup UnitMath
72 * @brief Compute sine
73 * @details The input value can be in any unit of angle, including radians or
74 * degrees.
75 * @tparam AngleUnit any `unit_t` type of `category::angle_unit`.
76 * @param[in] angle angle to compute the since of
77 * @returns Returns the sine of <i>angle</i>
78 */
79#if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS)
80template <class AngleUnit>
81dimensionless::scalar_t sin(const AngleUnit angle) noexcept {
82 static_assert(
83 traits::is_angle_unit<AngleUnit>::value,
84 "Type `AngleUnit` must be a unit of angle derived from `unit_t`.");
86 std::sin(angle.template convert<angle::radian>()()));
87}
88#endif
89/**
90 * @ingroup UnitMath
91 * @brief Compute tangent
92 * @details The input value can be in any unit of angle, including radians or
93 * degrees.
94 * @tparam AngleUnit any `unit_t` type of `category::angle_unit`.
95 * @param[in] angle angle to compute the tangent of
96 * @returns Returns the tangent of <i>angle</i>
97 */
98#if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS)
99template <class AngleUnit>
100dimensionless::scalar_t tan(const AngleUnit angle) noexcept {
101 static_assert(
102 traits::is_angle_unit<AngleUnit>::value,
103 "Type `AngleUnit` must be a unit of angle derived from `unit_t`.");
105 std::tan(angle.template convert<angle::radian>()()));
106}
107#endif
108
109/**
110 * @ingroup UnitMath
111 * @brief Compute arc cosine
112 * @details Returns the principal value of the arc cosine of x, expressed in
113 * radians.
114 * @param[in] x Value whose arc cosine is computed, in the interval [-1,+1].
115 * @returns Principal arc cosine of x, in the interval [0,pi] radians.
116 */
117#if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS)
118template <class ScalarUnit>
119angle::radian_t acos(const ScalarUnit x) noexcept {
120 static_assert(
122 "Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`.");
123 return angle::radian_t(std::acos(x()));
124}
125#endif
126
127/**
128 * @ingroup UnitMath
129 * @brief Compute arc sine
130 * @details Returns the principal value of the arc sine of x, expressed in
131 * radians.
132 * @param[in] x Value whose arc sine is computed, in the interval [-1,+1].
133 * @returns Principal arc sine of x, in the interval [-pi/2,+pi/2] radians.
134 */
135#if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS)
136template <class ScalarUnit>
137angle::radian_t asin(const ScalarUnit x) noexcept {
138 static_assert(
140 "Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`.");
141 return angle::radian_t(std::asin(x()));
142}
143#endif
144
145/**
146 * @ingroup UnitMath
147 * @brief Compute arc tangent
148 * @details Returns the principal value of the arc tangent of x, expressed in
149 * radians. Notice that because of the sign ambiguity, the function
150 * cannot determine with certainty in which quadrant the angle falls
151 * only by its tangent value. See atan2 for an alternative that takes a
152 * fractional argument instead.
153 * @tparam AngleUnit any `unit_t` type of `category::angle_unit`.
154 * @param[in] x Value whose arc tangent is computed, in the interval [-1,+1].
155 * @returns Principal arc tangent of x, in the interval [-pi/2,+pi/2] radians.
156 */
157#if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS)
158template <class ScalarUnit>
159angle::radian_t atan(const ScalarUnit x) noexcept {
160 static_assert(
162 "Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`.");
163 return angle::radian_t(std::atan(x()));
164}
165#endif
166
167/**
168 * @ingroup UnitMath
169 * @brief Compute arc tangent with two parameters
170 * @details To compute the value, the function takes into account the sign of
171 * both arguments in order to determine the quadrant.
172 * @param[in] y y-component of the triangle expressed.
173 * @param[in] x x-component of the triangle expressed.
174 * @returns Returns the principal value of the arc tangent of <i>y/x</i>,
175 * expressed in radians.
176 */
177#if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS)
178template <class Y, class X>
179angle::radian_t atan2(const Y y, const X x) noexcept {
180 static_assert(traits::is_dimensionless_unit<decltype(y / x)>::value,
181 "The quantity y/x must yield a dimensionless ratio.");
182
183 // X and Y could be different length units, so normalize them
184 return angle::radian_t(
185 std::atan2(y.template convert<
186 typename units::traits::unit_t_traits<X>::unit_type>()(),
187 x()));
188}
189#endif
190
191//----------------------------------
192// HYPERBOLIC TRIG FUNCTIONS
193//----------------------------------
194
195/**
196 * @ingroup UnitMath
197 * @brief Compute hyperbolic cosine
198 * @details The input value can be in any unit of angle, including radians or
199 * degrees.
200 * @tparam AngleUnit any `unit_t` type of `category::angle_unit`.
201 * @param[in] angle angle to compute the hyperbolic cosine of
202 * @returns Returns the hyperbolic cosine of <i>angle</i>
203 */
204#if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS)
205template <class AngleUnit>
206dimensionless::scalar_t cosh(const AngleUnit angle) noexcept {
207 static_assert(
208 traits::is_angle_unit<AngleUnit>::value,
209 "Type `AngleUnit` must be a unit of angle derived from `unit_t`.");
211 std::cosh(angle.template convert<angle::radian>()()));
212}
213#endif
214
215/**
216 * @ingroup UnitMath
217 * @brief Compute hyperbolic sine
218 * @details The input value can be in any unit of angle, including radians or
219 * degrees.
220 * @tparam AngleUnit any `unit_t` type of `category::angle_unit`.
221 * @param[in] angle angle to compute the hyperbolic sine of
222 * @returns Returns the hyperbolic sine of <i>angle</i>
223 */
224#if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS)
225template <class AngleUnit>
226dimensionless::scalar_t sinh(const AngleUnit angle) noexcept {
227 static_assert(
228 traits::is_angle_unit<AngleUnit>::value,
229 "Type `AngleUnit` must be a unit of angle derived from `unit_t`.");
231 std::sinh(angle.template convert<angle::radian>()()));
232}
233#endif
234
235/**
236 * @ingroup UnitMath
237 * @brief Compute hyperbolic tangent
238 * @details The input value can be in any unit of angle, including radians or
239 * degrees.
240 * @tparam AngleUnit any `unit_t` type of `category::angle_unit`.
241 * @param[in] angle angle to compute the hyperbolic tangent of
242 * @returns Returns the hyperbolic tangent of <i>angle</i>
243 */
244#if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS)
245template <class AngleUnit>
246dimensionless::scalar_t tanh(const AngleUnit angle) noexcept {
247 static_assert(
248 traits::is_angle_unit<AngleUnit>::value,
249 "Type `AngleUnit` must be a unit of angle derived from `unit_t`.");
251 std::tanh(angle.template convert<angle::radian>()()));
252}
253#endif
254
255/**
256 * @ingroup UnitMath
257 * @brief Compute arc hyperbolic cosine
258 * @details Returns the nonnegative arc hyperbolic cosine of x, expressed in
259 * radians.
260 * @param[in] x Value whose arc hyperbolic cosine is computed. If the argument
261 * is less than 1, a domain error occurs.
262 * @returns Nonnegative arc hyperbolic cosine of x, in the interval
263 * [0,+INFINITY] radians.
264 */
265#if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS)
266template <class ScalarUnit>
267angle::radian_t acosh(const ScalarUnit x) noexcept {
268 static_assert(
270 "Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`.");
271 return angle::radian_t(std::acosh(x()));
272}
273#endif
274
275/**
276 * @ingroup UnitMath
277 * @brief Compute arc hyperbolic sine
278 * @details Returns the arc hyperbolic sine of x, expressed in radians.
279 * @param[in] x Value whose arc hyperbolic sine is computed.
280 * @returns Arc hyperbolic sine of x, in radians.
281 */
282#if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS)
283template <class ScalarUnit>
284angle::radian_t asinh(const ScalarUnit x) noexcept {
285 static_assert(
287 "Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`.");
288 return angle::radian_t(std::asinh(x()));
289}
290#endif
291
292/**
293 * @ingroup UnitMath
294 * @brief Compute arc hyperbolic tangent
295 * @details Returns the arc hyperbolic tangent of x, expressed in radians.
296 * @param[in] x Value whose arc hyperbolic tangent is computed, in the interval
297 * [-1,+1]. If the argument is out of this interval, a domain error
298 * occurs. For values of -1 and +1, a pole error may occur.
299 * @returns units::angle::radian_t
300 */
301#if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS)
302template <class ScalarUnit>
303angle::radian_t atanh(const ScalarUnit x) noexcept {
304 static_assert(
306 "Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`.");
307 return angle::radian_t(std::atanh(x()));
308}
309#endif
310
311//----------------------------------
312// TRANSCENDENTAL FUNCTIONS
313//----------------------------------
314
315// it makes NO SENSE to put dimensioned units into a transcendental function,
316// and if you think it does you are demonstrably wrong.
317// https://en.wikipedia.org/wiki/Transcendental_function#Dimensional_analysis
318
319/**
320 * @ingroup UnitMath
321 * @brief Compute exponential function
322 * @details Returns the base-e exponential function of x, which is e raised to
323 * the power x: ex.
324 * @param[in] x scalar value of the exponent.
325 * @returns Exponential value of x.
326 * If the magnitude of the result is too large to be represented by a
327 * value of the return type, the function returns HUGE_VAL (or
328 * HUGE_VALF or HUGE_VALL) with the proper sign, and an overflow range
329 * error occurs.
330 */
331template <class ScalarUnit>
332dimensionless::scalar_t exp(const ScalarUnit x) noexcept {
333 static_assert(
335 "Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`.");
336 return dimensionless::scalar_t(std::exp(x()));
337}
338
339/**
340 * @ingroup UnitMath
341 * @brief Compute natural logarithm
342 * @details Returns the natural logarithm of x.
343 * @param[in] x scalar value whose logarithm is calculated. If the argument is
344 * negative, a domain error occurs.
345 * @sa log10 for more common base-10 logarithms
346 * @returns Natural logarithm of x.
347 */
348template <class ScalarUnit>
349dimensionless::scalar_t log(const ScalarUnit x) noexcept {
350 static_assert(
352 "Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`.");
354}
355
356/**
357 * @ingroup UnitMath
358 * @brief Compute common logarithm
359 * @details Returns the common (base-10) logarithm of x.
360 * @param[in] x Value whose logarithm is calculated. If the argument is
361 * negative, a domain error occurs.
362 * @returns Common logarithm of x.
363 */
364template <class ScalarUnit>
365dimensionless::scalar_t log10(const ScalarUnit x) noexcept {
366 static_assert(
368 "Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`.");
370}
371
372/**
373 * @ingroup UnitMath
374 * @brief Break into fractional and integral parts.
375 * @details The integer part is stored in the object pointed by intpart, and the
376 * fractional part is returned by the function. Both parts have the
377 * same sign as x.
378 * @param[in] x scalar value to break into parts.
379 * @param[in] intpart Pointer to an object (of the same type as x) where the
380 * integral part is stored with the same sign as x.
381 * @returns The fractional part of x, with the same sign.
382 */
383template <class ScalarUnit>
384dimensionless::scalar_t modf(const ScalarUnit x, ScalarUnit* intpart) noexcept {
385 static_assert(
387 "Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`.");
388
390 dimensionless::scalar_t fracpart =
392 *intpart = intp;
393 return fracpart;
394}
395
396/**
397 * @ingroup UnitMath
398 * @brief Compute binary exponential function
399 * @details Returns the base-2 exponential function of x, which is 2 raised to
400 * the power x: 2^x. 2param[in] x Value of the exponent.
401 * @returns 2 raised to the power of x.
402 */
403template <class ScalarUnit>
404dimensionless::scalar_t exp2(const ScalarUnit x) noexcept {
405 static_assert(
407 "Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`.");
409}
410
411/**
412 * @ingroup UnitMath
413 * @brief Compute exponential minus one
414 * @details Returns e raised to the power x minus one: e^x-1. For small
415 * magnitude values of x, expm1 may be more accurate than exp(x)-1.
416 * @param[in] x Value of the exponent.
417 * @returns e raised to the power of x, minus one.
418 */
419template <class ScalarUnit>
420dimensionless::scalar_t expm1(const ScalarUnit x) noexcept {
421 static_assert(
423 "Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`.");
425}
426
427/**
428 * @ingroup UnitMath
429 * @brief Compute logarithm plus one
430 * @details Returns the natural logarithm of one plus x. For small magnitude
431 * values of x, logp1 may be more accurate than log(1+x).
432 * @param[in] x Value whose logarithm is calculated. If the argument is less
433 * than -1, a domain error occurs.
434 * @returns The natural logarithm of (1+x).
435 */
436template <class ScalarUnit>
437dimensionless::scalar_t log1p(const ScalarUnit x) noexcept {
438 static_assert(
440 "Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`.");
442}
443
444/**
445 * @ingroup UnitMath
446 * @brief Compute binary logarithm
447 * @details Returns the binary (base-2) logarithm of x.
448 * @param[in] x Value whose logarithm is calculated. If the argument is
449 * negative, a domain error occurs.
450 * @returns The binary logarithm of x: log2x.
451 */
452template <class ScalarUnit>
453dimensionless::scalar_t log2(const ScalarUnit x) noexcept {
454 static_assert(
456 "Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`.");
458}
459
460//----------------------------------
461// POWER FUNCTIONS
462//----------------------------------
463
464/* pow is implemented earlier in the library since a lot of the unit definitions
465 * depend on it */
466
467/**
468 * @ingroup UnitMath
469 * @brief computes the square root of <i>value</i>
470 * @details Only implemented for linear_scale units.
471 * @param[in] value `unit_t` derived type to compute the square root of.
472 * @returns new unit_t, whose units are the square root of value's.
473 * E.g. if values had units of `square_meter`, then the return type
474 * will have units of `meter`.
475 * @note `sqrt` provides a _rational approximation_ of the square root of
476 * <i>value</i>. In some cases, _both_ the returned value _and_ conversion
477 * factor of the returned unit type may have errors no larger than
478 * `1e-10`.
479 */
480template <
481 class UnitType,
482 std::enable_if_t<units::traits::has_linear_scale<UnitType>::value, int> = 0>
483inline auto sqrt(const UnitType& value) noexcept -> unit_t<
485 typename units::traits::unit_t_traits<UnitType>::underlying_type,
486 linear_scale> {
487 return unit_t<
489 typename units::traits::unit_t_traits<UnitType>::underlying_type,
490 linear_scale>(std::sqrt(value()));
491}
492
493/**
494 * @ingroup UnitMath
495 * @brief Computes the square root of the sum-of-squares of x and y.
496 * @details Only implemented for linear_scale units.
497 * @param[in] x unit_t type value
498 * @param[in] y unit_t type value
499 * @returns square root of the sum-of-squares of x and y in the same units as x.
500 */
501template <class UnitTypeLhs, class UnitTypeRhs,
504 int> = 0>
505inline UnitTypeLhs hypot(const UnitTypeLhs& x, const UnitTypeRhs& y) {
507 "Parameters of hypot() function are not compatible units.");
508 return UnitTypeLhs(std::hypot(
509 x(),
510 y.template convert<
511 typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type>()()));
512}
513
514//----------------------------------
515// ROUNDING FUNCTIONS
516//----------------------------------
517
518/**
519 * @ingroup UnitMath
520 * @brief Round up value
521 * @details Rounds x upward, returning the smallest integral value that is not
522 * less than x.
523 * @param[in] x Unit value to round up.
524 * @returns The smallest integral value that is not less than x.
525 */
526template <class UnitType,
527 class = std::enable_if_t<traits::is_unit_t<UnitType>::value>>
528UnitType ceil(const UnitType x) noexcept {
529 return UnitType(std::ceil(x()));
530}
531
532/**
533 * @ingroup UnitMath
534 * @brief Round down value
535 * @details Rounds x downward, returning the largest integral value that is not
536 * greater than x.
537 * @param[in] x Unit value to round down.
538 * @returns The value of x rounded downward.
539 */
540template <class UnitType,
541 class = std::enable_if_t<traits::is_unit_t<UnitType>::value>>
542UnitType floor(const UnitType x) noexcept {
543 return UnitType(std::floor(x()));
544}
545
546/**
547 * @ingroup UnitMath
548 * @brief Compute remainder of division
549 * @details Returns the floating-point remainder of numer/denom (rounded towards
550 * zero).
551 * @param[in] numer Value of the quotient numerator.
552 * @param[in] denom Value of the quotient denominator.
553 * @returns The remainder of dividing the arguments.
554 */
555template <class UnitTypeLhs, class UnitTypeRhs,
556 class = std::enable_if_t<traits::is_unit_t<UnitTypeLhs>::value &&
558UnitTypeLhs fmod(const UnitTypeLhs numer, const UnitTypeRhs denom) noexcept {
560 "Parameters of fmod() function are not compatible units.");
561 return UnitTypeLhs(std::fmod(
562 numer(),
563 denom.template convert<
564 typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type>()()));
565}
566
567/**
568 * @ingroup UnitMath
569 * @brief Truncate value
570 * @details Rounds x toward zero, returning the nearest integral value that is
571 * not larger in magnitude than x. Effectively rounds towards 0.
572 * @param[in] x Value to truncate
573 * @returns The nearest integral value that is not larger in magnitude than x.
574 */
575template <class UnitType,
576 class = std::enable_if_t<traits::is_unit_t<UnitType>::value>>
577UnitType trunc(const UnitType x) noexcept {
578 return UnitType(std::trunc(x()));
579}
580
581/**
582 * @ingroup UnitMath
583 * @brief Round to nearest
584 * @details Returns the integral value that is nearest to x, with halfway cases
585 * rounded away from zero.
586 * @param[in] x value to round.
587 * @returns The value of x rounded to the nearest integral.
588 */
589template <class UnitType,
590 class = std::enable_if_t<traits::is_unit_t<UnitType>::value>>
591UnitType round(const UnitType x) noexcept {
592 return UnitType(std::round(x()));
593}
594
595//----------------------------------
596// FLOATING POINT MANIPULATION
597//----------------------------------
598
599/**
600 * @ingroup UnitMath
601 * @brief Copy sign
602 * @details Returns a value with the magnitude and dimension of x, and the sign
603 * of y. Values x and y do not have to be compatible units.
604 * @param[in] x Value with the magnitude of the resulting value.
605 * @param[in] y Value with the sign of the resulting value.
606 * @returns value with the magnitude and dimension of x, and the sign of y.
607 */
608template <class UnitTypeLhs, class UnitTypeRhs,
609 class = std::enable_if_t<traits::is_unit_t<UnitTypeLhs>::value &&
611UnitTypeLhs copysign(const UnitTypeLhs x, const UnitTypeRhs y) noexcept {
612 return UnitTypeLhs(std::copysign(
613 x(), y())); // no need for conversion to get the correct sign.
614}
615
616/// Overload to copy the sign from a raw double
617template <class UnitTypeLhs,
618 class = std::enable_if_t<traits::is_unit_t<UnitTypeLhs>::value>>
619UnitTypeLhs copysign(const UnitTypeLhs x,
620 const UNIT_LIB_DEFAULT_TYPE y) noexcept {
621 return UnitTypeLhs(std::copysign(x(), y));
622}
623
624//----------------------------------
625// MIN / MAX / DIFFERENCE
626//----------------------------------
627
628/**
629 * @ingroup UnitMath
630 * @brief Positive difference
631 * @details The function returns x-y if x>y, and zero otherwise, in the same
632 * units as x. Values x and y do not have to be the same type of units,
633 * but they do have to be compatible.
634 * @param[in] x Values whose difference is calculated.
635 * @param[in] y Values whose difference is calculated.
636 * @returns The positive difference between x and y.
637 */
638template <class UnitTypeLhs, class UnitTypeRhs,
639 class = std::enable_if_t<traits::is_unit_t<UnitTypeLhs>::value &&
641UnitTypeLhs fdim(const UnitTypeLhs x, const UnitTypeRhs y) noexcept {
643 "Parameters of fdim() function are not compatible units.");
644 return UnitTypeLhs(std::fdim(
645 x(),
646 y.template convert<
647 typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type>()()));
648}
649
650/**
651 * @ingroup UnitMath
652 * @brief Maximum value
653 * @details Returns the larger of its arguments: either x or y, in the same
654 * units as x. Values x and y do not have to be the same type of units,
655 * but they do have to be compatible.
656 * @param[in] x Values among which the function selects a maximum.
657 * @param[in] y Values among which the function selects a maximum.
658 * @returns The maximum numeric value of its arguments.
659 */
660template <class UnitTypeLhs, class UnitTypeRhs,
661 class = std::enable_if_t<traits::is_unit_t<UnitTypeLhs>::value &&
663UnitTypeLhs fmax(const UnitTypeLhs x, const UnitTypeRhs y) noexcept {
665 "Parameters of fmax() function are not compatible units.");
666 return UnitTypeLhs(std::fmax(
667 x(),
668 y.template convert<
669 typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type>()()));
670}
671
672/**
673 * @ingroup UnitMath
674 * @brief Minimum value
675 * @details Returns the smaller of its arguments: either x or y, in the same
676 * units as x. If one of the arguments in a NaN, the other is returned.
677 * Values x and y do not have to be the same type of units, but they do
678 * have to be compatible.
679 * @param[in] x Values among which the function selects a minimum.
680 * @param[in] y Values among which the function selects a minimum.
681 * @returns The minimum numeric value of its arguments.
682 */
683template <class UnitTypeLhs, class UnitTypeRhs,
684 class = std::enable_if_t<traits::is_unit_t<UnitTypeLhs>::value &&
686UnitTypeLhs fmin(const UnitTypeLhs x, const UnitTypeRhs y) noexcept {
688 "Parameters of fmin() function are not compatible units.");
689 return UnitTypeLhs(std::fmin(
690 x(),
691 y.template convert<
692 typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type>()()));
693}
694
695//----------------------------------
696// OTHER FUNCTIONS
697//----------------------------------
698
699/**
700 * @ingroup UnitMath
701 * @brief Compute absolute value
702 * @details Returns the absolute value of x, i.e. |x|.
703 * @param[in] x Value whose absolute value is returned.
704 * @returns The absolute value of x.
705 */
706template <class UnitType,
707 class = std::enable_if_t<traits::is_unit_t<UnitType>::value>>
708UnitType fabs(const UnitType x) noexcept {
709 return UnitType(std::fabs(x()));
710}
711
712/**
713 * @ingroup UnitMath
714 * @brief Compute absolute value
715 * @details Returns the absolute value of x, i.e. |x|.
716 * @param[in] x Value whose absolute value is returned.
717 * @returns The absolute value of x.
718 */
719template <class UnitType,
720 class = std::enable_if_t<traits::is_unit_t<UnitType>::value>>
721UnitType abs(const UnitType x) noexcept {
722 return UnitType(std::fabs(x()));
723}
724
725/**
726 * @ingroup UnitMath
727 * @brief Multiply-add
728 * @details Returns x*y+z. The function computes the result without losing
729 * precision in any intermediate result. The resulting unit type is a
730 * compound unit of x* y.
731 * @param[in] x Values to be multiplied.
732 * @param[in] y Values to be multiplied.
733 * @param[in] z Value to be added.
734 * @returns The result of x*y+z
735 */
736template <class UnitTypeLhs, class UnitMultiply, class UnitAdd,
737 class = std::enable_if_t<traits::is_unit_t<UnitTypeLhs>::value &&
740auto fma(const UnitTypeLhs x, const UnitMultiply y, const UnitAdd z) noexcept
741 -> decltype(x * y) {
742 using resultType = decltype(x * y);
743 static_assert(
746 typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type,
747 typename units::traits::unit_t_traits<UnitMultiply>::unit_type>,
748 typename units::traits::unit_t_traits<UnitAdd>::unit_type>::value,
749 "Unit types are not compatible.");
750 return resultType(std::fma(x(), y(), resultType(z)()));
751}
752} // namespace units::math
#define UNIT_LIB_DEFAULT_TYPE
Definition: base.h:59
Container for values which represent quantities of a given unit.
Definition: base.h:1926
typename std::enable_if< B, T >::type enable_if_t
Definition: core.h:256
static constexpr T convert(const T &value) noexcept
converts a value from one type to another.
Definition: base.h:1648
typename units::detail::sqrt_impl< U, Eps >::type square_root
represents the square root of type class U.
Definition: base.h:1401
UnitTypeLhs fmax(const UnitTypeLhs x, const UnitTypeRhs y) noexcept
Maximum value.
Definition: math.h:663
UnitType abs(const UnitType x) noexcept
Compute absolute value.
Definition: math.h:721
angle::radian_t acosh(const ScalarUnit x) noexcept
Compute arc hyperbolic cosine.
Definition: math.h:267
UnitTypeLhs fmin(const UnitTypeLhs x, const UnitTypeRhs y) noexcept
Minimum value.
Definition: math.h:686
UnitTypeLhs hypot(const UnitTypeLhs &x, const UnitTypeRhs &y)
Computes the square root of the sum-of-squares of x and y.
Definition: math.h:505
dimensionless::scalar_t exp(const ScalarUnit x) noexcept
Compute exponential function.
Definition: math.h:332
dimensionless::scalar_t sinh(const AngleUnit angle) noexcept
Compute hyperbolic sine.
Definition: math.h:226
UnitType round(const UnitType x) noexcept
Round to nearest.
Definition: math.h:591
dimensionless::scalar_t tan(const AngleUnit angle) noexcept
Compute tangent.
Definition: math.h:100
UnitTypeLhs fmod(const UnitTypeLhs numer, const UnitTypeRhs denom) noexcept
Compute remainder of division.
Definition: math.h:558
angle::radian_t asin(const ScalarUnit x) noexcept
Compute arc sine.
Definition: math.h:137
auto fma(const UnitTypeLhs x, const UnitMultiply y, const UnitAdd z) noexcept -> decltype(x *y)
Multiply-add.
Definition: math.h:740
UnitTypeLhs fdim(const UnitTypeLhs x, const UnitTypeRhs y) noexcept
Positive difference.
Definition: math.h:641
angle::radian_t atanh(const ScalarUnit x) noexcept
Compute arc hyperbolic tangent.
Definition: math.h:303
angle::radian_t acos(const ScalarUnit x) noexcept
Compute arc cosine.
Definition: math.h:119
angle::radian_t atan2(const Y y, const X x) noexcept
Compute arc tangent with two parameters.
Definition: math.h:179
dimensionless::scalar_t modf(const ScalarUnit x, ScalarUnit *intpart) noexcept
Break into fractional and integral parts.
Definition: math.h:384
dimensionless::scalar_t exp2(const ScalarUnit x) noexcept
Compute binary exponential function.
Definition: math.h:404
dimensionless::scalar_t expm1(const ScalarUnit x) noexcept
Compute exponential minus one.
Definition: math.h:420
UnitType fabs(const UnitType x) noexcept
Compute absolute value.
Definition: math.h:708
dimensionless::scalar_t cosh(const AngleUnit angle) noexcept
Compute hyperbolic cosine.
Definition: math.h:206
angle::radian_t atan(const ScalarUnit x) noexcept
Compute arc tangent.
Definition: math.h:159
dimensionless::scalar_t log2(const ScalarUnit x) noexcept
Compute binary logarithm.
Definition: math.h:453
dimensionless::scalar_t cos(const AngleUnit angle) noexcept
Compute cosine.
Definition: math.h:61
dimensionless::scalar_t tanh(const AngleUnit angle) noexcept
Compute hyperbolic tangent.
Definition: math.h:246
UnitType floor(const UnitType x) noexcept
Round down value.
Definition: math.h:542
UnitTypeLhs copysign(const UnitTypeLhs x, const UnitTypeRhs y) noexcept
Copy sign.
Definition: math.h:611
UnitType trunc(const UnitType x) noexcept
Truncate value.
Definition: math.h:577
auto sqrt(const UnitType &value) noexcept -> unit_t< square_root< typename units::traits::unit_t_traits< UnitType >::unit_type >, typename units::traits::unit_t_traits< UnitType >::underlying_type, linear_scale >
computes the square root of value
Definition: math.h:483
dimensionless::scalar_t log(const ScalarUnit x) noexcept
Compute natural logarithm.
Definition: math.h:349
dimensionless::scalar_t log1p(const ScalarUnit x) noexcept
Compute logarithm plus one.
Definition: math.h:437
dimensionless::scalar_t log10(const ScalarUnit x) noexcept
Compute common logarithm.
Definition: math.h:365
dimensionless::scalar_t sin(const AngleUnit angle) noexcept
Compute sine.
Definition: math.h:81
UnitType ceil(const UnitType x) noexcept
Round up value.
Definition: math.h:528
angle::radian_t asinh(const ScalarUnit x) noexcept
Compute arc hyperbolic sine.
Definition: math.h:284
typename units::detail::compound_impl< U, Us... >::type compound_unit
Represents a unit type made up from other units.
Definition: base.h:1434
unit_t< scalar > scalar_t
Definition: base.h:2513
namespace for unit-enabled versions of the <cmath> library
Definition: math.h:45
UnitTypeLhs copysign(const UnitTypeLhs x, const UNIT_LIB_DEFAULT_TYPE y) noexcept
Overload to copy the sign from a raw double.
Definition: math.h:619
unit_t scale which is linear
Definition: base.h:2487
Trait which tests whether a type is inherited from a linear scale.
Definition: base.h:2415
Trait which tests whether two container types derived from unit_t are convertible to each other.
Definition: base.h:1826
Traits which tests if a class is a unit
Definition: base.h:1864