diff --git a/src/utility/include/mp-units/math.h b/src/utility/include/mp-units/math.h index 6e8291b5..094f4b6e 100644 --- a/src/utility/include/mp-units/math.h +++ b/src/utility/include/mp-units/math.h @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -49,20 +50,20 @@ namespace mp_units { * @param q Quantity being the base of the operation * @return Quantity The result of computation */ -template - requires detail::non_zero -[[nodiscard]] constexpr Quantity auto pow(const Q& q) noexcept - requires requires { pow(q.number(), 1.0); } || requires { std::pow(q.number(), 1.0); } +template + requires detail::non_zero && + requires { quantity_values::one(); } + [[nodiscard]] constexpr quantity(R), Rep> pow(const quantity& q) noexcept + requires requires { pow(q.number(), 1.0); } || requires { std::pow(q.number(), 1.0); } { - using rep = TYPENAME Q::rep; if constexpr (Num == 0) { - return quantity(Q::reference), rep>::one(); + return quantity(R), Rep>::one(); } else if constexpr (ratio{Num, Den} == 1) { return q; } else { using std::pow; - return make_quantity(Q::reference)>( - static_cast(pow(q.number(), static_cast(Num) / static_cast(Den)))); + return make_quantity(R)>( + static_cast(pow(q.number(), static_cast(Num) / static_cast(Den)))); } } @@ -74,13 +75,12 @@ template * @param q Quantity being the base of the operation * @return Quantity The result of computation */ -template -[[nodiscard]] constexpr Quantity auto sqrt(const Q& q) noexcept +template +[[nodiscard]] constexpr quantity sqrt(const quantity& q) noexcept requires requires { sqrt(q.number()); } || requires { std::sqrt(q.number()); } { - using rep = TYPENAME Q::rep; using std::sqrt; - return make_quantity(static_cast(sqrt(q.number()))); + return make_quantity(static_cast(sqrt(q.number()))); } /** @@ -91,13 +91,12 @@ template * @param q Quantity being the base of the operation * @return Quantity The result of computation */ -template -[[nodiscard]] constexpr Quantity auto cbrt(const Q& q) noexcept +template +[[nodiscard]] constexpr quantity cbrt(const quantity& q) noexcept requires requires { cbrt(q.number()); } || requires { std::cbrt(q.number()); } { - using rep = TYPENAME Q::rep; using std::cbrt; - return make_quantity(static_cast(cbrt(q.number()))); + return make_quantity(static_cast(cbrt(q.number()))); } /** @@ -108,12 +107,13 @@ template * @param q Quantity being the base of the operation * @return Quantity The value of the same quantity type */ -template Q> -[[nodiscard]] constexpr Q exp(const Q& q) +template auto R, typename Rep> +[[nodiscard]] constexpr quantity exp(const quantity& q) requires requires { exp(q.number()); } || requires { std::exp(q.number()); } { using std::exp; - return value_cast(make_quantity(exp(value_cast(q).number()))); + return value_cast( + make_quantity(R)>(static_cast(exp(value_cast(q).number())))); } /** @@ -122,12 +122,12 @@ template Q> * @param q Quantity being the base of the operation * @return Quantity The absolute value of a provided quantity */ -template -[[nodiscard]] constexpr Q abs(const Q& q) noexcept +template +[[nodiscard]] constexpr quantity abs(const quantity& q) noexcept requires requires { abs(q.number()); } || requires { std::abs(q.number()); } { using std::abs; - return make_quantity(abs(q.number())); + return make_quantity(static_cast(abs(q.number()))); } /** @@ -140,9 +140,9 @@ template */ template requires requires { std::numeric_limits::epsilon(); } -[[nodiscard]] constexpr Quantity auto epsilon(R r) noexcept +[[nodiscard]] constexpr quantity epsilon(R r) noexcept { - return make_quantity(std::numeric_limits::epsilon()); + return make_quantity(static_cast(std::numeric_limits::epsilon())); } /** @@ -152,12 +152,12 @@ template * @return Quantity The rounded quantity with unit type To */ template -[[nodiscard]] constexpr quantity{}, Rep> floor(const quantity& q) noexcept +[[nodiscard]] constexpr quantity(R), Rep> floor(const quantity& q) noexcept requires((!treat_as_floating_point) || requires { floor(q.number()); } || requires { std::floor(q.number()); }) && (To == get_unit(R) || requires { ::mp_units::value_cast(q); - quantity{}, Rep>::one(); + quantity_values::one(); }) { const auto handle_signed_results = [&](const T& res) { @@ -169,10 +169,10 @@ template if constexpr (treat_as_floating_point) { using std::floor; if constexpr (To == get_unit(R)) { - return make_quantity{}>(floor(q.number())); + return make_quantity(R)>(static_cast(floor(q.number()))); } else { - return handle_signed_results( - make_quantity{}>(floor(value_cast(q).number()))); + return handle_signed_results(make_quantity(q.reference)>( + static_cast(floor(value_cast(q).number())))); } } else { if constexpr (To == get_unit(R)) { @@ -190,11 +190,11 @@ template * @return Quantity The rounded quantity with unit type To */ template -[[nodiscard]] constexpr quantity{}, Rep> ceil(const quantity& q) noexcept +[[nodiscard]] constexpr quantity(R), Rep> ceil(const quantity& q) noexcept requires((!treat_as_floating_point) || requires { ceil(q.number()); } || requires { std::ceil(q.number()); }) && (To == get_unit(R) || requires { ::mp_units::value_cast(q); - quantity{}, Rep>::one(); + quantity_values::one(); }) { const auto handle_signed_results = [&](const T& res) { @@ -206,10 +206,10 @@ template if constexpr (treat_as_floating_point) { using std::ceil; if constexpr (To == get_unit(R)) { - return make_quantity{}>(ceil(q.number())); + return make_quantity(q.reference)>(static_cast(ceil(q.number()))); } else { - return handle_signed_results( - make_quantity{}>(ceil(value_cast(q).number()))); + return handle_signed_results(make_quantity(q.reference)>( + static_cast(ceil(value_cast(q).number())))); } } else { if constexpr (To == get_unit(R)) { @@ -229,18 +229,18 @@ template * @return Quantity The rounded quantity with unit type To */ template -[[nodiscard]] constexpr quantity{}, Rep> round(const quantity& q) noexcept +[[nodiscard]] constexpr quantity(R), Rep> round(const quantity& q) noexcept requires((!treat_as_floating_point) || requires { round(q.number()); } || requires { std::round(q.number()); }) && (To == get_unit(R) || requires { ::mp_units::floor(q); - quantity{}, Rep>::one(); + quantity_values::one(); }) { if constexpr (To == get_unit(R)) { if constexpr (treat_as_floating_point) { using std::round; - return make_quantity{}>(round(q.number())); + return make_quantity(q.reference)>(static_cast(round(q.number()))); } else { return value_cast(q); } @@ -266,148 +266,148 @@ template * @brief Computes the square root of the sum of the squares of x and y, * without undue overflow or underflow at intermediate stages of the computation */ -template -[[nodiscard]] constexpr QuantityOf auto hypot( - const Q1& x, const Q2& y) noexcept - requires requires { common_reference(Q1::reference, Q2::reference); } && +template +[[nodiscard]] constexpr QuantityOf auto hypot( + const quantity& x, const quantity& y) noexcept + requires requires { common_reference(R1, R2); } && ( requires { hypot(x.number(), y.number()); } || requires { std::hypot(x.number(), y.number()); }) { + constexpr auto ref = common_reference(R1, R2); + constexpr auto unit = get_unit(ref); using std::hypot; - using type = quantity; - return make_quantity(hypot(type{x}.number(), type{y}.number())); + return make_quantity(hypot(x.number_in(unit), y.number_in(unit))); } /** * @brief Computes the square root of the sum of the squares of x, y, and z, * without undue overflow or underflow at intermediate stages of the computation */ -template -[[nodiscard]] constexpr QuantityOf auto -hypot(const Q1& x, const Q2& y, const Q3& z) noexcept - requires requires { common_reference(Q1::reference, Q2::reference, Q3::reference); } && - ( - requires { hypot(x.number(), y.number(), z.number()); } || - requires { std::hypot(x.number(), y.number(), z.number()); }) +template +[[nodiscard]] constexpr QuantityOf auto hypot( + const quantity& x, const quantity& y, const quantity& z) noexcept + requires requires { common_reference(R1, R2, R3); } && ( + requires { hypot(x.number(), y.number(), z.number()); } || + requires { std::hypot(x.number(), y.number(), z.number()); }) { + constexpr auto ref = common_reference(R1, R2); + constexpr auto unit = get_unit(ref); using std::hypot; - using type = quantity; - return make_quantity(hypot(type{x}.number(), type{y}.number(), type{z}.number())); + return make_quantity(hypot(x.number_in(unit), y.number_in(unit), z.number_in(unit))); } namespace isq { -template Q> - requires treat_as_floating_point -[[nodiscard]] inline QuantityOf auto sin(const Q& q) noexcept +template auto R, typename Rep> + requires treat_as_floating_point +[[nodiscard]] inline quantity sin(const quantity& q) noexcept requires requires { sin(q.number()); } || requires { std::sin(q.number()); } { using std::sin; - return make_quantity(sin(q[si::radian].number())); + return make_quantity(static_cast(sin(q[si::radian].number()))); } -template Q> - requires treat_as_floating_point -[[nodiscard]] inline QuantityOf auto cos(const Q& q) noexcept +template auto R, typename Rep> + requires treat_as_floating_point +[[nodiscard]] inline quantity cos(const quantity& q) noexcept requires requires { cos(q.number()); } || requires { std::cos(q.number()); } { using std::cos; - return make_quantity(cos(q[si::radian].number())); + return make_quantity(static_cast(cos(q[si::radian].number()))); } -template Q> - requires treat_as_floating_point -[[nodiscard]] inline QuantityOf auto tan(const Q& q) noexcept +template auto R, typename Rep> + requires treat_as_floating_point +[[nodiscard]] inline quantity tan(const quantity& q) noexcept requires requires { tan(q.number()); } || requires { std::tan(q.number()); } { using std::tan; - return make_quantity(tan(q[si::radian].number())); + return make_quantity(static_cast(tan(q[si::radian].number()))); } -template Q> - requires treat_as_floating_point -[[nodiscard]] inline QuantityOf auto asin(const Q& q) noexcept +template auto R, typename Rep> + requires treat_as_floating_point +[[nodiscard]] inline quantity asin(const quantity& q) noexcept requires requires { asin(q.number()); } || requires { std::asin(q.number()); } { using std::asin; - return make_quantity(asin(value_cast(q).number())); + return make_quantity(static_cast(asin(value_cast(q).number()))); } -template Q> - requires treat_as_floating_point -[[nodiscard]] inline QuantityOf auto acos(const Q& q) noexcept +template auto R, typename Rep> + requires treat_as_floating_point +[[nodiscard]] inline quantity acos(const quantity& q) noexcept requires requires { acos(q.number()); } || requires { std::acos(q.number()); } { using std::acos; - return make_quantity(acos(value_cast(q).number())); + return make_quantity(static_cast(acos(value_cast(q).number()))); } -template Q> - requires treat_as_floating_point -[[nodiscard]] inline QuantityOf auto atan(const Q& q) noexcept +template auto R, typename Rep> + requires treat_as_floating_point +[[nodiscard]] inline quantity atan(const quantity& q) noexcept requires requires { atan(q.number()); } || requires { std::atan(q.number()); } { using std::atan; - return make_quantity(atan(value_cast(q).number())); + return make_quantity(static_cast(atan(value_cast(q).number()))); } } // namespace isq namespace angular { -template Q> - requires treat_as_floating_point -[[nodiscard]] inline QuantityOf auto sin(const Q& q) noexcept +template auto R, typename Rep> + requires treat_as_floating_point +[[nodiscard]] inline quantity sin(const quantity& q) noexcept requires requires { sin(q.number()); } || requires { std::sin(q.number()); } { using std::sin; - return sin(q[radian].number()) * one; + return make_quantity(static_cast(sin(q[radian].number()))); } -template Q> - requires treat_as_floating_point -[[nodiscard]] inline QuantityOf auto cos(const Q& q) noexcept +template auto R, typename Rep> + requires treat_as_floating_point +[[nodiscard]] inline quantity cos(const quantity& q) noexcept requires requires { cos(q.number()); } || requires { std::cos(q.number()); } { using std::cos; - return cos(q[radian].number()) * one; + return make_quantity(static_cast(cos(q[radian].number()))); } -template Q> - requires treat_as_floating_point -[[nodiscard]] inline QuantityOf auto tan(const Q& q) noexcept +template auto R, typename Rep> + requires treat_as_floating_point +[[nodiscard]] inline quantity tan(const quantity& q) noexcept requires requires { tan(q.number()); } || requires { std::tan(q.number()); } { using std::tan; - return tan(q[radian].number()) * one; + return make_quantity(static_cast(tan(q[radian].number()))); } -template Q> - requires treat_as_floating_point -[[nodiscard]] inline QuantityOf auto asin(const Q& q) noexcept +template auto R, typename Rep> + requires treat_as_floating_point +[[nodiscard]] inline quantity asin(const quantity& q) noexcept requires requires { asin(q.number()); } || requires { std::asin(q.number()); } { using std::asin; - return asin(value_cast(q).number()) * angle[radian]; + return make_quantity(static_cast(asin(value_cast(q).number()))); } -template Q> - requires treat_as_floating_point -[[nodiscard]] inline QuantityOf auto acos(const Q& q) noexcept +template auto R, typename Rep> + requires treat_as_floating_point +[[nodiscard]] inline quantity acos(const quantity& q) noexcept requires requires { acos(q.number()); } || requires { std::acos(q.number()); } { using std::acos; - return acos(value_cast(q).number()) * angle[radian]; + return make_quantity(static_cast(acos(value_cast(q).number()))); } -template Q> - requires treat_as_floating_point -[[nodiscard]] inline QuantityOf auto atan(const Q& q) noexcept +template auto R, typename Rep> + requires treat_as_floating_point +[[nodiscard]] inline quantity atan(const quantity& q) noexcept requires requires { atan(q.number()); } || requires { std::atan(q.number()); } { using std::atan; - return atan(value_cast(q).number()) * angle[radian]; + return make_quantity(static_cast(atan(value_cast(q).number()))); } } // namespace angular