mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-27 02:01:42 +00:00
[wpiutil] Split units.h into separate headers for each unit (#2551)
Closes #2508. Co-authored-by: Prateek Machiraju <prateek.machiraju@gmail.com>
This commit is contained in:
758
wpiutil/src/main/native/include/units/math.h
Normal file
758
wpiutil/src/main/native/include/units/math.h
Normal file
@@ -0,0 +1,758 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2020 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
// Copyright (c) 2016 Nic Holthaus
|
||||
//
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "units/angle.h"
|
||||
#include "units/base.h"
|
||||
#include "units/dimensionless.h"
|
||||
|
||||
namespace units {
|
||||
//----------------------------------
|
||||
// UNIT-ENABLED CMATH FUNCTIONS
|
||||
//----------------------------------
|
||||
|
||||
/**
|
||||
* @brief namespace for unit-enabled versions of the `<cmath>` library
|
||||
* @details Includes trigonometric functions, exponential/log functions,
|
||||
* rounding functions, etc.
|
||||
* @sa See `unit_t` for more information on unit type containers.
|
||||
*/
|
||||
namespace math {
|
||||
//----------------------------------
|
||||
// TRIGONOMETRIC FUNCTIONS
|
||||
//----------------------------------
|
||||
|
||||
/**
|
||||
* @ingroup UnitMath
|
||||
* @brief Compute cosine
|
||||
* @details The input value can be in any unit of angle, including radians or
|
||||
* degrees.
|
||||
* @tparam AngleUnit any `unit_t` type of `category::angle_unit`.
|
||||
* @param[in] angle angle to compute the cosine of
|
||||
* @returns Returns the cosine of <i>angle</i>
|
||||
*/
|
||||
#if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS)
|
||||
template <class AngleUnit>
|
||||
dimensionless::scalar_t cos(const AngleUnit angle) noexcept {
|
||||
static_assert(
|
||||
traits::is_angle_unit<AngleUnit>::value,
|
||||
"Type `AngleUnit` must be a unit of angle derived from `unit_t`.");
|
||||
return dimensionless::scalar_t(
|
||||
std::cos(angle.template convert<angle::radian>()()));
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @ingroup UnitMath
|
||||
* @brief Compute sine
|
||||
* @details The input value can be in any unit of angle, including radians or
|
||||
* degrees.
|
||||
* @tparam AngleUnit any `unit_t` type of `category::angle_unit`.
|
||||
* @param[in] angle angle to compute the since of
|
||||
* @returns Returns the sine of <i>angle</i>
|
||||
*/
|
||||
#if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS)
|
||||
template <class AngleUnit>
|
||||
dimensionless::scalar_t sin(const AngleUnit angle) noexcept {
|
||||
static_assert(
|
||||
traits::is_angle_unit<AngleUnit>::value,
|
||||
"Type `AngleUnit` must be a unit of angle derived from `unit_t`.");
|
||||
return dimensionless::scalar_t(
|
||||
std::sin(angle.template convert<angle::radian>()()));
|
||||
}
|
||||
#endif
|
||||
/**
|
||||
* @ingroup UnitMath
|
||||
* @brief Compute tangent
|
||||
* @details The input value can be in any unit of angle, including radians or
|
||||
* degrees.
|
||||
* @tparam AngleUnit any `unit_t` type of `category::angle_unit`.
|
||||
* @param[in] angle angle to compute the tangent of
|
||||
* @returns Returns the tangent of <i>angle</i>
|
||||
*/
|
||||
#if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS)
|
||||
template <class AngleUnit>
|
||||
dimensionless::scalar_t tan(const AngleUnit angle) noexcept {
|
||||
static_assert(
|
||||
traits::is_angle_unit<AngleUnit>::value,
|
||||
"Type `AngleUnit` must be a unit of angle derived from `unit_t`.");
|
||||
return dimensionless::scalar_t(
|
||||
std::tan(angle.template convert<angle::radian>()()));
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @ingroup UnitMath
|
||||
* @brief Compute arc cosine
|
||||
* @details Returns the principal value of the arc cosine of x, expressed in
|
||||
* radians.
|
||||
* @param[in] x Value whose arc cosine is computed, in the interval [-1,+1].
|
||||
* @returns Principal arc cosine of x, in the interval [0,pi] radians.
|
||||
*/
|
||||
#if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS)
|
||||
template <class ScalarUnit>
|
||||
angle::radian_t acos(const ScalarUnit x) noexcept {
|
||||
static_assert(
|
||||
traits::is_dimensionless_unit<ScalarUnit>::value,
|
||||
"Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`.");
|
||||
return angle::radian_t(std::acos(x()));
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @ingroup UnitMath
|
||||
* @brief Compute arc sine
|
||||
* @details Returns the principal value of the arc sine of x, expressed in
|
||||
* radians.
|
||||
* @param[in] x Value whose arc sine is computed, in the interval [-1,+1].
|
||||
* @returns Principal arc sine of x, in the interval [-pi/2,+pi/2] radians.
|
||||
*/
|
||||
#if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS)
|
||||
template <class ScalarUnit>
|
||||
angle::radian_t asin(const ScalarUnit x) noexcept {
|
||||
static_assert(
|
||||
traits::is_dimensionless_unit<ScalarUnit>::value,
|
||||
"Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`.");
|
||||
return angle::radian_t(std::asin(x()));
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @ingroup UnitMath
|
||||
* @brief Compute arc tangent
|
||||
* @details Returns the principal value of the arc tangent of x, expressed in
|
||||
* radians. Notice that because of the sign ambiguity, the function
|
||||
* cannot determine with certainty in which quadrant the angle falls
|
||||
* only by its tangent value. See atan2 for an alternative that takes a
|
||||
* fractional argument instead.
|
||||
* @tparam AngleUnit any `unit_t` type of `category::angle_unit`.
|
||||
* @param[in] x Value whose arc tangent is computed, in the interval [-1,+1].
|
||||
* @returns Principal arc tangent of x, in the interval [-pi/2,+pi/2] radians.
|
||||
*/
|
||||
#if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS)
|
||||
template <class ScalarUnit>
|
||||
angle::radian_t atan(const ScalarUnit x) noexcept {
|
||||
static_assert(
|
||||
traits::is_dimensionless_unit<ScalarUnit>::value,
|
||||
"Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`.");
|
||||
return angle::radian_t(std::atan(x()));
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @ingroup UnitMath
|
||||
* @brief Compute arc tangent with two parameters
|
||||
* @details To compute the value, the function takes into account the sign of
|
||||
* both arguments in order to determine the quadrant.
|
||||
* @param[in] y y-component of the triangle expressed.
|
||||
* @param[in] x x-component of the triangle expressed.
|
||||
* @returns Returns the principal value of the arc tangent of <i>y/x</i>,
|
||||
* expressed in radians.
|
||||
*/
|
||||
#if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS)
|
||||
template <class Y, class X>
|
||||
angle::radian_t atan2(const Y y, const X x) noexcept {
|
||||
static_assert(traits::is_dimensionless_unit<decltype(y / x)>::value,
|
||||
"The quantity y/x must yield a dimensionless ratio.");
|
||||
|
||||
// X and Y could be different length units, so normalize them
|
||||
return angle::radian_t(
|
||||
std::atan2(y.template convert<
|
||||
typename units::traits::unit_t_traits<X>::unit_type>()(),
|
||||
x()));
|
||||
}
|
||||
#endif
|
||||
|
||||
//----------------------------------
|
||||
// HYPERBOLIC TRIG FUNCTIONS
|
||||
//----------------------------------
|
||||
|
||||
/**
|
||||
* @ingroup UnitMath
|
||||
* @brief Compute hyperbolic cosine
|
||||
* @details The input value can be in any unit of angle, including radians or
|
||||
* degrees.
|
||||
* @tparam AngleUnit any `unit_t` type of `category::angle_unit`.
|
||||
* @param[in] angle angle to compute the hyperbolic cosine of
|
||||
* @returns Returns the hyperbolic cosine of <i>angle</i>
|
||||
*/
|
||||
#if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS)
|
||||
template <class AngleUnit>
|
||||
dimensionless::scalar_t cosh(const AngleUnit angle) noexcept {
|
||||
static_assert(
|
||||
traits::is_angle_unit<AngleUnit>::value,
|
||||
"Type `AngleUnit` must be a unit of angle derived from `unit_t`.");
|
||||
return dimensionless::scalar_t(
|
||||
std::cosh(angle.template convert<angle::radian>()()));
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @ingroup UnitMath
|
||||
* @brief Compute hyperbolic sine
|
||||
* @details The input value can be in any unit of angle, including radians or
|
||||
* degrees.
|
||||
* @tparam AngleUnit any `unit_t` type of `category::angle_unit`.
|
||||
* @param[in] angle angle to compute the hyperbolic sine of
|
||||
* @returns Returns the hyperbolic sine of <i>angle</i>
|
||||
*/
|
||||
#if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS)
|
||||
template <class AngleUnit>
|
||||
dimensionless::scalar_t sinh(const AngleUnit angle) noexcept {
|
||||
static_assert(
|
||||
traits::is_angle_unit<AngleUnit>::value,
|
||||
"Type `AngleUnit` must be a unit of angle derived from `unit_t`.");
|
||||
return dimensionless::scalar_t(
|
||||
std::sinh(angle.template convert<angle::radian>()()));
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @ingroup UnitMath
|
||||
* @brief Compute hyperbolic tangent
|
||||
* @details The input value can be in any unit of angle, including radians or
|
||||
* degrees.
|
||||
* @tparam AngleUnit any `unit_t` type of `category::angle_unit`.
|
||||
* @param[in] angle angle to compute the hyperbolic tangent of
|
||||
* @returns Returns the hyperbolic tangent of <i>angle</i>
|
||||
*/
|
||||
#if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS)
|
||||
template <class AngleUnit>
|
||||
dimensionless::scalar_t tanh(const AngleUnit angle) noexcept {
|
||||
static_assert(
|
||||
traits::is_angle_unit<AngleUnit>::value,
|
||||
"Type `AngleUnit` must be a unit of angle derived from `unit_t`.");
|
||||
return dimensionless::scalar_t(
|
||||
std::tanh(angle.template convert<angle::radian>()()));
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @ingroup UnitMath
|
||||
* @brief Compute arc hyperbolic cosine
|
||||
* @details Returns the nonnegative arc hyperbolic cosine of x, expressed in
|
||||
* radians.
|
||||
* @param[in] x Value whose arc hyperbolic cosine is computed. If the argument
|
||||
* is less than 1, a domain error occurs.
|
||||
* @returns Nonnegative arc hyperbolic cosine of x, in the interval
|
||||
* [0,+INFINITY] radians.
|
||||
*/
|
||||
#if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS)
|
||||
template <class ScalarUnit>
|
||||
angle::radian_t acosh(const ScalarUnit x) noexcept {
|
||||
static_assert(
|
||||
traits::is_dimensionless_unit<ScalarUnit>::value,
|
||||
"Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`.");
|
||||
return angle::radian_t(std::acosh(x()));
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @ingroup UnitMath
|
||||
* @brief Compute arc hyperbolic sine
|
||||
* @details Returns the arc hyperbolic sine of x, expressed in radians.
|
||||
* @param[in] x Value whose arc hyperbolic sine is computed.
|
||||
* @returns Arc hyperbolic sine of x, in radians.
|
||||
*/
|
||||
#if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS)
|
||||
template <class ScalarUnit>
|
||||
angle::radian_t asinh(const ScalarUnit x) noexcept {
|
||||
static_assert(
|
||||
traits::is_dimensionless_unit<ScalarUnit>::value,
|
||||
"Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`.");
|
||||
return angle::radian_t(std::asinh(x()));
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @ingroup UnitMath
|
||||
* @brief Compute arc hyperbolic tangent
|
||||
* @details Returns the arc hyperbolic tangent of x, expressed in radians.
|
||||
* @param[in] x Value whose arc hyperbolic tangent is computed, in the interval
|
||||
* [-1,+1]. If the argument is out of this interval, a domain error
|
||||
* occurs. For values of -1 and +1, a pole error may occur.
|
||||
* @returns units::angle::radian_t
|
||||
*/
|
||||
#if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS)
|
||||
template <class ScalarUnit>
|
||||
angle::radian_t atanh(const ScalarUnit x) noexcept {
|
||||
static_assert(
|
||||
traits::is_dimensionless_unit<ScalarUnit>::value,
|
||||
"Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`.");
|
||||
return angle::radian_t(std::atanh(x()));
|
||||
}
|
||||
#endif
|
||||
|
||||
//----------------------------------
|
||||
// TRANSCENDENTAL FUNCTIONS
|
||||
//----------------------------------
|
||||
|
||||
// it makes NO SENSE to put dimensioned units into a transcendental function,
|
||||
// and if you think it does you are demonstrably wrong.
|
||||
// https://en.wikipedia.org/wiki/Transcendental_function#Dimensional_analysis
|
||||
|
||||
/**
|
||||
* @ingroup UnitMath
|
||||
* @brief Compute exponential function
|
||||
* @details Returns the base-e exponential function of x, which is e raised to
|
||||
* the power x: ex.
|
||||
* @param[in] x scalar value of the exponent.
|
||||
* @returns Exponential value of x.
|
||||
* If the magnitude of the result is too large to be represented by a
|
||||
* value of the return type, the function returns HUGE_VAL (or
|
||||
* HUGE_VALF or HUGE_VALL) with the proper sign, and an overflow range
|
||||
* error occurs.
|
||||
*/
|
||||
template <class ScalarUnit>
|
||||
dimensionless::scalar_t exp(const ScalarUnit x) noexcept {
|
||||
static_assert(
|
||||
traits::is_dimensionless_unit<ScalarUnit>::value,
|
||||
"Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`.");
|
||||
return dimensionless::scalar_t(std::exp(x()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup UnitMath
|
||||
* @brief Compute natural logarithm
|
||||
* @details Returns the natural logarithm of x.
|
||||
* @param[in] x scalar value whose logarithm is calculated. If the argument is
|
||||
* negative, a domain error occurs.
|
||||
* @sa log10 for more common base-10 logarithms
|
||||
* @returns Natural logarithm of x.
|
||||
*/
|
||||
template <class ScalarUnit>
|
||||
dimensionless::scalar_t log(const ScalarUnit x) noexcept {
|
||||
static_assert(
|
||||
traits::is_dimensionless_unit<ScalarUnit>::value,
|
||||
"Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`.");
|
||||
return dimensionless::scalar_t(std::log(x()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup UnitMath
|
||||
* @brief Compute common logarithm
|
||||
* @details Returns the common (base-10) logarithm of x.
|
||||
* @param[in] x Value whose logarithm is calculated. If the argument is
|
||||
* negative, a domain error occurs.
|
||||
* @returns Common logarithm of x.
|
||||
*/
|
||||
template <class ScalarUnit>
|
||||
dimensionless::scalar_t log10(const ScalarUnit x) noexcept {
|
||||
static_assert(
|
||||
traits::is_dimensionless_unit<ScalarUnit>::value,
|
||||
"Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`.");
|
||||
return dimensionless::scalar_t(std::log10(x()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup UnitMath
|
||||
* @brief Break into fractional and integral parts.
|
||||
* @details The integer part is stored in the object pointed by intpart, and the
|
||||
* fractional part is returned by the function. Both parts have the
|
||||
* same sign as x.
|
||||
* @param[in] x scalar value to break into parts.
|
||||
* @param[in] intpart Pointer to an object (of the same type as x) where the
|
||||
* integral part is stored with the same sign as x.
|
||||
* @returns The fractional part of x, with the same sign.
|
||||
*/
|
||||
template <class ScalarUnit>
|
||||
dimensionless::scalar_t modf(const ScalarUnit x, ScalarUnit* intpart) noexcept {
|
||||
static_assert(
|
||||
traits::is_dimensionless_unit<ScalarUnit>::value,
|
||||
"Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`.");
|
||||
|
||||
UNIT_LIB_DEFAULT_TYPE intp;
|
||||
dimensionless::scalar_t fracpart =
|
||||
dimensionless::scalar_t(std::modf(x(), &intp));
|
||||
*intpart = intp;
|
||||
return fracpart;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup UnitMath
|
||||
* @brief Compute binary exponential function
|
||||
* @details Returns the base-2 exponential function of x, which is 2 raised to
|
||||
* the power x: 2^x. 2param[in] x Value of the exponent.
|
||||
* @returns 2 raised to the power of x.
|
||||
*/
|
||||
template <class ScalarUnit>
|
||||
dimensionless::scalar_t exp2(const ScalarUnit x) noexcept {
|
||||
static_assert(
|
||||
traits::is_dimensionless_unit<ScalarUnit>::value,
|
||||
"Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`.");
|
||||
return dimensionless::scalar_t(std::exp2(x()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup UnitMath
|
||||
* @brief Compute exponential minus one
|
||||
* @details Returns e raised to the power x minus one: e^x-1. For small
|
||||
* magnitude values of x, expm1 may be more accurate than exp(x)-1.
|
||||
* @param[in] x Value of the exponent.
|
||||
* @returns e raised to the power of x, minus one.
|
||||
*/
|
||||
template <class ScalarUnit>
|
||||
dimensionless::scalar_t expm1(const ScalarUnit x) noexcept {
|
||||
static_assert(
|
||||
traits::is_dimensionless_unit<ScalarUnit>::value,
|
||||
"Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`.");
|
||||
return dimensionless::scalar_t(std::expm1(x()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup UnitMath
|
||||
* @brief Compute logarithm plus one
|
||||
* @details Returns the natural logarithm of one plus x. For small magnitude
|
||||
* values of x, logp1 may be more accurate than log(1+x).
|
||||
* @param[in] x Value whose logarithm is calculated. If the argument is less
|
||||
* than -1, a domain error occurs.
|
||||
* @returns The natural logarithm of (1+x).
|
||||
*/
|
||||
template <class ScalarUnit>
|
||||
dimensionless::scalar_t log1p(const ScalarUnit x) noexcept {
|
||||
static_assert(
|
||||
traits::is_dimensionless_unit<ScalarUnit>::value,
|
||||
"Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`.");
|
||||
return dimensionless::scalar_t(std::log1p(x()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup UnitMath
|
||||
* @brief Compute binary logarithm
|
||||
* @details Returns the binary (base-2) logarithm of x.
|
||||
* @param[in] x Value whose logarithm is calculated. If the argument is
|
||||
* negative, a domain error occurs.
|
||||
* @returns The binary logarithm of x: log2x.
|
||||
*/
|
||||
template <class ScalarUnit>
|
||||
dimensionless::scalar_t log2(const ScalarUnit x) noexcept {
|
||||
static_assert(
|
||||
traits::is_dimensionless_unit<ScalarUnit>::value,
|
||||
"Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`.");
|
||||
return dimensionless::scalar_t(std::log2(x()));
|
||||
}
|
||||
|
||||
//----------------------------------
|
||||
// POWER FUNCTIONS
|
||||
//----------------------------------
|
||||
|
||||
/* pow is implemented earlier in the library since a lot of the unit definitions
|
||||
* depend on it */
|
||||
|
||||
/**
|
||||
* @ingroup UnitMath
|
||||
* @brief computes the square root of <i>value</i>
|
||||
* @details Only implemented for linear_scale units.
|
||||
* @param[in] value `unit_t` derived type to compute the square root of.
|
||||
* @returns new unit_t, whose units are the square root of value's.
|
||||
* E.g. if values had units of `square_meter`, then the return type
|
||||
* will have units of `meter`.
|
||||
* @note `sqrt` provides a _rational approximation_ of the square root of
|
||||
* <i>value</i>. In some cases, _both_ the returned value _and_ conversion
|
||||
* factor of the returned unit type may have errors no larger than
|
||||
* `1e-10`.
|
||||
*/
|
||||
template <
|
||||
class UnitType,
|
||||
std::enable_if_t<units::traits::has_linear_scale<UnitType>::value, int> = 0>
|
||||
inline 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> {
|
||||
return unit_t<
|
||||
square_root<typename units::traits::unit_t_traits<UnitType>::unit_type>,
|
||||
typename units::traits::unit_t_traits<UnitType>::underlying_type,
|
||||
linear_scale>(std::sqrt(value()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup UnitMath
|
||||
* @brief Computes the square root of the sum-of-squares of x and y.
|
||||
* @details Only implemented for linear_scale units.
|
||||
* @param[in] x unit_t type value
|
||||
* @param[in] y unit_t type value
|
||||
* @returns square root of the sum-of-squares of x and y in the same units as x.
|
||||
*/
|
||||
template <class UnitTypeLhs, class UnitTypeRhs,
|
||||
std::enable_if_t<
|
||||
units::traits::has_linear_scale<UnitTypeLhs, UnitTypeRhs>::value,
|
||||
int> = 0>
|
||||
inline UnitTypeLhs hypot(const UnitTypeLhs& x, const UnitTypeRhs& y) {
|
||||
static_assert(traits::is_convertible_unit_t<UnitTypeLhs, UnitTypeRhs>::value,
|
||||
"Parameters of hypot() function are not compatible units.");
|
||||
return UnitTypeLhs(std::hypot(
|
||||
x(),
|
||||
y.template convert<
|
||||
typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type>()()));
|
||||
}
|
||||
|
||||
//----------------------------------
|
||||
// ROUNDING FUNCTIONS
|
||||
//----------------------------------
|
||||
|
||||
/**
|
||||
* @ingroup UnitMath
|
||||
* @brief Round up value
|
||||
* @details Rounds x upward, returning the smallest integral value that is not
|
||||
* less than x.
|
||||
* @param[in] x Unit value to round up.
|
||||
* @returns The smallest integral value that is not less than x.
|
||||
*/
|
||||
template <class UnitType,
|
||||
class = std::enable_if_t<traits::is_unit_t<UnitType>::value>>
|
||||
UnitType ceil(const UnitType x) noexcept {
|
||||
return UnitType(std::ceil(x()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup UnitMath
|
||||
* @brief Round down value
|
||||
* @details Rounds x downward, returning the largest integral value that is not
|
||||
* greater than x.
|
||||
* @param[in] x Unit value to round down.
|
||||
* @returns The value of x rounded downward.
|
||||
*/
|
||||
template <class UnitType,
|
||||
class = std::enable_if_t<traits::is_unit_t<UnitType>::value>>
|
||||
UnitType floor(const UnitType x) noexcept {
|
||||
return UnitType(std::floor(x()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup UnitMath
|
||||
* @brief Compute remainder of division
|
||||
* @details Returns the floating-point remainder of numer/denom (rounded towards
|
||||
* zero).
|
||||
* @param[in] numer Value of the quotient numerator.
|
||||
* @param[in] denom Value of the quotient denominator.
|
||||
* @returns The remainder of dividing the arguments.
|
||||
*/
|
||||
template <class UnitTypeLhs, class UnitTypeRhs,
|
||||
class = std::enable_if_t<traits::is_unit_t<UnitTypeLhs>::value &&
|
||||
traits::is_unit_t<UnitTypeRhs>::value>>
|
||||
UnitTypeLhs fmod(const UnitTypeLhs numer, const UnitTypeRhs denom) noexcept {
|
||||
static_assert(traits::is_convertible_unit_t<UnitTypeLhs, UnitTypeRhs>::value,
|
||||
"Parameters of fmod() function are not compatible units.");
|
||||
return UnitTypeLhs(std::fmod(
|
||||
numer(),
|
||||
denom.template convert<
|
||||
typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type>()()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup UnitMath
|
||||
* @brief Truncate value
|
||||
* @details Rounds x toward zero, returning the nearest integral value that is
|
||||
* not larger in magnitude than x. Effectively rounds towards 0.
|
||||
* @param[in] x Value to truncate
|
||||
* @returns The nearest integral value that is not larger in magnitude than x.
|
||||
*/
|
||||
template <class UnitType,
|
||||
class = std::enable_if_t<traits::is_unit_t<UnitType>::value>>
|
||||
UnitType trunc(const UnitType x) noexcept {
|
||||
return UnitType(std::trunc(x()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup UnitMath
|
||||
* @brief Round to nearest
|
||||
* @details Returns the integral value that is nearest to x, with halfway cases
|
||||
* rounded away from zero.
|
||||
* @param[in] x value to round.
|
||||
* @returns The value of x rounded to the nearest integral.
|
||||
*/
|
||||
template <class UnitType,
|
||||
class = std::enable_if_t<traits::is_unit_t<UnitType>::value>>
|
||||
UnitType round(const UnitType x) noexcept {
|
||||
return UnitType(std::round(x()));
|
||||
}
|
||||
|
||||
//----------------------------------
|
||||
// FLOATING POINT MANIPULATION
|
||||
//----------------------------------
|
||||
|
||||
/**
|
||||
* @ingroup UnitMath
|
||||
* @brief Copy sign
|
||||
* @details Returns a value with the magnitude and dimension of x, and the sign
|
||||
* of y. Values x and y do not have to be compatible units.
|
||||
* @param[in] x Value with the magnitude of the resulting value.
|
||||
* @param[in] y Value with the sign of the resulting value.
|
||||
* @returns value with the magnitude and dimension of x, and the sign of y.
|
||||
*/
|
||||
template <class UnitTypeLhs, class UnitTypeRhs,
|
||||
class = std::enable_if_t<traits::is_unit_t<UnitTypeLhs>::value &&
|
||||
traits::is_unit_t<UnitTypeRhs>::value>>
|
||||
UnitTypeLhs copysign(const UnitTypeLhs x, const UnitTypeRhs y) noexcept {
|
||||
return UnitTypeLhs(std::copysign(
|
||||
x(), y())); // no need for conversion to get the correct sign.
|
||||
}
|
||||
|
||||
/// Overload to copy the sign from a raw double
|
||||
template <class UnitTypeLhs,
|
||||
class = std::enable_if_t<traits::is_unit_t<UnitTypeLhs>::value>>
|
||||
UnitTypeLhs copysign(const UnitTypeLhs x,
|
||||
const UNIT_LIB_DEFAULT_TYPE y) noexcept {
|
||||
return UnitTypeLhs(std::copysign(x(), y));
|
||||
}
|
||||
|
||||
//----------------------------------
|
||||
// MIN / MAX / DIFFERENCE
|
||||
//----------------------------------
|
||||
|
||||
/**
|
||||
* @ingroup UnitMath
|
||||
* @brief Positive difference
|
||||
* @details The function returns x-y if x>y, and zero otherwise, in the same
|
||||
* units as x. Values x and y do not have to be the same type of units,
|
||||
* but they do have to be compatible.
|
||||
* @param[in] x Values whose difference is calculated.
|
||||
* @param[in] y Values whose difference is calculated.
|
||||
* @returns The positive difference between x and y.
|
||||
*/
|
||||
template <class UnitTypeLhs, class UnitTypeRhs,
|
||||
class = std::enable_if_t<traits::is_unit_t<UnitTypeLhs>::value &&
|
||||
traits::is_unit_t<UnitTypeRhs>::value>>
|
||||
UnitTypeLhs fdim(const UnitTypeLhs x, const UnitTypeRhs y) noexcept {
|
||||
static_assert(traits::is_convertible_unit_t<UnitTypeLhs, UnitTypeRhs>::value,
|
||||
"Parameters of fdim() function are not compatible units.");
|
||||
return UnitTypeLhs(std::fdim(
|
||||
x(),
|
||||
y.template convert<
|
||||
typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type>()()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup UnitMath
|
||||
* @brief Maximum value
|
||||
* @details Returns the larger of its arguments: either x or y, in the same
|
||||
* units as x. Values x and y do not have to be the same type of units,
|
||||
* but they do have to be compatible.
|
||||
* @param[in] x Values among which the function selects a maximum.
|
||||
* @param[in] y Values among which the function selects a maximum.
|
||||
* @returns The maximum numeric value of its arguments.
|
||||
*/
|
||||
template <class UnitTypeLhs, class UnitTypeRhs,
|
||||
class = std::enable_if_t<traits::is_unit_t<UnitTypeLhs>::value &&
|
||||
traits::is_unit_t<UnitTypeRhs>::value>>
|
||||
UnitTypeLhs fmax(const UnitTypeLhs x, const UnitTypeRhs y) noexcept {
|
||||
static_assert(traits::is_convertible_unit_t<UnitTypeLhs, UnitTypeRhs>::value,
|
||||
"Parameters of fmax() function are not compatible units.");
|
||||
return UnitTypeLhs(std::fmax(
|
||||
x(),
|
||||
y.template convert<
|
||||
typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type>()()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup UnitMath
|
||||
* @brief Minimum value
|
||||
* @details Returns the smaller of its arguments: either x or y, in the same
|
||||
* units as x. If one of the arguments in a NaN, the other is returned.
|
||||
* Values x and y do not have to be the same type of units, but they do
|
||||
* have to be compatible.
|
||||
* @param[in] x Values among which the function selects a minimum.
|
||||
* @param[in] y Values among which the function selects a minimum.
|
||||
* @returns The minimum numeric value of its arguments.
|
||||
*/
|
||||
template <class UnitTypeLhs, class UnitTypeRhs,
|
||||
class = std::enable_if_t<traits::is_unit_t<UnitTypeLhs>::value &&
|
||||
traits::is_unit_t<UnitTypeRhs>::value>>
|
||||
UnitTypeLhs fmin(const UnitTypeLhs x, const UnitTypeRhs y) noexcept {
|
||||
static_assert(traits::is_convertible_unit_t<UnitTypeLhs, UnitTypeRhs>::value,
|
||||
"Parameters of fmin() function are not compatible units.");
|
||||
return UnitTypeLhs(std::fmin(
|
||||
x(),
|
||||
y.template convert<
|
||||
typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type>()()));
|
||||
}
|
||||
|
||||
//----------------------------------
|
||||
// OTHER FUNCTIONS
|
||||
//----------------------------------
|
||||
|
||||
/**
|
||||
* @ingroup UnitMath
|
||||
* @brief Compute absolute value
|
||||
* @details Returns the absolute value of x, i.e. |x|.
|
||||
* @param[in] x Value whose absolute value is returned.
|
||||
* @returns The absolute value of x.
|
||||
*/
|
||||
template <class UnitType,
|
||||
class = std::enable_if_t<traits::is_unit_t<UnitType>::value>>
|
||||
UnitType fabs(const UnitType x) noexcept {
|
||||
return UnitType(std::fabs(x()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup UnitMath
|
||||
* @brief Compute absolute value
|
||||
* @details Returns the absolute value of x, i.e. |x|.
|
||||
* @param[in] x Value whose absolute value is returned.
|
||||
* @returns The absolute value of x.
|
||||
*/
|
||||
template <class UnitType,
|
||||
class = std::enable_if_t<traits::is_unit_t<UnitType>::value>>
|
||||
UnitType abs(const UnitType x) noexcept {
|
||||
return UnitType(std::fabs(x()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup UnitMath
|
||||
* @brief Multiply-add
|
||||
* @details Returns x*y+z. The function computes the result without losing
|
||||
* precision in any intermediate result. The resulting unit type is a
|
||||
* compound unit of x* y.
|
||||
* @param[in] x Values to be multiplied.
|
||||
* @param[in] y Values to be multiplied.
|
||||
* @param[in] z Value to be added.
|
||||
* @returns The result of x*y+z
|
||||
*/
|
||||
template <class UnitTypeLhs, class UnitMultiply, class UnitAdd,
|
||||
class = std::enable_if_t<traits::is_unit_t<UnitTypeLhs>::value &&
|
||||
traits::is_unit_t<UnitMultiply>::value &&
|
||||
traits::is_unit_t<UnitAdd>::value>>
|
||||
auto fma(const UnitTypeLhs x, const UnitMultiply y, const UnitAdd z) noexcept
|
||||
-> decltype(x * y) {
|
||||
using resultType = decltype(x * y);
|
||||
static_assert(
|
||||
traits::is_convertible_unit_t<
|
||||
compound_unit<
|
||||
typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type,
|
||||
typename units::traits::unit_t_traits<UnitMultiply>::unit_type>,
|
||||
typename units::traits::unit_t_traits<UnitAdd>::unit_type>::value,
|
||||
"Unit types are not compatible.");
|
||||
return resultType(std::fma(x(), y(), resultType(z)()));
|
||||
}
|
||||
|
||||
} // namespace math
|
||||
} // namespace units
|
||||
Reference in New Issue
Block a user