mirror of
https://github.com/mpusz/mp-units.git
synced 2025-07-31 10:57:16 +02:00
implementing ratio<num,den,exp> which replaces ratio<num,den>
https://github.com/mpusz/units/issues/14 This "works", as in it passes all static and runtime tests. However quite a few of the tests have been "modified" to make them pass. Whether this is legitimate is debatable and should be the source of some thought / discussion. 1. many of the static tests and some of the runtime tests have had the input ratios of the tests modified in the following way. eg ratio<3,1000> => ratio<3,1,-3>. ie they have been "canonicalised". There are obviously an infinite number of ratios which represent the same rational number. The way `ratio` is implemented it always moves as "many powers of 10" from the `num` and `den` into the `exp` and that makes the `canonical` ratio. Because these are all "types" and the lib uses is_same all over the place, only exact matches will be `is_same`. ie ratio<300,4,0> !is_same ratio<3,4,2> (the latter is the canonical ratio). This is perhaps fine for tests in the devlopment phase, but there may be a need for "more forgiving" comparison / concept of value equality. One such comparison which compares den,num,exp after canonicalisation is the constexpr function `same` as defined at top of `ratio_test.cpp`. We may need to expose this and perhaps add even more soft comparisions. 2. In the runtime tests it is "subjective" how some resukts should be printed. There is the question of "how exactly to format certain ratios". eg omit denominators of "1" and exponents of "0". However before even addressing these in detail a decision needs to be made about the general form of "non-floating-point-converted" ratios which do not map exactly to a "Symbol prefix". Arguably these are "relatively ugly" whatever we do, so we could just go for an easily canonicalised form. An example is: - CHECK(stream.str() == "10 [1/60]W"); + CHECK(stream.str() == "10 [1/6 x 10⁻¹]W"); Which of thses is "better"? Is there a "third", better form? It's not obvious. My opnion is: Both of 1&2 are fine for now, unless we think they go down the wrong avenue, and can be "perfected later"? ie we can expose a softer version of ratio based equality, and decide on canonical way of printing ratios (as far as that is actually a very useful output form, compared with decimal, scientific or engineering notation).
This commit is contained in:
committed by
Mateusz Pusz
parent
eef6371ab4
commit
509b6c9653
@ -32,7 +32,7 @@ template<Exponent E>
|
|||||||
requires (E::den == 1 || E::den == 2) // TODO provide support for any den
|
requires (E::den == 1 || E::den == 2) // TODO provide support for any den
|
||||||
struct exp_ratio {
|
struct exp_ratio {
|
||||||
using base_ratio = E::dimension::base_unit::ratio;
|
using base_ratio = E::dimension::base_unit::ratio;
|
||||||
using positive_ratio = conditional<E::num * E::den < 0, ratio<base_ratio::den, base_ratio::num>, base_ratio>;
|
using positive_ratio = conditional<E::num * E::den < 0, ratio<base_ratio::den, base_ratio::num, -base_ratio::exp>, base_ratio>;
|
||||||
static constexpr std::int64_t N = E::num * E::den < 0 ? -E::num : E::num;
|
static constexpr std::int64_t N = E::num * E::den < 0 ? -E::num : E::num;
|
||||||
using pow = ratio_pow<positive_ratio, N>;
|
using pow = ratio_pow<positive_ratio, N>;
|
||||||
using type = conditional<E::den == 2, ratio_sqrt<pow>, pow>;
|
using type = conditional<E::den == 2, ratio_sqrt<pow>, pow>;
|
||||||
|
@ -29,13 +29,19 @@ namespace units::detail {
|
|||||||
template<typename Ratio>
|
template<typename Ratio>
|
||||||
constexpr auto ratio_text()
|
constexpr auto ratio_text()
|
||||||
{
|
{
|
||||||
if constexpr(Ratio::num != 1 || Ratio::den != 1) {
|
if constexpr(Ratio::num != 1 || Ratio::den != 1 || Ratio::exp != 0) {
|
||||||
auto txt = basic_fixed_string("[") + regular<Ratio::num>();
|
auto txt = basic_fixed_string("[") + regular<Ratio::num>();
|
||||||
if constexpr(Ratio::den == 1) {
|
if constexpr(Ratio::den == 1 && Ratio::exp == 0) {
|
||||||
return txt + basic_fixed_string("]");
|
return txt + basic_fixed_string("]");
|
||||||
}
|
}
|
||||||
|
else if constexpr (Ratio::den == 1) {
|
||||||
|
return txt + basic_fixed_string(" x 10") + superscript<Ratio::exp>() +
|
||||||
|
basic_fixed_string("]");
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
return txt + basic_fixed_string("/") + regular<Ratio::den>() + basic_fixed_string("]");
|
return txt + basic_fixed_string("/") + regular<Ratio::den>() +
|
||||||
|
basic_fixed_string(" x 10") + superscript<Ratio::exp>() +
|
||||||
|
basic_fixed_string("]");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -46,7 +52,7 @@ constexpr auto ratio_text()
|
|||||||
template<typename Ratio, typename PrefixType>
|
template<typename Ratio, typename PrefixType>
|
||||||
constexpr auto prefix_or_ratio_text()
|
constexpr auto prefix_or_ratio_text()
|
||||||
{
|
{
|
||||||
if constexpr(Ratio::num == 1 && Ratio::den == 1) {
|
if constexpr(Ratio::num == 1 && Ratio::den == 1 && Ratio::exp == 0) {
|
||||||
// no ratio/prefix
|
// no ratio/prefix
|
||||||
return basic_fixed_string("");
|
return basic_fixed_string("");
|
||||||
}
|
}
|
||||||
|
@ -31,21 +31,23 @@ struct prefix : prefix_type {};
|
|||||||
|
|
||||||
// TODO Remove dependency on std::ratio
|
// TODO Remove dependency on std::ratio
|
||||||
|
|
||||||
struct atto : units::prefix<atto, prefix, "a", ratio<1, std::atto::den>> {};
|
// clang-format off
|
||||||
struct femto : units::prefix<femto, prefix, "f", ratio<1, std::femto::den>> {};
|
struct atto : units::prefix<atto, prefix, "a", ratio<1, 1, -18>> {}; // std::atto::den>> {};
|
||||||
struct pico : units::prefix<pico, prefix, "p", ratio<1, std::pico::den>> {};
|
struct femto : units::prefix<femto, prefix, "f", ratio<1, 1, -15>> {}; // std::femto::den>> {};
|
||||||
struct nano : units::prefix<nano, prefix, "n", ratio<1, std::nano::den>> {};
|
struct pico : units::prefix<pico, prefix, "p", ratio<1, 1, -12>> {}; // std::pico::den>> {};
|
||||||
struct micro : units::prefix<micro, prefix, "\u00b5", ratio<1, std::micro::den>> {};
|
struct nano : units::prefix<nano, prefix, "n", ratio<1, 1, -9>> {}; // std::nano::den>> {};
|
||||||
struct milli : units::prefix<milli, prefix, "m", ratio<1, std::milli::den>> {};
|
struct micro : units::prefix<micro, prefix, "\u00b5", ratio<1, 1, -6>> {}; // std::micro::den>> {};
|
||||||
struct centi : units::prefix<centi, prefix, "c", ratio<1, std::centi::den>> {};
|
struct milli : units::prefix<milli, prefix, "m", ratio<1, 1, -3>> {}; // std::milli::den>> {};
|
||||||
struct deci : units::prefix<deci, prefix, "d", ratio<1, std::deci::den>> {};
|
struct centi : units::prefix<centi, prefix, "c", ratio<1, 1, -2>> {}; // std::centi::den>> {};
|
||||||
struct deca : units::prefix<deca, prefix, "da", ratio<std::deca::num>> {};
|
struct deci : units::prefix<deci, prefix, "d", ratio<1, 1, -1>> {}; // std::deci::den>> {};
|
||||||
struct hecto : units::prefix<hecto, prefix, "h", ratio<std::hecto::num>> {};
|
struct deca : units::prefix<deca, prefix, "da", ratio<1, 1, 1>> {}; // std::deca::num>> {};
|
||||||
struct kilo : units::prefix<kilo, prefix, "k", ratio<std::kilo::num>> {};
|
struct hecto : units::prefix<hecto, prefix, "h", ratio<1, 1, 2>> {}; // std::hecto::num>> {};
|
||||||
struct mega : units::prefix<mega, prefix, "M", ratio<std::mega::num>> {};
|
struct kilo : units::prefix<kilo, prefix, "k", ratio<1, 1, 3>> {}; // std::kilo::num>> {};
|
||||||
struct giga : units::prefix<giga, prefix, "G", ratio<std::giga::num>> {};
|
struct mega : units::prefix<mega, prefix, "M", ratio<1, 1, 6>> {}; // std::mega::num>> {};
|
||||||
struct tera : units::prefix<tera, prefix, "T", ratio<std::tera::num>> {};
|
struct giga : units::prefix<giga, prefix, "G", ratio<1, 1, 9>> {}; // std::giga::num>> {};
|
||||||
struct peta : units::prefix<peta, prefix, "P", ratio<std::peta::num>> {};
|
struct tera : units::prefix<tera, prefix, "T", ratio<1, 1, 12>> {}; // std::tera::num>> {};
|
||||||
struct exa : units::prefix<exa, prefix, "E", ratio<std::exa::num>> {};
|
struct peta : units::prefix<peta, prefix, "P", ratio<1, 1, 15>> {}; // std::peta::num>> {};
|
||||||
|
struct exa : units::prefix<exa, prefix, "E", ratio<1, 1, 18>> {}; // std::exa::num>> {};
|
||||||
|
// clang-format off
|
||||||
|
|
||||||
} // namespace units::si
|
} // namespace units::si
|
||||||
|
@ -70,7 +70,7 @@ struct prefix_base : downcast_base<prefix_base<PT, R>> {
|
|||||||
*/
|
*/
|
||||||
template<typename Child, PrefixType PT, basic_fixed_string Symbol, Ratio R>
|
template<typename Child, PrefixType PT, basic_fixed_string Symbol, Ratio R>
|
||||||
requires (!std::same_as<PT, no_prefix>)
|
requires (!std::same_as<PT, no_prefix>)
|
||||||
struct prefix : downcast_child<Child, detail::prefix_base<PT, ratio<R::num, R::den>>> {
|
struct prefix : downcast_child<Child, detail::prefix_base<PT, ratio<R::num, R::den, R::exp>>> {
|
||||||
static constexpr auto symbol = Symbol;
|
static constexpr auto symbol = Symbol;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
namespace units {
|
namespace units {
|
||||||
|
|
||||||
@ -352,7 +353,7 @@ template<typename D1, typename U1, typename Rep1, typename D2, typename U2, type
|
|||||||
{
|
{
|
||||||
using common_rep = decltype(lhs.count() * rhs.count());
|
using common_rep = decltype(lhs.count() * rhs.count());
|
||||||
using ratio = ratio_multiply<typename U1::ratio, typename U2::ratio>;
|
using ratio = ratio_multiply<typename U1::ratio, typename U2::ratio>;
|
||||||
return common_rep(lhs.count()) * common_rep(rhs.count()) * common_rep(ratio::num) / common_rep(ratio::den);
|
return common_rep(lhs.count()) * common_rep(rhs.count()) * common_rep(ratio::num) * std::pow(10, common_rep(ratio::exp)) / common_rep(ratio::den);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename D1, typename U1, typename Rep1, typename D2, typename U2, typename Rep2>
|
template<typename D1, typename U1, typename Rep1, typename D2, typename U2, typename Rep2>
|
||||||
@ -376,7 +377,7 @@ template<Scalar Value, typename D, typename U, typename Rep>
|
|||||||
Expects(q.count() != 0);
|
Expects(q.count() != 0);
|
||||||
|
|
||||||
using dim = dim_invert<D>;
|
using dim = dim_invert<D>;
|
||||||
using ratio = ratio<U::ratio::den, U::ratio::num>;
|
using ratio = ratio<U::ratio::den, U::ratio::num, -U::ratio::exp>;
|
||||||
using unit = downcast_unit<dim, ratio>;
|
using unit = downcast_unit<dim, ratio>;
|
||||||
using common_rep = decltype(v / q.count());
|
using common_rep = decltype(v / q.count());
|
||||||
using ret = quantity<dim, unit, common_rep>;
|
using ret = quantity<dim, unit, common_rep>;
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include <units/concepts.h>
|
#include <units/concepts.h>
|
||||||
#include <units/bits/dimension_op.h>
|
#include <units/bits/dimension_op.h>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
namespace units {
|
namespace units {
|
||||||
|
|
||||||
@ -41,10 +42,15 @@ struct quantity_cast_impl {
|
|||||||
{
|
{
|
||||||
if constexpr (treat_as_floating_point<CRep>) {
|
if constexpr (treat_as_floating_point<CRep>) {
|
||||||
return To(static_cast<To::rep>(static_cast<CRep>(q.count()) *
|
return To(static_cast<To::rep>(static_cast<CRep>(q.count()) *
|
||||||
(static_cast<CRep>(CRatio::num) / static_cast<CRep>(CRatio::den))));
|
static_cast<CRep>(std::pow(10, CRatio::exp)) *
|
||||||
|
(static_cast<CRep>(CRatio::num) /
|
||||||
|
static_cast<CRep>(CRatio::den))));
|
||||||
} else {
|
} else {
|
||||||
return To(static_cast<To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(CRatio::num) /
|
return To(static_cast<To::rep>(static_cast<CRep>(q.count()) *
|
||||||
static_cast<CRep>(CRatio::den)));
|
static_cast<CRep>(CRatio::num) *
|
||||||
|
static_cast<CRep>(CRatio::exp > 0 ? std::pow(10, CRatio::exp) : 1) /
|
||||||
|
(static_cast<CRep>(CRatio::den) *
|
||||||
|
static_cast<CRep>(CRatio::exp < 0 ? std::pow(10, -CRatio::exp) : 1))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -54,7 +60,7 @@ struct quantity_cast_impl<To, CRatio, CRep, true, true> {
|
|||||||
template<Quantity Q>
|
template<Quantity Q>
|
||||||
static constexpr To cast(const Q& q)
|
static constexpr To cast(const Q& q)
|
||||||
{
|
{
|
||||||
return To(static_cast<To::rep>(q.count()));
|
return To(static_cast<To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(std::pow(10, CRatio::exp))));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -64,9 +70,9 @@ struct quantity_cast_impl<To, CRatio, CRep, true, false> {
|
|||||||
static constexpr To cast(const Q& q)
|
static constexpr To cast(const Q& q)
|
||||||
{
|
{
|
||||||
if constexpr (treat_as_floating_point<CRep>) {
|
if constexpr (treat_as_floating_point<CRep>) {
|
||||||
return To(static_cast<To::rep>(static_cast<CRep>(q.count()) * (CRep{1} / static_cast<CRep>(CRatio::den))));
|
return To(static_cast<To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(std::pow(10, CRatio::exp)) * (CRep{1} / static_cast<CRep>(CRatio::den))));
|
||||||
} else {
|
} else {
|
||||||
return To(static_cast<To::rep>(static_cast<CRep>(q.count()) / static_cast<CRep>(CRatio::den)));
|
return To(static_cast<To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(std::pow(10, CRatio::exp)) / static_cast<CRep>(CRatio::den)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -76,7 +82,7 @@ struct quantity_cast_impl<To, CRatio, CRep, false, true> {
|
|||||||
template<Quantity Q>
|
template<Quantity Q>
|
||||||
static constexpr To cast(const Q& q)
|
static constexpr To cast(const Q& q)
|
||||||
{
|
{
|
||||||
return To(static_cast<To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(CRatio::num)));
|
return To(static_cast<To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(CRatio::num) * static_cast<CRep>(std::pow(10, CRatio::exp))));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -124,7 +130,7 @@ template<Quantity To, typename D, typename U, typename Rep>
|
|||||||
using c_rep = std::common_type_t<typename To::rep, Rep, intmax_t>;
|
using c_rep = std::common_type_t<typename To::rep, Rep, intmax_t>;
|
||||||
using ret_unit = downcast_unit<typename To::dimension, typename To::unit::ratio>;
|
using ret_unit = downcast_unit<typename To::dimension, typename To::unit::ratio>;
|
||||||
using ret = quantity<typename To::dimension, ret_unit, typename To::rep>;
|
using ret = quantity<typename To::dimension, ret_unit, typename To::rep>;
|
||||||
using cast = detail::quantity_cast_impl<ret, c_ratio, c_rep, c_ratio::num == 1, c_ratio::den == 1>;
|
using cast = detail::quantity_cast_impl<ret, c_ratio, c_rep, c_ratio::num == 1 && c_ratio::exp == 0, c_ratio::den == 1 && c_ratio::exp == 0>;
|
||||||
return cast::cast(q);
|
return cast::cast(q);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,6 +27,8 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
#include <tuple>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
namespace units {
|
namespace units {
|
||||||
|
|
||||||
@ -38,24 +40,45 @@ template<typename T>
|
|||||||
return v < 0 ? -v : v;
|
return v < 0 ? -v : v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr std::tuple<std::intmax_t, std::intmax_t, std::intmax_t> normalize(std::intmax_t num, std::intmax_t den, std::intmax_t exp) {
|
||||||
|
std::intmax_t gcd = std::gcd(num, den);
|
||||||
|
num = num * (den < 0 ? -1 : 1) / gcd;
|
||||||
|
den = detail::abs(den) / gcd;
|
||||||
|
|
||||||
|
while (num % 10 == 0) {
|
||||||
|
num /= 10;
|
||||||
|
++exp;
|
||||||
|
}
|
||||||
|
while (den % 10 == 0) {
|
||||||
|
den /= 10;
|
||||||
|
--exp;
|
||||||
|
}
|
||||||
|
return std::make_tuple(num, den, exp);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
template<std::intmax_t Num, std::intmax_t Den = 1>
|
template<std::intmax_t Num, std::intmax_t Den = 1, std::intmax_t Exp = 0>
|
||||||
requires(Den != 0)
|
requires(Den != 0)
|
||||||
struct ratio {
|
struct ratio {
|
||||||
static_assert(-INTMAX_MAX <= Num, "numerator too negative");
|
static_assert(-INTMAX_MAX <= Num, "numerator too negative");
|
||||||
static_assert(-INTMAX_MAX <= Den, "denominator too negative");
|
static_assert(-INTMAX_MAX <= Den, "denominator too negative");
|
||||||
|
|
||||||
static constexpr std::intmax_t num = Num * (Den < 0 ? -1 : 1) / std::gcd(Num, Den);
|
private:
|
||||||
static constexpr std::intmax_t den = detail::abs(Den) / std::gcd(Num, Den);
|
static constexpr auto norm = detail::normalize(Num, Den, Exp);
|
||||||
|
|
||||||
using type = ratio<num, den>;
|
public:
|
||||||
|
static constexpr std::intmax_t num = std::get<0>(norm);
|
||||||
|
static constexpr std::intmax_t den = std::get<1>(norm);
|
||||||
|
static constexpr std::intmax_t exp = std::get<2>(norm);
|
||||||
|
|
||||||
|
using type = ratio<num, den, exp>;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
template<intmax_t Num, intmax_t Den>
|
template<intmax_t Num, intmax_t Den, intmax_t Exp>
|
||||||
inline constexpr bool is_ratio<ratio<Num, Den>> = true;
|
inline constexpr bool is_ratio<ratio<Num, Den, Exp>> = true;
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
@ -97,10 +120,19 @@ private:
|
|||||||
static constexpr std::intmax_t gcd1 = std::gcd(R1::num, R2::den);
|
static constexpr std::intmax_t gcd1 = std::gcd(R1::num, R2::den);
|
||||||
static constexpr std::intmax_t gcd2 = std::gcd(R2::num, R1::den);
|
static constexpr std::intmax_t gcd2 = std::gcd(R2::num, R1::den);
|
||||||
|
|
||||||
|
static constexpr auto norm = detail::normalize(safe_multiply(R1::num / gcd1, R2::num / gcd2),
|
||||||
|
safe_multiply(R1::den / gcd2, R2::den / gcd1),
|
||||||
|
R1::exp + R2::exp);
|
||||||
|
|
||||||
|
static constexpr std::intmax_t norm_num = std::get<0>(norm);
|
||||||
|
static constexpr std::intmax_t norm_den = std::get<1>(norm);
|
||||||
|
static constexpr std::intmax_t norm_exp = std::get<2>(norm);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using type = ratio<safe_multiply(R1::num / gcd1, R2::num / gcd2), safe_multiply(R1::den / gcd2, R2::den / gcd1)>;
|
using type = ratio<norm_num, norm_den, norm_exp>;
|
||||||
static constexpr std::intmax_t num = type::num;
|
static constexpr std::intmax_t num = type::num;
|
||||||
static constexpr std::intmax_t den = type::den;
|
static constexpr std::intmax_t den = type::den;
|
||||||
|
static constexpr std::intmax_t exp = type::exp;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
@ -115,9 +147,10 @@ namespace detail {
|
|||||||
template<typename R1, typename R2>
|
template<typename R1, typename R2>
|
||||||
struct ratio_divide_impl {
|
struct ratio_divide_impl {
|
||||||
static_assert(R2::num != 0, "division by 0");
|
static_assert(R2::num != 0, "division by 0");
|
||||||
using type = ratio_multiply<R1, ratio<R2::den, R2::num>>;
|
using type = ratio_multiply<R1, ratio<R2::den, R2::num, -R2::exp>>;
|
||||||
static constexpr std::intmax_t num = type::num;
|
static constexpr std::intmax_t num = type::num;
|
||||||
static constexpr std::intmax_t den = type::den;
|
static constexpr std::intmax_t den = type::den;
|
||||||
|
static constexpr std::intmax_t exp = type::exp;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
@ -168,6 +201,7 @@ static constexpr std::intmax_t sqrt_impl(std::intmax_t v) { return sqrt_impl(v,
|
|||||||
|
|
||||||
template<typename R>
|
template<typename R>
|
||||||
struct ratio_sqrt_impl {
|
struct ratio_sqrt_impl {
|
||||||
|
// TODO this is broken..need /2 logic on EXP
|
||||||
using type = ratio<detail::sqrt_impl(R::num), detail::sqrt_impl(R::den)>;
|
using type = ratio<detail::sqrt_impl(R::num), detail::sqrt_impl(R::den)>;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -190,7 +224,7 @@ template<typename R1, typename R2>
|
|||||||
struct common_ratio_impl {
|
struct common_ratio_impl {
|
||||||
static constexpr std::intmax_t gcd_num = std::gcd(R1::num, R2::num);
|
static constexpr std::intmax_t gcd_num = std::gcd(R1::num, R2::num);
|
||||||
static constexpr std::intmax_t gcd_den = std::gcd(R1::den, R2::den);
|
static constexpr std::intmax_t gcd_den = std::gcd(R1::den, R2::den);
|
||||||
using type = ratio<gcd_num, (R1::den / gcd_den) * R2::den>;
|
using type = ratio<gcd_num, (R1::den / gcd_den) * R2::den, std::min(R1::exp, R2::exp)>;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
@ -110,7 +110,7 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]")
|
|||||||
{
|
{
|
||||||
SECTION("in terms of base units")
|
SECTION("in terms of base units")
|
||||||
{
|
{
|
||||||
const length<scaled_unit<ratio<1'000'000>, metre>> q(123);
|
const length<scaled_unit<ratio<1, 1, 6>, metre>> q(123);
|
||||||
stream << q;
|
stream << q;
|
||||||
|
|
||||||
SECTION("iostream")
|
SECTION("iostream")
|
||||||
@ -131,7 +131,7 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]")
|
|||||||
|
|
||||||
SECTION("in terms of derived units")
|
SECTION("in terms of derived units")
|
||||||
{
|
{
|
||||||
const energy<scaled_unit<ratio<1, 100>, joule>> q(60);
|
const energy<scaled_unit<ratio<1, 1, -2>, joule>> q(60);
|
||||||
stream << q;
|
stream << q;
|
||||||
|
|
||||||
SECTION("iostream")
|
SECTION("iostream")
|
||||||
@ -296,7 +296,7 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]")
|
|||||||
|
|
||||||
SECTION("iostream")
|
SECTION("iostream")
|
||||||
{
|
{
|
||||||
CHECK(stream.str() == "8 [1/100]m³");
|
CHECK(stream.str() == "8 [1 x 10⁻²]m³");
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("fmt with default format {} on a quantity")
|
SECTION("fmt with default format {} on a quantity")
|
||||||
@ -317,7 +317,7 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]")
|
|||||||
|
|
||||||
SECTION("iostream")
|
SECTION("iostream")
|
||||||
{
|
{
|
||||||
CHECK(stream.str() == "2 [60]Hz");
|
CHECK(stream.str() == "2 [6 x 10¹]Hz");
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("fmt with default format {} on a quantity")
|
SECTION("fmt with default format {} on a quantity")
|
||||||
@ -338,7 +338,7 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]")
|
|||||||
|
|
||||||
SECTION("iostream")
|
SECTION("iostream")
|
||||||
{
|
{
|
||||||
CHECK(stream.str() == "10 [1/60]W");
|
CHECK(stream.str() == "10 [1/6 x 10⁻¹]W");
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("fmt with default format {} on a quantity")
|
SECTION("fmt with default format {} on a quantity")
|
||||||
@ -359,7 +359,7 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]")
|
|||||||
|
|
||||||
SECTION("iostream")
|
SECTION("iostream")
|
||||||
{
|
{
|
||||||
CHECK(stream.str() == "30 [50/3]W");
|
CHECK(stream.str() == "30 [1/6 x 10²]W");
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("fmt with default format {} on a quantity")
|
SECTION("fmt with default format {} on a quantity")
|
||||||
@ -404,7 +404,7 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]")
|
|||||||
|
|
||||||
SECTION("iostream")
|
SECTION("iostream")
|
||||||
{
|
{
|
||||||
CHECK(stream.str() == "8 [1000]m⋅s");
|
CHECK(stream.str() == "8 [1 x 10³]m⋅s");
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("fmt with default format {} on a quantity")
|
SECTION("fmt with default format {} on a quantity")
|
||||||
@ -425,7 +425,7 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]")
|
|||||||
|
|
||||||
SECTION("iostream")
|
SECTION("iostream")
|
||||||
{
|
{
|
||||||
CHECK(stream.str() == "2 [60]kg/s");
|
CHECK(stream.str() == "2 [6 x 10¹]kg/s");
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("fmt with default format {} on a quantity")
|
SECTION("fmt with default format {} on a quantity")
|
||||||
@ -446,7 +446,7 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]")
|
|||||||
|
|
||||||
SECTION("iostream")
|
SECTION("iostream")
|
||||||
{
|
{
|
||||||
CHECK(stream.str() == "10 [1/60]kg/s");
|
CHECK(stream.str() == "10 [1/6 x 10⁻¹]kg/s");
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("fmt with default format {} on a quantity")
|
SECTION("fmt with default format {} on a quantity")
|
||||||
@ -467,7 +467,7 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]")
|
|||||||
|
|
||||||
SECTION("iostream")
|
SECTION("iostream")
|
||||||
{
|
{
|
||||||
CHECK(stream.str() == "30 [3/50]1/m⋅s");
|
CHECK(stream.str() == "30 [6 x 10⁻²]1/m⋅s");
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("fmt with default format {} on a quantity")
|
SECTION("fmt with default format {} on a quantity")
|
||||||
|
@ -160,6 +160,7 @@ static_assert(length<metre, int>(1km).count() == 1000);
|
|||||||
// static_assert(length<metre, int>(1s).count() == 1); // should not compile (different dimensions)
|
// static_assert(length<metre, int>(1s).count() == 1); // should not compile (different dimensions)
|
||||||
//static_assert(length<kilometre, int>(1010m).count() == 1); // should not compile (truncating conversion)
|
//static_assert(length<kilometre, int>(1010m).count() == 1); // should not compile (truncating conversion)
|
||||||
static_assert(length<kilometre, int>(quantity_cast<length<kilometre, my_int>>(1010m)).count() == 1);
|
static_assert(length<kilometre, int>(quantity_cast<length<kilometre, my_int>>(1010m)).count() == 1);
|
||||||
|
static_assert(length<metre, int>(quantity_cast<length<kilometre, my_int>>(1010m)).count() == 1000);
|
||||||
|
|
||||||
// assignment operator
|
// assignment operator
|
||||||
|
|
||||||
@ -236,23 +237,23 @@ static_assert(std::is_same_v<decltype(1.0 * length<metre, int>()), length<metre,
|
|||||||
static_assert(
|
static_assert(
|
||||||
std::is_same_v<decltype(velocity<metre_per_second, int>() * si::time<second, int>()), length<metre, int>>);
|
std::is_same_v<decltype(velocity<metre_per_second, int>() * si::time<second, int>()), length<metre, int>>);
|
||||||
static_assert(
|
static_assert(
|
||||||
std::is_same_v<decltype(velocity<metre_per_second, int>() * si::time<hour, int>()), length<scaled_unit<ratio<3600>, metre>, int>>);
|
std::is_same_v<decltype(velocity<metre_per_second, int>() * si::time<hour, int>()), length<scaled_unit<ratio<36, 1, 2>, metre>, int>>);
|
||||||
static_assert(std::is_same_v<decltype(length<metre>() * si::time<minute>()),
|
static_assert(std::is_same_v<decltype(length<metre>() * si::time<minute>()),
|
||||||
quantity<unknown_dimension<units::exp<dim_length, 1>, units::exp<dim_time, 1>>, scaled_unit<ratio<60>, unknown_unit>>>);
|
quantity<unknown_dimension<units::exp<dim_length, 1>, units::exp<dim_time, 1>>, scaled_unit<ratio<6, 1, 1>, unknown_unit>>>);
|
||||||
static_assert(std::is_same_v<decltype(1 / si::time<second, int>()), frequency<hertz, int>>);
|
static_assert(std::is_same_v<decltype(1 / si::time<second, int>()), frequency<hertz, int>>);
|
||||||
static_assert(std::is_same_v<decltype(1 / si::time<minute, int>()), frequency<scaled_unit<ratio<1, 60>, hertz>, int>>);
|
static_assert(std::is_same_v<decltype(1 / si::time<minute, int>()), frequency<scaled_unit<ratio<1, 6, -1>, hertz>, int>>);
|
||||||
static_assert(std::is_same_v<decltype(1 / frequency<hertz, int>()), si::time<second, int>>);
|
static_assert(std::is_same_v<decltype(1 / frequency<hertz, int>()), si::time<second, int>>);
|
||||||
static_assert(std::is_same_v<decltype(1 / length<kilometre>()),
|
static_assert(std::is_same_v<decltype(1 / length<kilometre>()),
|
||||||
quantity<unknown_dimension<units::exp<dim_length, -1>>, scaled_unit<ratio<1, 1000>, unknown_unit>>>);
|
quantity<unknown_dimension<units::exp<dim_length, -1>>, scaled_unit<ratio<1, 1, -3>, unknown_unit>>>);
|
||||||
static_assert(std::is_same_v<decltype(length<metre, int>() / 1.0), length<metre, double>>);
|
static_assert(std::is_same_v<decltype(length<metre, int>() / 1.0), length<metre, double>>);
|
||||||
static_assert(std::is_same_v<decltype(length<metre, int>() / length<metre, double>()), double>);
|
static_assert(std::is_same_v<decltype(length<metre, int>() / length<metre, double>()), double>);
|
||||||
static_assert(std::is_same_v<decltype(length<kilometre, int>() / length<metre, double>()), double>);
|
static_assert(std::is_same_v<decltype(length<kilometre, int>() / length<metre, double>()), double>);
|
||||||
static_assert(
|
static_assert(
|
||||||
std::is_same_v<decltype(length<metre, int>() / si::time<second, int>()), velocity<metre_per_second, int>>);
|
std::is_same_v<decltype(length<metre, int>() / si::time<second, int>()), velocity<metre_per_second, int>>);
|
||||||
static_assert(
|
static_assert(
|
||||||
std::is_same_v<decltype(length<metre>() / si::time<minute>()), velocity<scaled_unit<ratio<1, 60>, metre_per_second>>>);
|
std::is_same_v<decltype(length<metre>() / si::time<minute>()), velocity<scaled_unit<ratio<1, 6, -1>, metre_per_second>>>);
|
||||||
static_assert(std::is_same_v<decltype(si::time<minute>() / length<metre>()),
|
static_assert(std::is_same_v<decltype(si::time<minute>() / length<metre>()),
|
||||||
quantity<unknown_dimension<units::exp<dim_length, -1>, units::exp<dim_time, 1>>, scaled_unit<ratio<60>, unknown_unit>>>);
|
quantity<unknown_dimension<units::exp<dim_length, -1>, units::exp<dim_time, 1>>, scaled_unit<ratio<6 ,1 , 1>, unknown_unit>>>);
|
||||||
static_assert(std::is_same_v<decltype(length<metre, int>() % short(1)), length<metre, int>>);
|
static_assert(std::is_same_v<decltype(length<metre, int>() % short(1)), length<metre, int>>);
|
||||||
static_assert(std::is_same_v<decltype(length<metre, int>() % length<metre, short>(1)), length<metre, int>>);
|
static_assert(std::is_same_v<decltype(length<metre, int>() % length<metre, short>(1)), length<metre, int>>);
|
||||||
|
|
||||||
|
@ -27,10 +27,16 @@
|
|||||||
using namespace units;
|
using namespace units;
|
||||||
|
|
||||||
template<Ratio R1, Ratio R2>
|
template<Ratio R1, Ratio R2>
|
||||||
inline constexpr bool same = R1::num == R2::num && R1::den == R2::den;
|
inline constexpr bool same = R1::num == R2::num && R1::den == R2::den && R1::exp == R2::exp;
|
||||||
|
|
||||||
static_assert(same<ratio<2, 4>, ratio<1, 2>>);
|
static_assert(same<ratio<2, 4>, ratio<1, 2>>);
|
||||||
|
|
||||||
|
// basic exponents tests
|
||||||
|
// note use of ::type is required because template params are changed while stamping out template
|
||||||
|
static_assert(std::is_same_v<ratio<2, 40, 1>::type, ratio<1, 20, 1>::type>);
|
||||||
|
static_assert(std::is_same_v<ratio<20, 4, -1>::type, ratio<10, 2, -1>::type>);
|
||||||
|
static_assert(std::is_same_v<ratio<200, 5>::type, ratio<20'000, 50, -1>::type>);
|
||||||
|
|
||||||
static_assert(std::is_same_v<ratio_multiply<ratio<1>, ratio<3, 8>>, ratio<3, 8>>);
|
static_assert(std::is_same_v<ratio_multiply<ratio<1>, ratio<3, 8>>, ratio<3, 8>>);
|
||||||
static_assert(std::is_same_v<ratio_multiply<ratio<3, 8>, ratio<1>>, ratio<3, 8>>);
|
static_assert(std::is_same_v<ratio_multiply<ratio<3, 8>, ratio<1>>, ratio<3, 8>>);
|
||||||
static_assert(std::is_same_v<ratio_multiply<ratio<4>, ratio<1, 8>>, ratio<1, 2>>);
|
static_assert(std::is_same_v<ratio_multiply<ratio<4>, ratio<1, 8>>, ratio<1, 2>>);
|
||||||
@ -38,11 +44,19 @@
|
|||||||
static_assert(std::is_same_v<ratio_multiply<ratio<1, 8>, ratio<2>>, ratio<1, 4>>);
|
static_assert(std::is_same_v<ratio_multiply<ratio<1, 8>, ratio<2>>, ratio<1, 4>>);
|
||||||
static_assert(std::is_same_v<ratio_multiply<ratio<1, 2>, ratio<8>>, ratio<4>>);
|
static_assert(std::is_same_v<ratio_multiply<ratio<1, 2>, ratio<8>>, ratio<4>>);
|
||||||
|
|
||||||
|
// multiply with exponents
|
||||||
|
static_assert(std::is_same_v<ratio_multiply<ratio<1, 8, 2>, ratio<2, 1, 4>>, ratio<1, 4, 6>>);
|
||||||
|
static_assert(std::is_same_v<ratio_multiply<ratio<1, 2, -4>, ratio<8, 1, 3>>, ratio<4, 1, -1>>);
|
||||||
|
|
||||||
static_assert(std::is_same_v<ratio_divide<ratio<4>, ratio<2>>, ratio<2>>);
|
static_assert(std::is_same_v<ratio_divide<ratio<4>, ratio<2>>, ratio<2>>);
|
||||||
static_assert(std::is_same_v<ratio_divide<ratio<2>, ratio<8>>, ratio<1, 4>>);
|
static_assert(std::is_same_v<ratio_divide<ratio<2>, ratio<8>>, ratio<1, 4>>);
|
||||||
static_assert(std::is_same_v<ratio_divide<ratio<1, 8>, ratio<2>>, ratio<1, 16>>);
|
static_assert(std::is_same_v<ratio_divide<ratio<1, 8>, ratio<2>>, ratio<1, 16>>);
|
||||||
static_assert(std::is_same_v<ratio_divide<ratio<6>, ratio<3>>, ratio<2>>);
|
static_assert(std::is_same_v<ratio_divide<ratio<6>, ratio<3>>, ratio<2>>);
|
||||||
|
|
||||||
|
// divide with exponents
|
||||||
|
static_assert(std::is_same_v<ratio_divide<ratio<1, 8, -6>, ratio<2, 1, -8>>, ratio<1, 16, 2>>);
|
||||||
|
static_assert(std::is_same_v<ratio_divide<ratio<6, 1, 4>, ratio<3>>, ratio<2, 1, 4>>);
|
||||||
|
|
||||||
static_assert(std::is_same_v<ratio_pow<ratio<2>, 0>, ratio<1>>);
|
static_assert(std::is_same_v<ratio_pow<ratio<2>, 0>, ratio<1>>);
|
||||||
static_assert(std::is_same_v<ratio_pow<ratio<2>, 1>, ratio<2>>);
|
static_assert(std::is_same_v<ratio_pow<ratio<2>, 1>, ratio<2>>);
|
||||||
static_assert(std::is_same_v<ratio_pow<ratio<2>, 2>, ratio<4>>);
|
static_assert(std::is_same_v<ratio_pow<ratio<2>, 2>, ratio<4>>);
|
||||||
@ -52,17 +66,33 @@
|
|||||||
static_assert(std::is_same_v<ratio_pow<ratio<1, 2>, 2>, ratio<1, 4>>);
|
static_assert(std::is_same_v<ratio_pow<ratio<1, 2>, 2>, ratio<1, 4>>);
|
||||||
static_assert(std::is_same_v<ratio_pow<ratio<1, 2>, 3>, ratio<1, 8>>);
|
static_assert(std::is_same_v<ratio_pow<ratio<1, 2>, 3>, ratio<1, 8>>);
|
||||||
|
|
||||||
|
// pow with exponents
|
||||||
|
static_assert(std::is_same_v<ratio_pow<ratio<1, 2, 3>, 2>, ratio<1, 4, 6>>);
|
||||||
|
static_assert(std::is_same_v<ratio_pow<ratio<1, 2, -6>, 3>, ratio<1, 8, -18>>);
|
||||||
|
|
||||||
static_assert(std::is_same_v<ratio_sqrt<ratio<9>>, ratio<3>>);
|
static_assert(std::is_same_v<ratio_sqrt<ratio<9>>, ratio<3>>);
|
||||||
static_assert(std::is_same_v<ratio_sqrt<ratio<4>>, ratio<2>>);
|
static_assert(std::is_same_v<ratio_sqrt<ratio<4>>, ratio<2>>);
|
||||||
static_assert(std::is_same_v<ratio_sqrt<ratio<1>>, ratio<1>>);
|
static_assert(std::is_same_v<ratio_sqrt<ratio<1>>, ratio<1>>);
|
||||||
static_assert(std::is_same_v<ratio_sqrt<ratio<0>>, ratio<0>>);
|
static_assert(std::is_same_v<ratio_sqrt<ratio<0>>, ratio<0>>);
|
||||||
static_assert(std::is_same_v<ratio_sqrt<ratio<1, 4>>, ratio<1, 2>>);
|
static_assert(std::is_same_v<ratio_sqrt<ratio<1, 4>>, ratio<1, 2>>);
|
||||||
|
|
||||||
// common_ratio
|
// // sqrt with exponents: TODO not working yet. Also not sure the non exponent version is accurate.
|
||||||
|
// static_assert(std::is_same_v<ratio_sqrt<ratio<9, 1, 2>>, ratio<3, 1, 1>>);
|
||||||
|
// static_assert(std::is_same_v<ratio_sqrt<ratio<4>>, ratio<2>>);
|
||||||
|
|
||||||
|
// common_ratio
|
||||||
|
// note use of ::type is required because template params are changed while stamping out template
|
||||||
|
static_assert(std::is_same_v<common_ratio<ratio<1>::type, ratio<1000>>, ratio<1>::type>);
|
||||||
|
static_assert(std::is_same_v<common_ratio<ratio<1000>, ratio<1>>::type, ratio<1>::type>);
|
||||||
|
static_assert(std::is_same_v<common_ratio<ratio<1>, ratio<1, 1000>>::type, ratio<1, 1000>::type>);
|
||||||
|
static_assert(std::is_same_v<common_ratio<ratio<1, 1000>, ratio<1>>::type, ratio<1, 1000>::type>);
|
||||||
|
static_assert(std::is_same_v<common_ratio<ratio<100, 1>, ratio<10, 1>>::type, ratio<10, 1>::type>);
|
||||||
|
static_assert(std::is_same_v<common_ratio<ratio<100, 1>, ratio<1, 10>>::type, ratio<1, 10>::type>);
|
||||||
|
|
||||||
|
// common ratio with exponents
|
||||||
|
static_assert(std::is_same_v<common_ratio<ratio<1>, ratio<1, 1, 3>>::type, ratio<1>::type>);
|
||||||
|
static_assert(std::is_same_v<common_ratio<ratio<10, 1, -1>, ratio<1, 1, -3>>::type, ratio<1, 1, -3>::type>);
|
||||||
|
|
||||||
|
|
||||||
static_assert(std::is_same_v<common_ratio<ratio<1>, ratio<1000>>, ratio<1>>);
|
|
||||||
static_assert(std::is_same_v<common_ratio<ratio<1000>, ratio<1>>, ratio<1>>);
|
|
||||||
static_assert(std::is_same_v<common_ratio<ratio<1>, ratio<1, 1000>>, ratio<1, 1000>>);
|
|
||||||
static_assert(std::is_same_v<common_ratio<ratio<1, 1000>, ratio<1>>, ratio<1, 1000>>);
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
@ -192,7 +192,7 @@ static_assert(10V * 1F == 10C);
|
|||||||
|
|
||||||
// velocity
|
// velocity
|
||||||
|
|
||||||
static_assert(std::is_same_v<decltype(1km / 1s), velocity<scaled_unit<ratio<1000>, metre_per_second>, std::int64_t>>);
|
static_assert(std::is_same_v<decltype(1km / 1s), velocity<scaled_unit<ratio<1, 1, 3>, metre_per_second>, std::int64_t>>);
|
||||||
|
|
||||||
static_assert(10m / 5s == 2mps);
|
static_assert(10m / 5s == 2mps);
|
||||||
static_assert(10 / 5s * 1m == 2mps);
|
static_assert(10 / 5s * 1m == 2mps);
|
||||||
|
@ -30,12 +30,12 @@ using namespace units;
|
|||||||
struct metre : named_unit<metre, "m", si::prefix> {};
|
struct metre : named_unit<metre, "m", si::prefix> {};
|
||||||
struct centimetre : prefixed_unit<centimetre, si::centi, metre> {};
|
struct centimetre : prefixed_unit<centimetre, si::centi, metre> {};
|
||||||
struct kilometre : prefixed_unit<kilometre, si::kilo, metre> {};
|
struct kilometre : prefixed_unit<kilometre, si::kilo, metre> {};
|
||||||
struct yard : named_scaled_unit<yard, "yd", no_prefix, ratio<9'144, 10'000>, metre> {};
|
struct yard : named_scaled_unit<yard, "yd", no_prefix, ratio<9'144, 1, -4>, metre> {};
|
||||||
struct foot : named_scaled_unit<foot, "ft", no_prefix, ratio<1, 3>, yard> {};
|
struct foot : named_scaled_unit<foot, "ft", no_prefix, ratio<1, 3>, yard> {};
|
||||||
struct dim_length : base_dimension<"length", metre> {};
|
struct dim_length : base_dimension<"length", metre> {};
|
||||||
|
|
||||||
struct second : named_unit<second, "s", si::prefix> {};
|
struct second : named_unit<second, "s", si::prefix> {};
|
||||||
struct hour : named_scaled_unit<hour, "h", no_prefix, ratio<3600>, second> {};
|
struct hour : named_scaled_unit<hour, "h", no_prefix, ratio<36, 1, 2>, second> {};
|
||||||
struct dim_time : base_dimension<"time", second> {};
|
struct dim_time : base_dimension<"time", second> {};
|
||||||
|
|
||||||
struct kelvin : named_unit<kelvin, "K", no_prefix> {};
|
struct kelvin : named_unit<kelvin, "K", no_prefix> {};
|
||||||
@ -46,8 +46,8 @@ struct dim_velocity : derived_dimension<dim_velocity, metre_per_second, exp<dim_
|
|||||||
struct kilometre_per_hour : deduced_unit<kilometre_per_hour, dim_velocity, kilometre, hour> {};
|
struct kilometre_per_hour : deduced_unit<kilometre_per_hour, dim_velocity, kilometre, hour> {};
|
||||||
|
|
||||||
static_assert(std::is_same_v<downcast<scaled_unit<ratio<1>, metre>>, metre>);
|
static_assert(std::is_same_v<downcast<scaled_unit<ratio<1>, metre>>, metre>);
|
||||||
static_assert(std::is_same_v<downcast<scaled_unit<ratio<1, 100>, metre>>, centimetre>);
|
static_assert(std::is_same_v<downcast<scaled_unit<ratio<1, 1, -2>, metre>>, centimetre>);
|
||||||
static_assert(std::is_same_v<downcast<scaled_unit<ratio<yard::ratio::num, yard::ratio::den>, metre>>, yard>);
|
static_assert(std::is_same_v<downcast<scaled_unit<ratio<yard::ratio::num, yard::ratio::den, yard::ratio::exp>, metre>>, yard>);
|
||||||
static_assert(std::is_same_v<downcast<scaled_unit<ratio_multiply<typename yard::ratio, ratio<1, 3>>, metre>>, foot>);
|
static_assert(std::is_same_v<downcast<scaled_unit<ratio_multiply<typename yard::ratio, ratio<1, 3>>, metre>>, foot>);
|
||||||
static_assert(std::is_same_v<downcast<scaled_unit<ratio_divide<typename kilometre::ratio, typename hour::ratio>, metre_per_second>>, kilometre_per_hour>);
|
static_assert(std::is_same_v<downcast<scaled_unit<ratio_divide<typename kilometre::ratio, typename hour::ratio>, metre_per_second>>, kilometre_per_hour>);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user