diff --git a/src/include/units/quantity.h b/src/include/units/quantity.h index 6425fba6..dc6ac1ff 100644 --- a/src/include/units/quantity.h +++ b/src/include/units/quantity.h @@ -353,7 +353,11 @@ template; - return common_rep(lhs.count()) * common_rep(rhs.count()) * common_rep(ratio::num) * std::pow(10, common_rep(ratio::exp)) / common_rep(ratio::den); + if constexpr (treat_as_floating_point) { + return common_rep(lhs.count()) * common_rep(rhs.count()) * common_rep(ratio::num) * fpow10(ratio::exp) / common_rep(ratio::den); + } else { + return common_rep(lhs.count()) * common_rep(rhs.count()) * common_rep(ratio::num) * ipow10(ratio::exp) / common_rep(ratio::den); + } } template diff --git a/src/include/units/quantity_cast.h b/src/include/units/quantity_cast.h index ac019d82..8d6fd270 100644 --- a/src/include/units/quantity_cast.h +++ b/src/include/units/quantity_cast.h @@ -24,10 +24,40 @@ #include #include -#include namespace units { +constexpr std::intmax_t ipow10(std::intmax_t exp) { + // how to assert here? + // static_assert(exp >= 0, "Use fpow10() for negative exponents"); + if (exp == 0) return 1; + std::intmax_t result = 1; + while (exp > 0) { + result *= 10; + --exp; + } + return result; +} + + +constexpr long double fpow10(std::intmax_t exp) { + if (exp == 0) return 1.0L; + long double result = 1.0L; + if (exp < 0) { + while (exp < 0) { + result /= 10.0L; + ++exp; + } + } else { + while (exp > 0) { + result *= 10.0L; + --exp; + } + } + return result; +} + + // QuantityOf template concept QuantityOf = Quantity && Dimension && equivalent_dim; @@ -42,15 +72,15 @@ struct quantity_cast_impl { { if constexpr (treat_as_floating_point) { return To(static_cast(static_cast(q.count()) * - static_cast(std::pow(10, CRatio::exp)) * + static_cast(fpow10(CRatio::exp)) * (static_cast(CRatio::num) / static_cast(CRatio::den)))); } else { return To(static_cast(static_cast(q.count()) * static_cast(CRatio::num) * - static_cast(CRatio::exp > 0 ? std::pow(10, CRatio::exp) : 1) / + static_cast(CRatio::exp > 0 ? ipow10(CRatio::exp) : 1) / (static_cast(CRatio::den) * - static_cast(CRatio::exp < 0 ? std::pow(10, -CRatio::exp) : 1)))); + static_cast(CRatio::exp < 0 ? ipow10(-CRatio::exp) : 1)))); } } }; @@ -60,7 +90,11 @@ struct quantity_cast_impl { template static constexpr To cast(const Q& q) { - return To(static_cast(static_cast(q.count()) * static_cast(std::pow(10, CRatio::exp)))); + if constexpr (treat_as_floating_point) { + return To(static_cast(static_cast(q.count()) * static_cast(fpow10(CRatio::exp)))); + } else { + return To(static_cast(static_cast(q.count()) * static_cast(ipow10(CRatio::exp)))); + } } }; @@ -70,9 +104,9 @@ struct quantity_cast_impl { static constexpr To cast(const Q& q) { if constexpr (treat_as_floating_point) { - return To(static_cast(static_cast(q.count()) * static_cast(std::pow(10, CRatio::exp)) * (CRep{1} / static_cast(CRatio::den)))); + return To(static_cast(static_cast(q.count()) * static_cast(fpow10(CRatio::exp)) * (CRep{1} / static_cast(CRatio::den)))); } else { - return To(static_cast(static_cast(q.count()) * static_cast(std::pow(10, CRatio::exp)) / static_cast(CRatio::den))); + return To(static_cast(static_cast(q.count()) * static_cast(ipow10(CRatio::exp)) / static_cast(CRatio::den))); } } }; @@ -82,7 +116,11 @@ struct quantity_cast_impl { template static constexpr To cast(const Q& q) { - return To(static_cast(static_cast(q.count()) * static_cast(CRatio::num) * static_cast(std::pow(10, CRatio::exp)))); + if constexpr (treat_as_floating_point) { + return To(static_cast(static_cast(q.count()) * static_cast(CRatio::num) * static_cast(fpow10(CRatio::exp)))); + } else { + return To(static_cast(static_cast(q.count()) * static_cast(CRatio::num) * static_cast(ipow10(CRatio::exp)))); + } } };