refactor: quantity::value() refactored to quantity::value_ref_in(U)

This commit is contained in:
Mateusz Pusz
2023-08-27 20:19:26 +02:00
parent c30285ff96
commit a7711cb301
17 changed files with 445 additions and 346 deletions

View File

@ -33,7 +33,7 @@ template<mp_units::Quantity Target, mp_units::Quantity Source>
requires std::constructible_from<Target, Source>
inline constexpr double conversion_factor(Target, Source)
{
return mp_units::value_cast<Target::unit>(1. * Source::reference).numerical_value();
return mp_units::value_cast<Target::unit>(1. * Source::reference).numerical_value_ref_in(Target::unit);
}
} // namespace
@ -56,6 +56,8 @@ int main()
std::cout << MP_UNITS_STD_FMT::format("conversion factor from lengthA::unit of {:%q} to lengthB::unit of {:%q}:\n\n",
lengthA, lengthB)
<< MP_UNITS_STD_FMT::format("lengthB.value( {} ) == lengthA.value( {} ) * conversion_factor( {} )\n",
lengthB.numerical_value(), lengthA.numerical_value(),
lengthB.numerical_value_ref_in(lengthB.unit),
lengthA.numerical_value_ref_in(lengthA.unit),
conversion_factor(lengthB, lengthA));
}

View File

@ -81,9 +81,11 @@ quantity<To, Rep> exchange_to(quantity<From, Rep> q)
template<ReferenceOf<currency> auto To, ReferenceOf<currency> auto From, auto PO, typename Rep>
quantity_point<To, PO, Rep> exchange_to(quantity_point<From, PO, Rep> q)
{
return quantity_point{
zero +
static_cast<Rep>(exchange_rate<q.unit, get_unit(To)>() * (q - q.absolute_point_origin).numerical_value()) * To};
return quantity_point{zero +
static_cast<Rep>(exchange_rate<q.unit, get_unit(To)>() *
(q - q.absolute_point_origin).numerical_value_ref_in(q.unit)) *
To};
}
int main()

View File

@ -226,7 +226,7 @@ struct quantity_formatter {
explicit quantity_formatter(OutputIt o, quantity<Reference, Rep> q, const quantity_format_specs<CharT>& fspecs,
Locale lc) :
out(o), val(std::move(q).numerical_value()), specs(fspecs), loc(std::move(lc))
out(o), val(std::move(q).numerical_value_ref_in(q.unit)), specs(fspecs), loc(std::move(lc))
{
}
@ -396,7 +396,8 @@ private:
if (begin == end || *begin == '}') {
// default format should print value followed by the unit separated with 1 space
out = mp_units::detail::format_units_quantity_value<CharT>(out, q.numerical_value(), specs.rep, ctx.locale());
out = mp_units::detail::format_units_quantity_value<CharT>(out, q.numerical_value_ref_in(q.unit), specs.rep,
ctx.locale());
if constexpr (mp_units::detail::has_unit_symbol(get_unit(Reference))) {
if constexpr (mp_units::space_before_unit_symbol<get_unit(Reference)>) *out++ = CharT(' ');
out = unit_symbol_to<CharT>(out, get_unit(Reference));

View File

@ -36,9 +36,9 @@ void to_stream(std::basic_ostream<CharT, Traits>& os, const quantity<R, Rep>& q)
{
if constexpr (is_same_v<Rep, std::uint8_t> || is_same_v<Rep, std::int8_t>)
// promote the value to int
os << +q.numerical_value();
os << +q.numerical_value_ref_in(q.unit);
else
os << q.numerical_value();
os << q.numerical_value_ref_in(q.unit);
if constexpr (has_unit_symbol(get_unit(R))) {
if constexpr (space_before_unit_symbol<get_unit(R)>) os << " ";
unit_symbol_to<CharT>(std::ostream_iterator<CharT>(os), get_unit(R));
@ -49,7 +49,7 @@ void to_stream(std::basic_ostream<CharT, Traits>& os, const quantity<R, Rep>& q)
template<typename CharT, typename Traits, auto R, typename Rep>
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const quantity<R, Rep>& q)
requires requires { os << q.numerical_value(); }
requires requires { os << q.numerical_value_ref_in(q.unit); }
{
if (os.width()) {
// std::setw() applies to the whole quantity output so it has to be first put into std::string

View File

@ -51,9 +51,9 @@ template<QuantitySpec auto ToQS, typename Q>
{
if constexpr (detail::QuantityKindSpec<std::remove_const_t<decltype(ToQS)>> &&
AssociatedUnit<std::remove_const_t<decltype(Q::unit)>>)
return make_quantity<Q::unit>(std::forward<Q>(q).numerical_value());
return make_quantity<Q::unit>(std::forward<Q>(q).numerical_value_ref_in(q.unit));
else
return make_quantity<reference<ToQS, Q::unit>{}>(std::forward<Q>(q).numerical_value());
return make_quantity<reference<ToQS, Q::unit>{}>(std::forward<Q>(q).numerical_value_ref_in(q.unit));
}
} // namespace mp_units

View File

@ -63,10 +63,10 @@ template<Quantity To, typename From>
if constexpr (q_unit == To::unit) {
// no scaling of the number needed
return make_quantity<To::reference>(static_cast<MP_UNITS_TYPENAME To::rep>(
std::forward<From>(q).numerical_value())); // this is the only (and recommended) way to do
// a truncating conversion on a number, so we are
// using static_cast to suppress all the compiler
// warnings on conversions
std::forward<From>(q).numerical_value_ref_in(q_unit))); // this is the only (and recommended) way to do
// a truncating conversion on a number, so we are
// using static_cast to suppress all the compiler
// warnings on conversions
} else {
// scale the number
constexpr Magnitude auto c_mag = get_canonical_unit(q_unit).mag / get_canonical_unit(To::unit).mag;
@ -78,8 +78,9 @@ template<Quantity To, typename From>
using multiplier_type =
conditional<treat_as_floating_point<c_rep_type>, std::common_type_t<c_mag_type, long double>, c_mag_type>;
constexpr auto val = [](Magnitude auto m) { return get_value<multiplier_type>(m); };
return static_cast<MP_UNITS_TYPENAME To::rep>(static_cast<c_rep_type>(std::forward<From>(q).numerical_value()) *
val(num) / val(den) * val(irr)) *
return static_cast<MP_UNITS_TYPENAME To::rep>(
static_cast<c_rep_type>(std::forward<From>(q).numerical_value_ref_in(q_unit)) * val(num) / val(den) *
val(irr)) *
To::reference;
}
}

View File

@ -126,7 +126,7 @@ public:
template<detail::QuantityConvertibleTo<quantity> Q>
constexpr explicit(!std::convertible_to<typename Q::rep, Rep>) quantity(const Q& q) :
value_(detail::sudo_cast<quantity>(q).numerical_value())
value_(detail::sudo_cast<quantity>(q).numerical_value_ref_in(unit))
{
}
@ -143,23 +143,44 @@ public:
// data access
#ifdef __cpp_explicit_this_parameter
template<typename Self>
[[nodiscard]] constexpr auto&& value(this Self&& self) noexcept
template<typename Self, Unit U>
requires(U{} == unit)
[[nodiscard]] constexpr auto&& value_ref_in(this Self&& self, U) noexcept
{
return std::forward<Self>(self).value_;
}
#else
[[nodiscard]] constexpr rep& numerical_value() & noexcept { return value_; }
[[nodiscard]] constexpr const rep& numerical_value() const& noexcept { return value_; }
[[nodiscard]] constexpr rep&& numerical_value() && noexcept { return std::move(value_); }
[[nodiscard]] constexpr const rep&& numerical_value() const&& noexcept { return std::move(value_); }
template<Unit U>
requires(U{} == unit)
[[nodiscard]] constexpr rep& numerical_value_ref_in(U) & noexcept
{
return value_;
}
template<Unit U>
requires(U{} == unit)
[[nodiscard]] constexpr const rep& numerical_value_ref_in(U) const& noexcept
{
return value_;
}
template<Unit U>
requires(U{} == unit)
[[nodiscard]] constexpr rep&& numerical_value_ref_in(U) && noexcept
{
return std::move(value_);
}
template<Unit U>
requires(U{} == unit)
[[nodiscard]] constexpr const rep&& numerical_value_ref_in(U) const&& noexcept
{
return std::move(value_);
}
#endif
template<Unit U>
requires requires(quantity q) { q.in(U{}); }
[[nodiscard]] constexpr rep numerical_value_in(U) const noexcept
{
return (*this).in(U{}).numerical_value();
return (*this).in(U{}).numerical_value_ref_in(U{});
}
template<Unit U>
@ -177,7 +198,7 @@ public:
} -> std::common_with<rep>;
}
{
return make_quantity<reference>(+numerical_value());
return make_quantity<reference>(+numerical_value_ref_in(unit));
}
[[nodiscard]] constexpr Quantity auto operator-() const
@ -187,7 +208,7 @@ public:
} -> std::common_with<rep>;
}
{
return make_quantity<reference>(-numerical_value());
return make_quantity<reference>(-numerical_value_ref_in(unit));
}
constexpr quantity& operator++()
@ -240,7 +261,7 @@ public:
} -> std::same_as<rep&>;
}
{
value_ += q.numerical_value();
value_ += q.numerical_value_ref_in(unit);
return *this;
}
@ -251,7 +272,7 @@ public:
} -> std::same_as<rep&>;
}
{
value_ -= q.numerical_value();
value_ -= q.numerical_value_ref_in(unit);
return *this;
}
@ -263,7 +284,7 @@ public:
}
{
gsl_ExpectsAudit(q != zero());
value_ %= q.numerical_value();
value_ %= q.numerical_value_ref_in(unit);
return *this;
}
@ -287,7 +308,7 @@ public:
}
constexpr quantity& operator*=(const Q& rhs)
{
value_ *= rhs.numerical_value();
value_ *= rhs.numerical_value_ref_in(::mp_units::one);
return *this;
}
@ -313,7 +334,7 @@ public:
constexpr quantity& operator/=(const Q& rhs)
{
gsl_ExpectsAudit(rhs != rhs.zero());
value_ /= rhs.numerical_value();
value_ /= rhs.numerical_value_ref_in(::mp_units::one);
return *this;
}
@ -342,7 +363,8 @@ template<auto R1, typename Rep1, auto R2, typename Rep2>
[[nodiscard]] constexpr Quantity auto operator+(const quantity<R1, Rep1>& lhs, const quantity<R2, Rep2>& rhs)
{
using ret = detail::common_quantity_for<std::plus<>, quantity<R1, Rep1>, quantity<R2, Rep2>>;
return make_quantity<ret::reference>(ret(lhs).numerical_value() + ret(rhs).numerical_value());
return make_quantity<ret::reference>(ret(lhs).numerical_value_ref_in(ret::unit) +
ret(rhs).numerical_value_ref_in(ret::unit));
}
template<auto R1, typename Rep1, auto R2, typename Rep2>
@ -350,7 +372,8 @@ template<auto R1, typename Rep1, auto R2, typename Rep2>
[[nodiscard]] constexpr Quantity auto operator-(const quantity<R1, Rep1>& lhs, const quantity<R2, Rep2>& rhs)
{
using ret = detail::common_quantity_for<std::minus<>, quantity<R1, Rep1>, quantity<R2, Rep2>>;
return make_quantity<ret::reference>(ret(lhs).numerical_value() - ret(rhs).numerical_value());
return make_quantity<ret::reference>(ret(lhs).numerical_value_ref_in(ret::unit) -
ret(rhs).numerical_value_ref_in(ret::unit));
}
template<auto R1, typename Rep1, auto R2, typename Rep2>
@ -360,7 +383,8 @@ template<auto R1, typename Rep1, auto R2, typename Rep2>
{
gsl_ExpectsAudit(rhs != rhs.zero());
using ret = detail::common_quantity_for<std::modulus<>, quantity<R1, Rep1>, quantity<R2, Rep2>>;
return make_quantity<ret::reference>(ret(lhs).numerical_value() % ret(rhs).numerical_value());
return make_quantity<ret::reference>(ret(lhs).numerical_value_ref_in(ret::unit) %
ret(rhs).numerical_value_ref_in(ret::unit));
}
template<auto R1, typename Rep1, auto R2, typename Rep2>
@ -368,7 +392,7 @@ template<auto R1, typename Rep1, auto R2, typename Rep2>
Rep2>
[[nodiscard]] constexpr Quantity auto operator*(const quantity<R1, Rep1>& lhs, const quantity<R2, Rep2>& rhs)
{
return make_quantity<R1 * R2>(lhs.numerical_value() * rhs.numerical_value());
return make_quantity<R1 * R2>(lhs.numerical_value_ref_in(get_unit(R1)) * rhs.numerical_value_ref_in(get_unit(R2)));
}
template<auto R, typename Rep, typename Value>
@ -376,7 +400,7 @@ template<auto R, typename Rep, typename Value>
detail::InvokeResultOf<get_quantity_spec(R).character, std::multiplies<>, Rep, const Value&>
[[nodiscard]] constexpr Quantity auto operator*(const quantity<R, Rep>& q, const Value& v)
{
return make_quantity<R>(q.numerical_value() * v);
return make_quantity<R>(q.numerical_value_ref_in(get_unit(R)) * v);
}
template<typename Value, auto R, typename Rep>
@ -384,7 +408,7 @@ template<typename Value, auto R, typename Rep>
detail::InvokeResultOf<get_quantity_spec(R).character, std::multiplies<>, const Value&, Rep>
[[nodiscard]] constexpr Quantity auto operator*(const Value& v, const quantity<R, Rep>& q)
{
return make_quantity<R>(v * q.numerical_value());
return make_quantity<R>(v * q.numerical_value_ref_in(get_unit(R)));
}
template<auto R1, typename Rep1, auto R2, typename Rep2>
@ -392,7 +416,7 @@ template<auto R1, typename Rep1, auto R2, typename Rep2>
[[nodiscard]] constexpr Quantity auto operator/(const quantity<R1, Rep1>& lhs, const quantity<R2, Rep2>& rhs)
{
gsl_ExpectsAudit(rhs != rhs.zero());
return make_quantity<R1 / R2>(lhs.numerical_value() / rhs.numerical_value());
return make_quantity<R1 / R2>(lhs.numerical_value_ref_in(get_unit(R1)) / rhs.numerical_value_ref_in(get_unit(R2)));
}
template<auto R, typename Rep, typename Value>
@ -401,7 +425,7 @@ template<auto R, typename Rep, typename Value>
[[nodiscard]] constexpr Quantity auto operator/(const quantity<R, Rep>& q, const Value& v)
{
gsl_ExpectsAudit(v != quantity_values<Value>::zero());
return make_quantity<R>(q.numerical_value() / v);
return make_quantity<R>(q.numerical_value_ref_in(get_unit(R)) / v);
}
template<typename Value, auto R, typename Rep>
@ -409,7 +433,7 @@ template<typename Value, auto R, typename Rep>
detail::InvokeResultOf<get_quantity_spec(R).character, std::divides<>, const Value&, Rep>
[[nodiscard]] constexpr Quantity auto operator/(const Value& v, const quantity<R, Rep>& q)
{
return make_quantity<::mp_units::one / R>(v / q.numerical_value());
return make_quantity<::mp_units::one / R>(v / q.numerical_value_ref_in(get_unit(R)));
}
template<auto R1, typename Rep1, auto R2, typename Rep2>
@ -418,7 +442,7 @@ template<auto R1, typename Rep1, auto R2, typename Rep2>
[[nodiscard]] constexpr bool operator==(const quantity<R1, Rep1>& lhs, const quantity<R2, Rep2>& rhs)
{
using ct = std::common_type_t<quantity<R1, Rep1>, quantity<R2, Rep2>>;
return ct(lhs).numerical_value() == ct(rhs).numerical_value();
return ct(lhs).numerical_value_ref_in(ct::unit) == ct(rhs).numerical_value_ref_in(ct::unit);
}
template<auto R1, typename Rep1, auto R2, typename Rep2>
@ -427,7 +451,7 @@ template<auto R1, typename Rep1, auto R2, typename Rep2>
[[nodiscard]] constexpr auto operator<=>(const quantity<R1, Rep1>& lhs, const quantity<R2, Rep2>& rhs)
{
using ct = std::common_type_t<quantity<R1, Rep1>, quantity<R2, Rep2>>;
return ct(lhs).numerical_value() <=> ct(rhs).numerical_value();
return ct(lhs).numerical_value_ref_in(ct::unit) <=> ct(rhs).numerical_value_ref_in(ct::unit);
}
// make_quantity

View File

@ -111,7 +111,8 @@ struct quantity_spec_interface {
requires Quantity<std::remove_cvref_t<Q>> &&
(explicitly_convertible(std::remove_reference_t<Q>::quantity_spec, self))
{
return make_quantity<reference<self, std::remove_cvref_t<Q>::unit>{}>(std::forward<Q>(q).numerical_value());
return make_quantity<reference<self, std::remove_cvref_t<Q>::unit>{}>(
std::forward<Q>(q).numerical_value_ref_in(q.unit));
}
#else
template<typename Self_ = Self, UnitOf<Self_{}> U>
@ -128,7 +129,8 @@ struct quantity_spec_interface {
(explicitly_convertible(std::remove_reference_t<Q>::quantity_spec, Self_{}))
[[nodiscard]] constexpr Quantity auto operator()(Q&& q) const
{
return make_quantity<reference<Self{}, std::remove_cvref_t<Q>::unit>{}>(std::forward<Q>(q).numerical_value());
return make_quantity<reference<Self{}, std::remove_cvref_t<Q>::unit>{}>(
std::forward<Q>(q).numerical_value_ref_in(q.unit));
}
#endif
};
@ -307,7 +309,8 @@ struct quantity_spec<Self, QS, Args...> : std::remove_const_t<decltype(QS)> {
(explicitly_convertible(std::remove_reference_t<Q>::quantity_spec, Self_{}))
[[nodiscard]] constexpr Quantity auto operator()(Q&& q) const
{
return make_quantity<reference<Self{}, std::remove_cvref_t<Q>::unit>{}>(std::forward<Q>(q).numerical_value());
return make_quantity<reference<Self{}, std::remove_cvref_t<Q>::unit>{}>(
std::forward<Q>(q).numerical_value_ref_in(q.unit));
}
#endif
};

View File

@ -92,7 +92,7 @@ template<QuantityOf<isq::time> Q>
{
constexpr auto canonical = detail::get_canonical_unit(Q::unit);
constexpr ratio r = as_ratio(canonical.mag);
return std::chrono::duration<typename Q::rep, std::ratio<r.num, r.den>>{q.numerical_value()};
return std::chrono::duration<typename Q::rep, std::ratio<r.num, r.den>>{q.numerical_value_ref_in(Q::unit)};
}
template<QuantityPointOf<isq::time> QP>

View File

@ -54,7 +54,8 @@ template<std::intmax_t Num, std::intmax_t Den = 1, auto R, typename Rep>
requires detail::non_zero<Den> &&
requires { quantity_values<Rep>::one(); }
[[nodiscard]] constexpr quantity<pow<Num, Den>(R), Rep> pow(const quantity<R, Rep>& q) noexcept
requires requires { pow(q.numerical_value(), 1.0); } || requires { std::pow(q.numerical_value(), 1.0); }
requires requires { pow(q.numerical_value_ref_in(q.unit), 1.0); } ||
requires { std::pow(q.numerical_value_ref_in(q.unit), 1.0); }
{
if constexpr (Num == 0) {
return quantity<pow<Num, Den>(R), Rep>::one();
@ -63,7 +64,7 @@ template<std::intmax_t Num, std::intmax_t Den = 1, auto R, typename Rep>
} else {
using std::pow;
return make_quantity<pow<Num, Den>(R)>(
static_cast<Rep>(pow(q.numerical_value(), static_cast<double>(Num) / static_cast<double>(Den))));
static_cast<Rep>(pow(q.numerical_value_ref_in(q.unit), static_cast<double>(Num) / static_cast<double>(Den))));
}
}
@ -77,10 +78,11 @@ template<std::intmax_t Num, std::intmax_t Den = 1, auto R, typename Rep>
*/
template<auto R, typename Rep>
[[nodiscard]] constexpr quantity<sqrt(R), Rep> sqrt(const quantity<R, Rep>& q) noexcept
requires requires { sqrt(q.numerical_value()); } || requires { std::sqrt(q.numerical_value()); }
requires requires { sqrt(q.numerical_value_ref_in(q.unit)); } ||
requires { std::sqrt(q.numerical_value_ref_in(q.unit)); }
{
using std::sqrt;
return make_quantity<sqrt(R)>(static_cast<Rep>(sqrt(q.numerical_value())));
return make_quantity<sqrt(R)>(static_cast<Rep>(sqrt(q.numerical_value_ref_in(q.unit))));
}
/**
@ -93,10 +95,11 @@ template<auto R, typename Rep>
*/
template<auto R, typename Rep>
[[nodiscard]] constexpr quantity<cbrt(R), Rep> cbrt(const quantity<R, Rep>& q) noexcept
requires requires { cbrt(q.numerical_value()); } || requires { std::cbrt(q.numerical_value()); }
requires requires { cbrt(q.numerical_value_ref_in(q.unit)); } ||
requires { std::cbrt(q.numerical_value_ref_in(q.unit)); }
{
using std::cbrt;
return make_quantity<cbrt(R)>(static_cast<Rep>(cbrt(q.numerical_value())));
return make_quantity<cbrt(R)>(static_cast<Rep>(cbrt(q.numerical_value_ref_in(q.unit))));
}
/**
@ -109,11 +112,12 @@ template<auto R, typename Rep>
*/
template<ReferenceOf<dimensionless> auto R, typename Rep>
[[nodiscard]] constexpr quantity<R, Rep> exp(const quantity<R, Rep>& q)
requires requires { exp(q.numerical_value()); } || requires { std::exp(q.numerical_value()); }
requires requires { exp(q.numerical_value_ref_in(q.unit)); } ||
requires { std::exp(q.numerical_value_ref_in(q.unit)); }
{
using std::exp;
return value_cast<get_unit(R)>(
make_quantity<detail::clone_reference_with<one>(R)>(static_cast<Rep>(exp(value_cast<one>(q).numerical_value()))));
return value_cast<get_unit(R)>(make_quantity<detail::clone_reference_with<one>(R)>(
static_cast<Rep>(exp(value_cast<one>(q).numerical_value_ref_in(q.unit)))));
}
/**
@ -124,10 +128,11 @@ template<ReferenceOf<dimensionless> auto R, typename Rep>
*/
template<auto R, typename Rep>
[[nodiscard]] constexpr quantity<R, Rep> abs(const quantity<R, Rep>& q) noexcept
requires requires { abs(q.numerical_value()); } || requires { std::abs(q.numerical_value()); }
requires requires { abs(q.numerical_value_ref_in(q.unit)); } ||
requires { std::abs(q.numerical_value_ref_in(q.unit)); }
{
using std::abs;
return make_quantity<R>(static_cast<Rep>(abs(q.numerical_value())));
return make_quantity<R>(static_cast<Rep>(abs(q.numerical_value_ref_in(q.unit))));
}
/**
@ -153,8 +158,9 @@ template<Representation Rep, Reference R>
*/
template<Unit auto To, auto R, typename Rep>
[[nodiscard]] constexpr quantity<detail::clone_reference_with<To>(R), Rep> floor(const quantity<R, Rep>& q) noexcept
requires((!treat_as_floating_point<Rep>) || requires { floor(q.numerical_value()); } ||
requires { std::floor(q.numerical_value()); }) &&
requires((!treat_as_floating_point<Rep>) || requires { floor(q.numerical_value_ref_in(q.unit)); } ||
requires { std::floor(q.numerical_value_ref_in(q.unit)); }) &&
(To == get_unit(R) || requires {
::mp_units::value_cast<To>(q);
quantity_values<Rep>::one();
@ -169,10 +175,11 @@ template<Unit auto To, auto R, typename Rep>
if constexpr (treat_as_floating_point<Rep>) {
using std::floor;
if constexpr (To == get_unit(R)) {
return make_quantity<detail::clone_reference_with<To>(R)>(static_cast<Rep>(floor(q.numerical_value())));
return make_quantity<detail::clone_reference_with<To>(R)>(
static_cast<Rep>(floor(q.numerical_value_ref_in(q.unit))));
} else {
return handle_signed_results(make_quantity<detail::clone_reference_with<To>(R)>(
static_cast<Rep>(floor(value_cast<To>(q).numerical_value()))));
static_cast<Rep>(floor(value_cast<To>(q).numerical_value_ref_in(To)))));
}
} else {
if constexpr (To == get_unit(R)) {
@ -191,8 +198,9 @@ template<Unit auto To, auto R, typename Rep>
*/
template<Unit auto To, auto R, typename Rep>
[[nodiscard]] constexpr quantity<detail::clone_reference_with<To>(R), Rep> ceil(const quantity<R, Rep>& q) noexcept
requires((!treat_as_floating_point<Rep>) || requires { ceil(q.numerical_value()); } ||
requires { std::ceil(q.numerical_value()); }) &&
requires((!treat_as_floating_point<Rep>) || requires { ceil(q.numerical_value_ref_in(q.unit)); } ||
requires { std::ceil(q.numerical_value_ref_in(q.unit)); }) &&
(To == get_unit(R) || requires {
::mp_units::value_cast<To>(q);
quantity_values<Rep>::one();
@ -207,10 +215,11 @@ template<Unit auto To, auto R, typename Rep>
if constexpr (treat_as_floating_point<Rep>) {
using std::ceil;
if constexpr (To == get_unit(R)) {
return make_quantity<detail::clone_reference_with<To>(R)>(static_cast<Rep>(ceil(q.numerical_value())));
return make_quantity<detail::clone_reference_with<To>(R)>(
static_cast<Rep>(ceil(q.numerical_value_ref_in(q.unit))));
} else {
return handle_signed_results(make_quantity<detail::clone_reference_with<To>(R)>(
static_cast<Rep>(ceil(value_cast<To>(q).numerical_value()))));
static_cast<Rep>(ceil(value_cast<To>(q).numerical_value_ref_in(To)))));
}
} else {
if constexpr (To == get_unit(R)) {
@ -231,8 +240,9 @@ template<Unit auto To, auto R, typename Rep>
*/
template<Unit auto To, auto R, typename Rep>
[[nodiscard]] constexpr quantity<detail::clone_reference_with<To>(R), Rep> round(const quantity<R, Rep>& q) noexcept
requires((!treat_as_floating_point<Rep>) || requires { round(q.numerical_value()); } ||
requires { std::round(q.numerical_value()); }) &&
requires((!treat_as_floating_point<Rep>) || requires { round(q.numerical_value_ref_in(q.unit)); } ||
requires { std::round(q.numerical_value_ref_in(q.unit)); }) &&
(To == get_unit(R) || requires {
::mp_units::floor<To>(q);
quantity_values<Rep>::one();
@ -241,7 +251,8 @@ template<Unit auto To, auto R, typename Rep>
if constexpr (To == get_unit(R)) {
if constexpr (treat_as_floating_point<Rep>) {
using std::round;
return make_quantity<detail::clone_reference_with<To>(R)>(static_cast<Rep>(round(q.numerical_value())));
return make_quantity<detail::clone_reference_with<To>(R)>(
static_cast<Rep>(round(q.numerical_value_ref_in(q.unit))));
} else {
return value_cast<To>(q);
}
@ -251,7 +262,7 @@ template<Unit auto To, auto R, typename Rep>
const auto diff0 = q - res_low;
const auto diff1 = res_high - q;
if (diff0 == diff1) {
if (static_cast<int>(res_low.numerical_value()) & 1) {
if (static_cast<int>(res_low.numerical_value_ref_in(To)) & 1) {
return res_high;
}
return res_low;
@ -272,8 +283,9 @@ template<auto R1, typename Rep1, auto R2, typename Rep2>
const quantity<R1, Rep1>& x, const quantity<R2, Rep2>& y) noexcept
requires requires { common_reference(R1, R2); } &&
(
requires { hypot(x.numerical_value(), y.numerical_value()); } ||
requires { std::hypot(x.numerical_value(), y.numerical_value()); })
requires { hypot(x.numerical_value_ref_in(x.unit), y.numerical_value_ref_in(y.unit)); } ||
requires { std::hypot(x.numerical_value_ref_in(x.unit), y.numerical_value_ref_in(y.unit)); })
{
constexpr auto ref = common_reference(R1, R2);
constexpr auto unit = get_unit(ref);
@ -290,8 +302,14 @@ template<auto R1, typename Rep1, auto R2, typename Rep2, auto R3, typename Rep3>
const quantity<R1, Rep1>& x, const quantity<R2, Rep2>& y, const quantity<R3, Rep3>& z) noexcept
requires requires { common_reference(R1, R2, R3); } &&
(
requires { hypot(x.numerical_value(), y.numerical_value(), z.numerical_value()); } ||
requires { std::hypot(x.numerical_value(), y.numerical_value(), z.numerical_value()); })
requires {
hypot(x.numerical_value_ref_in(x.unit), y.numerical_value_ref_in(y.unit),
z.numerical_value_ref_in(z.unit));
} ||
requires {
std::hypot(x.numerical_value_ref_in(x.unit), y.numerical_value_ref_in(y.unit),
z.numerical_value_ref_in(z.unit));
})
{
constexpr auto ref = common_reference(R1, R2);
constexpr auto unit = get_unit(ref);
@ -303,12 +321,13 @@ namespace isq {
template<ReferenceOf<angular_measure> auto R, typename Rep>
[[nodiscard]] inline QuantityOf<dimensionless> auto sin(const quantity<R, Rep>& q) noexcept
requires requires { sin(q.numerical_value()); } || requires { std::sin(q.numerical_value()); }
requires requires { sin(q.numerical_value_ref_in(q.unit)); } ||
requires { std::sin(q.numerical_value_ref_in(q.unit)); }
{
using std::sin;
if constexpr (!treat_as_floating_point<Rep>) {
// check what is the return type when called with the integral value
using rep = decltype(sin(value_cast<si::radian>(q).numerical_value()));
using rep = decltype(sin(value_cast<si::radian>(q).numerical_value_in(si::radian)));
// use this type ahead of calling the function to prevent narrowing if a unit conversion is needed
return make_quantity<one>(sin(value_cast<rep>(q).numerical_value_in(si::radian)));
} else
@ -317,12 +336,13 @@ template<ReferenceOf<angular_measure> auto R, typename Rep>
template<ReferenceOf<angular_measure> auto R, typename Rep>
[[nodiscard]] inline QuantityOf<dimensionless> auto cos(const quantity<R, Rep>& q) noexcept
requires requires { cos(q.numerical_value()); } || requires { std::cos(q.numerical_value()); }
requires requires { cos(q.numerical_value_ref_in(q.unit)); } ||
requires { std::cos(q.numerical_value_ref_in(q.unit)); }
{
using std::cos;
if constexpr (!treat_as_floating_point<Rep>) {
// check what is the return type when called with the integral value
using rep = decltype(cos(value_cast<si::radian>(q).numerical_value()));
using rep = decltype(cos(value_cast<si::radian>(q).numerical_value_in(si::radian)));
// use this type ahead of calling the function to prevent narrowing if a unit conversion is needed
return make_quantity<one>(cos(value_cast<rep>(q).numerical_value_in(si::radian)));
} else
@ -331,12 +351,13 @@ template<ReferenceOf<angular_measure> auto R, typename Rep>
template<ReferenceOf<angular_measure> auto R, typename Rep>
[[nodiscard]] inline QuantityOf<dimensionless> auto tan(const quantity<R, Rep>& q) noexcept
requires requires { tan(q.numerical_value()); } || requires { std::tan(q.numerical_value()); }
requires requires { tan(q.numerical_value_ref_in(q.unit)); } ||
requires { std::tan(q.numerical_value_ref_in(q.unit)); }
{
using std::tan;
if constexpr (!treat_as_floating_point<Rep>) {
// check what is the return type when called with the integral value
using rep = decltype(tan(value_cast<si::radian>(q).numerical_value()));
using rep = decltype(tan(value_cast<si::radian>(q).numerical_value_in(si::radian)));
// use this type ahead of calling the function to prevent narrowing if a unit conversion is needed
return make_quantity<one>(tan(value_cast<rep>(q).numerical_value_in(si::radian)));
} else
@ -345,12 +366,13 @@ template<ReferenceOf<angular_measure> auto R, typename Rep>
template<ReferenceOf<dimensionless> auto R, typename Rep>
[[nodiscard]] inline QuantityOf<isq::angular_measure> auto asin(const quantity<R, Rep>& q) noexcept
requires requires { asin(q.numerical_value()); } || requires { std::asin(q.numerical_value()); }
requires requires { asin(q.numerical_value_ref_in(q.unit)); } ||
requires { std::asin(q.numerical_value_ref_in(q.unit)); }
{
using std::asin;
if constexpr (!treat_as_floating_point<Rep>) {
// check what is the return type when called with the integral value
using rep = decltype(asin(value_cast<one>(q).numerical_value()));
using rep = decltype(asin(value_cast<one>(q).numerical_value_in(one)));
// use this type ahead of calling the function to prevent narrowing if a unit conversion is needed
return make_quantity<si::radian>(asin(value_cast<rep>(q).numerical_value_in(one)));
} else
@ -359,7 +381,8 @@ template<ReferenceOf<dimensionless> auto R, typename Rep>
template<ReferenceOf<dimensionless> auto R, typename Rep>
[[nodiscard]] inline QuantityOf<isq::angular_measure> auto acos(const quantity<R, Rep>& q) noexcept
requires requires { acos(q.numerical_value()); } || requires { std::acos(q.numerical_value()); }
requires requires { acos(q.numerical_value_ref_in(q.unit)); } ||
requires { std::acos(q.numerical_value_ref_in(q.unit)); }
{
using std::acos;
if constexpr (!treat_as_floating_point<Rep>) {
@ -373,12 +396,13 @@ template<ReferenceOf<dimensionless> auto R, typename Rep>
template<ReferenceOf<dimensionless> auto R, typename Rep>
[[nodiscard]] inline QuantityOf<isq::angular_measure> auto atan(const quantity<R, Rep>& q) noexcept
requires requires { atan(q.numerical_value()); } || requires { std::atan(q.numerical_value()); }
requires requires { atan(q.numerical_value_ref_in(q.unit)); } ||
requires { std::atan(q.numerical_value_ref_in(q.unit)); }
{
using std::atan;
if constexpr (!treat_as_floating_point<Rep>) {
// check what is the return type when called with the integral value
using rep = decltype(atan(value_cast<one>(q).numerical_value()));
using rep = decltype(atan(value_cast<one>(q).numerical_value_in(one)));
// use this type ahead of calling the function to prevent narrowing if a unit conversion is needed
return make_quantity<si::radian>(atan(value_cast<rep>(q).numerical_value_in(one)));
} else
@ -391,12 +415,13 @@ namespace angular {
template<ReferenceOf<angle> auto R, typename Rep>
[[nodiscard]] inline QuantityOf<dimensionless> auto sin(const quantity<R, Rep>& q) noexcept
requires requires { sin(q.numerical_value()); } || requires { std::sin(q.numerical_value()); }
requires requires { sin(q.numerical_value_ref_in(q.unit)); } ||
requires { std::sin(q.numerical_value_ref_in(q.unit)); }
{
using std::sin;
if constexpr (!treat_as_floating_point<Rep>) {
// check what is the return type when called with the integral value
using rep = decltype(sin(value_cast<radian>(q).numerical_value()));
using rep = decltype(sin(value_cast<radian>(q).numerical_value_in(radian)));
// use this type ahead of calling the function to prevent narrowing if a unit conversion is needed
return make_quantity<one>(sin(value_cast<rep>(q).numerical_value_in(radian)));
} else
@ -405,12 +430,13 @@ template<ReferenceOf<angle> auto R, typename Rep>
template<ReferenceOf<angle> auto R, typename Rep>
[[nodiscard]] inline QuantityOf<dimensionless> auto cos(const quantity<R, Rep>& q) noexcept
requires requires { cos(q.numerical_value()); } || requires { std::cos(q.numerical_value()); }
requires requires { cos(q.numerical_value_ref_in(q.unit)); } ||
requires { std::cos(q.numerical_value_ref_in(q.unit)); }
{
using std::cos;
if constexpr (!treat_as_floating_point<Rep>) {
// check what is the return type when called with the integral value
using rep = decltype(cos(value_cast<radian>(q).numerical_value()));
using rep = decltype(cos(value_cast<radian>(q).numerical_value_in(radian)));
// use this type ahead of calling the function to prevent narrowing if a unit conversion is needed
return make_quantity<one>(cos(value_cast<rep>(q).numerical_value_in(radian)));
} else
@ -419,12 +445,13 @@ template<ReferenceOf<angle> auto R, typename Rep>
template<ReferenceOf<angle> auto R, typename Rep>
[[nodiscard]] inline QuantityOf<dimensionless> auto tan(const quantity<R, Rep>& q) noexcept
requires requires { tan(q.numerical_value()); } || requires { std::tan(q.numerical_value()); }
requires requires { tan(q.numerical_value_ref_in(q.unit)); } ||
requires { std::tan(q.numerical_value_ref_in(q.unit)); }
{
using std::tan;
if constexpr (!treat_as_floating_point<Rep>) {
// check what is the return type when called with the integral value
using rep = decltype(tan(value_cast<radian>(q).numerical_value()));
using rep = decltype(tan(value_cast<radian>(q).numerical_value_in(radian)));
// use this type ahead of calling the function to prevent narrowing if a unit conversion is needed
return make_quantity<one>(tan(value_cast<rep>(q).numerical_value_in(radian)));
} else
@ -433,12 +460,13 @@ template<ReferenceOf<angle> auto R, typename Rep>
template<ReferenceOf<dimensionless> auto R, typename Rep>
[[nodiscard]] inline QuantityOf<angle> auto asin(const quantity<R, Rep>& q) noexcept
requires requires { asin(q.numerical_value()); } || requires { std::asin(q.numerical_value()); }
requires requires { asin(q.numerical_value_ref_in(q.unit)); } ||
requires { std::asin(q.numerical_value_ref_in(q.unit)); }
{
using std::asin;
if constexpr (!treat_as_floating_point<Rep>) {
// check what is the return type when called with the integral value
using rep = decltype(asin(value_cast<one>(q).numerical_value()));
using rep = decltype(asin(value_cast<one>(q).numerical_value_in(one)));
// use this type ahead of calling the function to prevent narrowing if a unit conversion is needed
return make_quantity<radian>(asin(value_cast<rep>(q).numerical_value_in(one)));
} else
@ -447,12 +475,13 @@ template<ReferenceOf<dimensionless> auto R, typename Rep>
template<ReferenceOf<dimensionless> auto R, typename Rep>
[[nodiscard]] inline QuantityOf<angle> auto acos(const quantity<R, Rep>& q) noexcept
requires requires { acos(q.numerical_value()); } || requires { std::acos(q.numerical_value()); }
requires requires { acos(q.numerical_value_ref_in(q.unit)); } ||
requires { std::acos(q.numerical_value_ref_in(q.unit)); }
{
using std::acos;
if constexpr (!treat_as_floating_point<Rep>) {
// check what is the return type when called with the integral value
using rep = decltype(acos(value_cast<one>(q).numerical_value()));
using rep = decltype(acos(value_cast<one>(q).numerical_value_in(one)));
// use this type ahead of calling the function to prevent narrowing if a unit conversion is needed
return make_quantity<radian>(acos(value_cast<rep>(q).numerical_value_in(one)));
} else
@ -461,12 +490,13 @@ template<ReferenceOf<dimensionless> auto R, typename Rep>
template<ReferenceOf<dimensionless> auto R, typename Rep>
[[nodiscard]] inline QuantityOf<angle> auto atan(const quantity<R, Rep>& q) noexcept
requires requires { atan(q.numerical_value()); } || requires { std::atan(q.numerical_value()); }
requires requires { atan(q.numerical_value_ref_in(q.unit)); } ||
requires { std::atan(q.numerical_value_ref_in(q.unit)); }
{
using std::atan;
if constexpr (!treat_as_floating_point<Rep>) {
// check what is the return type when called with the integral value
using rep = decltype(atan(value_cast<one>(q).numerical_value()));
using rep = decltype(atan(value_cast<one>(q).numerical_value_in(one)));
// use this type ahead of calling the function to prevent narrowing if a unit conversion is needed
return make_quantity<radian>(atan(value_cast<rep>(q).numerical_value_in(one)));
} else

View File

@ -35,7 +35,7 @@ static std::vector<typename Q::rep> i_qty_to_rep(InputIt first, InputIt last)
std::vector<typename Q::rep> intervals_rep;
intervals_rep.reserve(static_cast<size_t>(std::distance(first, last)));
for (auto itr = first; itr != last; ++itr) {
intervals_rep.push_back(itr->numerical_value());
intervals_rep.push_back(itr->numerical_value_ref_in(Q::unit));
}
return intervals_rep;
}
@ -46,7 +46,7 @@ static std::vector<typename Q::rep> bl_qty_to_rep(std::initializer_list<Q>& bl)
std::vector<typename Q::rep> bl_rep;
bl_rep.reserve(bl.size());
for (const Q& qty : bl) {
bl_rep.push_back(qty.numerical_value());
bl_rep.push_back(qty.numerical_value_ref_in(Q::unit));
}
return bl_rep;
}
@ -88,7 +88,10 @@ struct uniform_int_distribution : public std::uniform_int_distribution<typename
using base = MP_UNITS_TYPENAME std::uniform_int_distribution<rep>;
uniform_int_distribution() : base() {}
uniform_int_distribution(const Q& a, const Q& b) : base(a.numerical_value(), b.numerical_value()) {}
uniform_int_distribution(const Q& a, const Q& b) :
base(a.numerical_value_ref_in(Q::unit), b.numerical_value_ref_in(Q::unit))
{
}
template<typename Generator>
Q operator()(Generator& g)
@ -110,7 +113,10 @@ struct uniform_real_distribution : public std::uniform_real_distribution<typenam
using base = MP_UNITS_TYPENAME std::uniform_real_distribution<rep>;
uniform_real_distribution() : base() {}
uniform_real_distribution(const Q& a, const Q& b) : base(a.numerical_value(), b.numerical_value()) {}
uniform_real_distribution(const Q& a, const Q& b) :
base(a.numerical_value_ref_in(Q::unit), b.numerical_value_ref_in(Q::unit))
{
}
template<typename Generator>
Q operator()(Generator& g)
@ -132,7 +138,7 @@ struct binomial_distribution : public std::binomial_distribution<typename Q::rep
using base = MP_UNITS_TYPENAME std::binomial_distribution<rep>;
binomial_distribution() : base() {}
binomial_distribution(const Q& t, double p) : base(t.numerical_value(), p) {}
binomial_distribution(const Q& t, double p) : base(t.numerical_value_ref_in(Q::unit), p) {}
template<typename Generator>
Q operator()(Generator& g)
@ -153,7 +159,7 @@ struct negative_binomial_distribution : public std::negative_binomial_distributi
using base = MP_UNITS_TYPENAME std::negative_binomial_distribution<rep>;
negative_binomial_distribution() : base() {}
negative_binomial_distribution(const Q& k, double p) : base(k.numerical_value(), p) {}
negative_binomial_distribution(const Q& k, double p) : base(k.numerical_value_ref_in(Q::unit), p) {}
template<typename Generator>
Q operator()(Generator& g)
@ -269,7 +275,7 @@ struct extreme_value_distribution : public std::extreme_value_distribution<typen
using base = MP_UNITS_TYPENAME std::extreme_value_distribution<rep>;
extreme_value_distribution() : base() {}
extreme_value_distribution(const Q& a, const rep& b) : base(a.numerical_value(), b) {}
extreme_value_distribution(const Q& a, const rep& b) : base(a.numerical_value_ref_in(Q::unit), b) {}
template<typename Generator>
Q operator()(Generator& g)
@ -290,7 +296,10 @@ struct normal_distribution : public std::normal_distribution<typename Q::rep> {
using base = MP_UNITS_TYPENAME std::normal_distribution<rep>;
normal_distribution() : base() {}
normal_distribution(const Q& mean, const Q& stddev) : base(mean.numerical_value(), stddev.numerical_value()) {}
normal_distribution(const Q& mean, const Q& stddev) :
base(mean.numerical_value_ref_in(Q::unit), stddev.numerical_value_ref_in(Q::unit))
{
}
template<typename Generator>
Q operator()(Generator& g)
@ -312,7 +321,10 @@ struct lognormal_distribution : public std::lognormal_distribution<typename Q::r
using base = MP_UNITS_TYPENAME std::lognormal_distribution<rep>;
lognormal_distribution() : base() {}
lognormal_distribution(const Q& m, const Q& s) : base(m.numerical_value(), s.numerical_value()) {}
lognormal_distribution(const Q& m, const Q& s) :
base(m.numerical_value_ref_in(Q::unit), s.numerical_value_ref_in(Q::unit))
{
}
template<typename Generator>
Q operator()(Generator& g)
@ -353,7 +365,10 @@ struct cauchy_distribution : public std::cauchy_distribution<typename Q::rep> {
using base = MP_UNITS_TYPENAME std::cauchy_distribution<rep>;
cauchy_distribution() : base() {}
cauchy_distribution(const Q& a, const Q& b) : base(a.numerical_value(), b.numerical_value()) {}
cauchy_distribution(const Q& a, const Q& b) :
base(a.numerical_value_ref_in(Q::unit), b.numerical_value_ref_in(Q::unit))
{
}
template<typename Generator>
Q operator()(Generator& g)
@ -470,7 +485,8 @@ public:
template<typename UnaryOperation>
piecewise_constant_distribution(std::size_t nw, const Q& xmin, const Q& xmax, UnaryOperation fw) :
base(nw, xmin.numerical_value(), xmax.numerical_value(), [fw](rep val) { return fw(val * Q::reference); })
base(nw, xmin.numerical_value_ref_in(Q::unit), xmax.numerical_value_ref_in(Q::unit),
[fw](rep val) { return fw(val * Q::reference); })
{
}
@ -528,7 +544,8 @@ public:
template<typename UnaryOperation>
piecewise_linear_distribution(std::size_t nw, const Q& xmin, const Q& xmax, UnaryOperation fw) :
base(nw, xmin.numerical_value(), xmax.numerical_value(), [fw](rep val) { return fw(val * Q::reference); })
base(nw, xmin.numerical_value_ref_in(Q::unit), xmax.numerical_value_ref_in(Q::unit),
[fw](rep val) { return fw(val * Q::reference); })
{
}

View File

@ -36,8 +36,8 @@ struct AlmostEqualsMatcher : Catch::Matchers::MatcherGenericBase {
{
using std::abs;
using common = std::common_type_t<T, U>;
const auto x = common(target_).numerical_value();
const auto y = common(other).numerical_value();
const auto x = common(target_).numerical_value_ref_in(common::unit);
const auto y = common(other).numerical_value_ref_in(common::unit);
const auto maxXYOne = std::max({typename T::rep{1}, abs(x), abs(y)});
return abs(x - y) <= std::numeric_limits<typename T::rep>::epsilon() * maxXYOne;
}

View File

@ -560,7 +560,9 @@ TEST_CASE("piecewise_constant_distribution")
auto stl_dist = std::piecewise_constant_distribution<rep>(intervals_rep, [](rep val) { return val; });
auto units_dist =
mp_units::piecewise_constant_distribution<q>(intervals_qty, [](q qty) { return qty.numerical_value(); });
mp_units::piecewise_constant_distribution<q>(intervals_qty,
[](q qty) { return qty.numerical_value_ref_in(qty.unit); });
CHECK(units_dist.intervals() == intervals_qty_vec);
CHECK(units_dist.densities() == stl_dist.densities());
@ -573,8 +575,8 @@ TEST_CASE("piecewise_constant_distribution")
constexpr q xmin_qty = 1.0 * isq::length[si::metre], xmax_qty = 3.0 * isq::length[si::metre];
auto stl_dist = std::piecewise_constant_distribution<rep>(nw, xmin_rep, xmax_rep, [](rep val) { return val; });
auto units_dist =
mp_units::piecewise_constant_distribution<q>(nw, xmin_qty, xmax_qty, [](q qty) { return qty.numerical_value(); });
auto units_dist = mp_units::piecewise_constant_distribution<q>(
nw, xmin_qty, xmax_qty, [](q qty) { return qty.numerical_value_ref_in(qty.unit); });
CHECK(units_dist.intervals() == intervals_qty_vec);
CHECK(units_dist.densities() == stl_dist.densities());
@ -628,7 +630,9 @@ TEST_CASE("piecewise_linear_distribution")
auto stl_dist = std::piecewise_linear_distribution<rep>(intervals_rep, [](rep val) { return val; });
auto units_dist =
mp_units::piecewise_linear_distribution<q>(intervals_qty, [](q qty) { return qty.numerical_value(); });
mp_units::piecewise_linear_distribution<q>(intervals_qty,
[](q qty) { return qty.numerical_value_ref_in(qty.unit); });
CHECK(units_dist.intervals() == intervals_qty_vec);
CHECK(units_dist.densities() == stl_dist.densities());
@ -641,8 +645,8 @@ TEST_CASE("piecewise_linear_distribution")
constexpr q xmin_qty = 1.0 * isq::length[si::metre], xmax_qty = 3.0 * isq::length[si::metre];
auto stl_dist = std::piecewise_linear_distribution<rep>(nw, xmin_rep, xmax_rep, [](rep val) { return val; });
auto units_dist =
mp_units::piecewise_linear_distribution<q>(nw, xmin_qty, xmax_qty, [](q qty) { return qty.numerical_value(); });
auto units_dist = mp_units::piecewise_linear_distribution<q>(
nw, xmin_qty, xmax_qty, [](q qty) { return qty.numerical_value_ref_in(qty.unit); });
CHECK(units_dist.intervals() == intervals_qty_vec);
CHECK(units_dist.densities() == stl_dist.densities());

View File

@ -74,7 +74,8 @@ template<Quantity Q1, Quantity Q2>
requires(typename Q1::rep v1, typename Q2::rep v2) { cross_product(v1, v2); }
[[nodiscard]] QuantityOf<Q1::quantity_spec * Q2::quantity_spec> auto cross_product(const Q1& q1, const Q2& q2)
{
return cross_product(q1.numerical_value(), q2.numerical_value()) * (Q1::reference * Q2::reference);
return cross_product(q1.numerical_value_ref_in(q1.unit), q2.numerical_value_ref_in(q2.unit)) *
(Q1::reference * Q2::reference);
}
} // namespace
@ -86,21 +87,22 @@ TEST_CASE("vector quantity", "[la]")
SECTION("non-truncating")
{
const auto v = vector<int>{3, 2, 1} * isq::position_vector[km];
CHECK(v.in(m).numerical_value() == vector<int>{3000, 2000, 1000});
CHECK(v.numerical_value_in(m) == vector<int>{3000, 2000, 1000});
}
SECTION("truncating")
{
const auto v = vector<int>{1001, 1002, 1003} * isq::position_vector[m];
CHECK(value_cast<km>(v).numerical_value() == vector<int>{1, 1, 1});
CHECK(value_cast<km>(v).numerical_value_ref_in(km) == vector<int>{1, 1, 1});
}
}
SECTION("to scalar magnitude")
{
const auto v = vector<int>{2, 3, 6} * isq::velocity[km / h];
const auto speed = get_magnitude(v.numerical_value()) * isq::speed[v.unit]; // TODO can we do better here?
CHECK(speed.numerical_value() == 7);
const auto speed =
get_magnitude(v.numerical_value_ref_in(km / h)) * isq::speed[v.unit]; // TODO can we do better here?
CHECK(speed.numerical_value_ref_in(km / h) == 7);
}
SECTION("multiply by scalar value")
@ -109,14 +111,14 @@ TEST_CASE("vector quantity", "[la]")
SECTION("integral")
{
SECTION("scalar on LHS") { CHECK((2 * v).numerical_value() == vector<int>{2, 4, 6}); }
SECTION("scalar on RHS") { CHECK((v * 2).numerical_value() == vector<int>{2, 4, 6}); }
SECTION("scalar on LHS") { CHECK((2 * v).numerical_value_ref_in(m) == vector<int>{2, 4, 6}); }
SECTION("scalar on RHS") { CHECK((v * 2).numerical_value_ref_in(m) == vector<int>{2, 4, 6}); }
}
SECTION("floating-point")
{
SECTION("scalar on LHS") { CHECK((0.5 * v).numerical_value() == vector<double>{0.5, 1., 1.5}); }
SECTION("scalar on RHS") { CHECK((v * 0.5).numerical_value() == vector<double>{0.5, 1., 1.5}); }
SECTION("scalar on LHS") { CHECK((0.5 * v).numerical_value_ref_in(m) == vector<double>{0.5, 1., 1.5}); }
SECTION("scalar on RHS") { CHECK((v * 0.5).numerical_value_ref_in(m) == vector<double>{0.5, 1., 1.5}); }
}
}
@ -124,8 +126,8 @@ TEST_CASE("vector quantity", "[la]")
{
const auto v = vector<int>{2, 4, 6} * isq::position_vector[m];
SECTION("integral") { CHECK((v / 2).numerical_value() == vector<int>{1, 2, 3}); }
SECTION("floating-point") { CHECK((v / 0.5).numerical_value() == vector<double>{4., 8., 12.}); }
SECTION("integral") { CHECK((v / 2).numerical_value_ref_in(m) == vector<int>{1, 2, 3}); }
SECTION("floating-point") { CHECK((v / 0.5).numerical_value_ref_in(m) == vector<double>{4., 8., 12.}); }
}
SECTION("add")
@ -135,12 +137,12 @@ TEST_CASE("vector quantity", "[la]")
SECTION("same unit")
{
const auto u = vector<int>{3, 2, 1} * isq::position_vector[m];
CHECK((v + u).numerical_value() == vector<int>{4, 4, 4});
CHECK((v + u).numerical_value_ref_in(m) == vector<int>{4, 4, 4});
}
SECTION("different units")
{
const auto u = vector<int>{3, 2, 1} * isq::position_vector[km];
CHECK((v + u).numerical_value() == vector<int>{3001, 2002, 1003});
CHECK((v + u).numerical_value_ref_in(m) == vector<int>{3001, 2002, 1003});
}
}
@ -151,12 +153,12 @@ TEST_CASE("vector quantity", "[la]")
SECTION("same unit")
{
const auto u = vector<int>{3, 2, 1} * isq::position_vector[m];
CHECK((v - u).numerical_value() == vector<int>{-2, 0, 2});
CHECK((v - u).numerical_value_ref_in(m) == vector<int>{-2, 0, 2});
}
SECTION("different units")
{
const auto u = vector<int>{3, 2, 1} * isq::position_vector[km];
CHECK((v - u).numerical_value() == vector<int>{-2999, -1998, -997});
CHECK((v - u).numerical_value_ref_in(m) == vector<int>{-2999, -1998, -997});
}
}
@ -170,18 +172,18 @@ TEST_CASE("vector quantity", "[la]")
SECTION("derived_quantity_spec")
{
SECTION("scalar on LHS") { CHECK((mass * v).numerical_value() == vector<int>{2, 4, 6}); }
SECTION("scalar on RHS") { CHECK((v * mass).numerical_value() == vector<int>{2, 4, 6}); }
SECTION("scalar on LHS") { CHECK((mass * v).numerical_value_ref_in(N * s) == vector<int>{2, 4, 6}); }
SECTION("scalar on RHS") { CHECK((v * mass).numerical_value_ref_in(N * s) == vector<int>{2, 4, 6}); }
}
SECTION("quantity_cast to momentum")
{
SECTION("scalar on LHS")
{
CHECK(quantity_cast<isq::momentum>(mass * v).numerical_value() == vector<int>{2, 4, 6});
CHECK(quantity_cast<isq::momentum>(mass * v).numerical_value_ref_in(N * s) == vector<int>{2, 4, 6});
}
SECTION("scalar on RHS")
{
CHECK(quantity_cast<isq::momentum>(v * mass).numerical_value() == vector<int>{2, 4, 6});
CHECK(quantity_cast<isq::momentum>(v * mass).numerical_value_ref_in(N * s) == vector<int>{2, 4, 6});
}
}
SECTION("quantity of momentum")
@ -189,12 +191,12 @@ TEST_CASE("vector quantity", "[la]")
SECTION("scalar on LHS")
{
const quantity<isq::momentum[N * s], vector<int>> momentum = mass * v;
CHECK(momentum.numerical_value() == vector<int>{2, 4, 6});
CHECK(momentum.numerical_value_ref_in(N * s) == vector<int>{2, 4, 6});
}
SECTION("scalar on RHS")
{
const quantity<isq::momentum[N * s], vector<int>> momentum = v * mass;
CHECK(momentum.numerical_value() == vector<int>{2, 4, 6});
CHECK(momentum.numerical_value_ref_in(N * s) == vector<int>{2, 4, 6});
}
}
}
@ -205,18 +207,18 @@ TEST_CASE("vector quantity", "[la]")
SECTION("derived_quantity_spec")
{
SECTION("scalar on LHS") { CHECK((mass * v).numerical_value() == vector<double>{0.5, 1., 1.5}); }
SECTION("scalar on RHS") { CHECK((v * mass).numerical_value() == vector<double>{0.5, 1., 1.5}); }
SECTION("scalar on LHS") { CHECK((mass * v).numerical_value_ref_in(N * s) == vector<double>{0.5, 1., 1.5}); }
SECTION("scalar on RHS") { CHECK((v * mass).numerical_value_ref_in(N * s) == vector<double>{0.5, 1., 1.5}); }
}
SECTION("quantity_cast to momentum")
{
SECTION("scalar on LHS")
{
CHECK(quantity_cast<isq::momentum>(mass * v).numerical_value() == vector<double>{0.5, 1., 1.5});
CHECK(quantity_cast<isq::momentum>(mass * v).numerical_value_ref_in(N * s) == vector<double>{0.5, 1., 1.5});
}
SECTION("scalar on RHS")
{
CHECK(quantity_cast<isq::momentum>(v * mass).numerical_value() == vector<double>{0.5, 1., 1.5});
CHECK(quantity_cast<isq::momentum>(v * mass).numerical_value_ref_in(N * s) == vector<double>{0.5, 1., 1.5});
}
}
SECTION("quantity of momentum")
@ -224,12 +226,12 @@ TEST_CASE("vector quantity", "[la]")
SECTION("scalar on LHS")
{
const quantity<isq::momentum[N * s], vector<double>> momentum = mass * v;
CHECK(momentum.numerical_value() == vector<double>{0.5, 1., 1.5});
CHECK(momentum.numerical_value_ref_in(N * s) == vector<double>{0.5, 1., 1.5});
}
SECTION("scalar on RHS")
{
const quantity<isq::momentum[N * s], vector<double>> momentum = v * mass;
CHECK(momentum.numerical_value() == vector<double>{0.5, 1., 1.5});
CHECK(momentum.numerical_value_ref_in(N * s) == vector<double>{0.5, 1., 1.5});
}
}
}
@ -243,15 +245,15 @@ TEST_CASE("vector quantity", "[la]")
{
const auto dur = 2 * isq::duration[h];
SECTION("derived_quantity_spec") { CHECK((pos / dur).numerical_value() == vector<int>{15, 10, 5}); }
SECTION("derived_quantity_spec") { CHECK((pos / dur).numerical_value_ref_in(km / h) == vector<int>{15, 10, 5}); }
SECTION("quantity_cast to velocity")
{
CHECK(quantity_cast<isq::velocity>(pos / dur).numerical_value() == vector<int>{15, 10, 5});
CHECK(quantity_cast<isq::velocity>(pos / dur).numerical_value_ref_in(km / h) == vector<int>{15, 10, 5});
}
SECTION("quantity of velocity")
{
const quantity<isq::velocity[km / h], vector<int>> v = pos / dur;
CHECK(v.numerical_value() == vector<int>{15, 10, 5});
CHECK(v.numerical_value_ref_in(km / h) == vector<int>{15, 10, 5});
}
}
@ -259,15 +261,18 @@ TEST_CASE("vector quantity", "[la]")
{
const auto dur = 0.5 * isq::duration[h];
SECTION("derived_quantity_spec") { CHECK((pos / dur).numerical_value() == vector<double>{60, 40, 20}); }
SECTION("derived_quantity_spec")
{
CHECK((pos / dur).numerical_value_ref_in(km / h) == vector<double>{60, 40, 20});
}
SECTION("quantity_cast to velocity")
{
CHECK(quantity_cast<isq::velocity>(pos / dur).numerical_value() == vector<double>{60, 40, 20});
CHECK(quantity_cast<isq::velocity>(pos / dur).numerical_value_ref_in(km / h) == vector<double>{60, 40, 20});
}
SECTION("quantity of velocity")
{
const quantity<isq::velocity[km / h], vector<double>> v = pos / dur;
CHECK(v.numerical_value() == vector<double>{60, 40, 20});
CHECK(v.numerical_value_ref_in(km / h) == vector<double>{60, 40, 20});
}
}
}
@ -303,8 +308,9 @@ TEST_CASE("vector of quantities", "[la]")
SECTION("to scalar magnitude")
{
const vector<quantity<isq::velocity[km / h], int>> v = {2 * (km / h), 3 * (km / h), 6 * (km / h)};
const auto speed = get_magnitude(v).numerical_value() * isq::speed[v(0).unit]; // TODO can we do better here?
CHECK(speed.numerical_value() == 7);
const auto speed =
get_magnitude(v).numerical_value_ref_in(km / h) * isq::speed[v(0).unit]; // TODO can we do better here?
CHECK(speed.numerical_value_ref_in(km / h) == 7);
}
SECTION("multiply by scalar value")

View File

@ -90,12 +90,13 @@ TEST_CASE("numeric_limits functions", "[limits]")
{
SECTION("'epsilon' works as expected using default floating type")
{
REQUIRE(epsilon<double>(isq::length[m]).numerical_value() ==
REQUIRE(epsilon<double>(isq::length[m]).numerical_value_ref_in(m) ==
std::numeric_limits<decltype(1. * isq::length[m])::rep>::epsilon());
}
SECTION("'epsilon' works as expected using integers")
{
REQUIRE(epsilon<int>(isq::length[m]).numerical_value() ==
REQUIRE(epsilon<int>(isq::length[m]).numerical_value_ref_in(m) ==
std::numeric_limits<decltype(1 * isq::length[m])::rep>::epsilon());
}
}

View File

@ -241,17 +241,19 @@ static_assert(
// static member functions
////////////////////////////
static_assert(quantity_point<isq::height[m], mean_sea_level>::zero().quantity_from_origin().numerical_value() == 0);
static_assert(quantity_point<isq::height[m], mean_sea_level>::min().quantity_from_origin().numerical_value() ==
static_assert(quantity_point<isq::height[m], mean_sea_level>::zero().quantity_from_origin().numerical_value_ref_in(m) ==
0);
static_assert(quantity_point<isq::height[m], mean_sea_level>::min().quantity_from_origin().numerical_value_ref_in(m) ==
std::numeric_limits<double>::lowest());
static_assert(quantity_point<isq::height[m], mean_sea_level>::max().quantity_from_origin().numerical_value() ==
static_assert(quantity_point<isq::height[m], mean_sea_level>::max().quantity_from_origin().numerical_value_ref_in(m) ==
std::numeric_limits<double>::max());
static_assert(quantity_point<isq::height[m], ground_level, int>::zero().quantity_from_origin().numerical_value() == 0);
static_assert(quantity_point<isq::height[m], ground_level, int>::min().quantity_from_origin().numerical_value() ==
std::numeric_limits<int>::lowest());
static_assert(quantity_point<isq::height[m], ground_level, int>::max().quantity_from_origin().numerical_value() ==
std::numeric_limits<int>::max());
static_assert(
quantity_point<isq::height[m], ground_level, int>::zero().quantity_from_origin().numerical_value_ref_in(m) == 0);
static_assert(quantity_point<isq::height[m], ground_level, int>::min().quantity_from_origin().numerical_value_ref_in(
m) == std::numeric_limits<int>::lowest());
static_assert(quantity_point<isq::height[m], ground_level, int>::max().quantity_from_origin().numerical_value_ref_in(
m) == std::numeric_limits<int>::max());
//////////////////////////////
@ -576,15 +578,15 @@ static_assert(is_of_type<(ground_level + isq::height(short(42) * m)).point_for(m
// converting to a different unit
///////////////////////////////////
static_assert((mean_sea_level + 2. * km).in(km).quantity_from_origin().numerical_value() == 2.);
static_assert((mean_sea_level + 2. * km).in(m).quantity_from_origin().numerical_value() == 2000.);
static_assert((mean_sea_level + 2000. * m).in(km).quantity_from_origin().numerical_value() == 2.);
static_assert((ground_level + 2. * km).in(km).quantity_from_origin().numerical_value() == 2.);
static_assert((ground_level + 2. * km).in(m).quantity_from_origin().numerical_value() == 2000.);
static_assert((ground_level + 2000. * m).in(km).quantity_from_origin().numerical_value() == 2.);
static_assert((tower_peak + 2. * km).in(km).quantity_from_origin().numerical_value() == 2.);
static_assert((tower_peak + 2. * km).in(m).quantity_from_origin().numerical_value() == 2000.);
static_assert((tower_peak + 2000. * m).in(km).quantity_from_origin().numerical_value() == 2.);
static_assert((mean_sea_level + 2. * km).in(km).quantity_from_origin().numerical_value_ref_in(km) == 2.);
static_assert((mean_sea_level + 2. * km).in(m).quantity_from_origin().numerical_value_ref_in(m) == 2000.);
static_assert((mean_sea_level + 2000. * m).in(km).quantity_from_origin().numerical_value_ref_in(km) == 2.);
static_assert((ground_level + 2. * km).in(km).quantity_from_origin().numerical_value_ref_in(km) == 2.);
static_assert((ground_level + 2. * km).in(m).quantity_from_origin().numerical_value_ref_in(m) == 2000.);
static_assert((ground_level + 2000. * m).in(km).quantity_from_origin().numerical_value_ref_in(km) == 2.);
static_assert((tower_peak + 2. * km).in(km).quantity_from_origin().numerical_value_ref_in(km) == 2.);
static_assert((tower_peak + 2. * km).in(m).quantity_from_origin().numerical_value_ref_in(m) == 2000.);
static_assert((tower_peak + 2000. * m).in(km).quantity_from_origin().numerical_value_ref_in(km) == 2.);
#if MP_UNITS_COMP_GCC != 10 || MP_UNITS_COMP_GCC_MINOR > 2
template<template<auto, auto, typename> typename QP>
@ -657,14 +659,14 @@ static_assert([](auto v) {
////////////////////////
// same type
static_assert((mean_sea_level + 1 * m += 1 * m).quantity_from_origin().numerical_value() == 2);
static_assert((mean_sea_level + 2 * m -= 1 * m).quantity_from_origin().numerical_value() == 1);
static_assert((mean_sea_level + 1 * m += 1 * m).quantity_from_origin().numerical_value_ref_in(m) == 2);
static_assert((mean_sea_level + 2 * m -= 1 * m).quantity_from_origin().numerical_value_ref_in(m) == 1);
// different types
static_assert((mean_sea_level + 2.5 * m += 3 * m).quantity_from_origin().numerical_value() == 5.5);
static_assert((mean_sea_level + 123 * m += 1 * km).quantity_from_origin().numerical_value() == 1123);
static_assert((mean_sea_level + 5.5 * m -= 3 * m).quantity_from_origin().numerical_value() == 2.5);
static_assert((mean_sea_level + 1123 * m -= 1 * km).quantity_from_origin().numerical_value() == 123);
static_assert((mean_sea_level + 2.5 * m += 3 * m).quantity_from_origin().numerical_value_ref_in(m) == 5.5);
static_assert((mean_sea_level + 123 * m += 1 * km).quantity_from_origin().numerical_value_ref_in(m) == 1123);
static_assert((mean_sea_level + 5.5 * m -= 3 * m).quantity_from_origin().numerical_value_ref_in(m) == 2.5);
static_assert((mean_sea_level + 1123 * m -= 1 * km).quantity_from_origin().numerical_value_ref_in(m) == 123);
template<template<auto, auto, typename> typename QP>
@ -935,31 +937,32 @@ static_assert(is_of_type<(1 * m + tower_peak) - (1 * m + other_ground_level), qu
// check for integral types promotion
static_assert(
is_same_v<
decltype(((mean_sea_level + std::uint8_t(0) * m) + std::uint8_t(0) * m).quantity_from_origin().numerical_value()),
int&&>);
static_assert(
is_same_v<
decltype((std::uint8_t(0) * m + (mean_sea_level + std::uint8_t(0) * m)).quantity_from_origin().numerical_value()),
int&&>);
static_assert(
is_same_v<
decltype(((mean_sea_level + std::uint8_t(0) * m) - std::uint8_t(0) * m).quantity_from_origin().numerical_value()),
int&&>);
static_assert(is_same_v<decltype(((mean_sea_level + std::uint8_t(0) * m) + std::uint8_t(0) * m)
.quantity_from_origin()
.numerical_value_ref_in(m)),
int&&>);
static_assert(is_same_v<decltype((std::uint8_t(0) * m + (mean_sea_level + std::uint8_t(0) * m))
.quantity_from_origin()
.numerical_value_ref_in(m)),
int&&>);
static_assert(is_same_v<decltype(((mean_sea_level + std::uint8_t(0) * m) - std::uint8_t(0) * m)
.quantity_from_origin()
.numerical_value_ref_in(m)),
int&&>);
static_assert(is_same_v<decltype(((mean_sea_level + std::uint8_t(0) * m) - (mean_sea_level + std::uint8_t(0) * m))
.numerical_value()),
.numerical_value_ref_in(m)),
int&&>);
static_assert(
((mean_sea_level + std::uint8_t(128) * m) + std::uint8_t(128) * m).quantity_from_origin().numerical_value() ==
((mean_sea_level + std::uint8_t(128) * m) + std::uint8_t(128) * m).quantity_from_origin().numerical_value_ref_in(m) ==
std::uint8_t(128) + std::uint8_t(128));
static_assert(
(std::uint8_t(128) * m + (mean_sea_level + std::uint8_t(128) * m)).quantity_from_origin().numerical_value() ==
(std::uint8_t(128) * m + (mean_sea_level + std::uint8_t(128) * m)).quantity_from_origin().numerical_value_ref_in(m) ==
std::uint8_t(128) + std::uint8_t(128));
static_assert(((mean_sea_level + std::uint8_t(0) * m) - std::uint8_t(1) * m).quantity_from_origin().numerical_value() ==
std::uint8_t(0) - std::uint8_t(1));
static_assert(((mean_sea_level + std::uint8_t(0) * m) - (mean_sea_level + std::uint8_t(1) * m)).numerical_value() ==
std::uint8_t(0) - std::uint8_t(1));
static_assert(
((mean_sea_level + std::uint8_t(0) * m) - std::uint8_t(1) * m).quantity_from_origin().numerical_value_ref_in(m) ==
std::uint8_t(0) - std::uint8_t(1));
static_assert(((mean_sea_level + std::uint8_t(0) * m) - (mean_sea_level + std::uint8_t(1) * m))
.numerical_value_ref_in(m) == std::uint8_t(0) - std::uint8_t(1));
// different representation types
static_assert(is_of_type<(mean_sea_level + 1. * m) + 1 * m, quantity_point<si::metre, mean_sea_level, double>>);
@ -1013,39 +1016,39 @@ static_assert(is_of_type<(mean_sea_level + 1 * km) - (mean_sea_level + 1. * m),
static_assert(is_of_type<(mean_sea_level + 1. * km) - (mean_sea_level + 1. * m), quantity<si::metre, double>>);
static_assert(((mean_sea_level + 1 * m) + 1 * m).quantity_from_origin().numerical_value() == 2);
static_assert((1 * m + (mean_sea_level + 1 * m)).quantity_from_origin().numerical_value() == 2);
static_assert(((mean_sea_level + 1 * m) + 1 * km).quantity_from_origin().numerical_value() == 1001);
static_assert((1 * m + (mean_sea_level + 1 * km)).quantity_from_origin().numerical_value() == 1001);
static_assert(((mean_sea_level + 1 * km) + 1 * m).quantity_from_origin().numerical_value() == 1001);
static_assert((1 * km + (mean_sea_level + 1 * m)).quantity_from_origin().numerical_value() == 1001);
static_assert(((mean_sea_level + 2 * m) - 1 * m).quantity_from_origin().numerical_value() == 1);
static_assert(((mean_sea_level + 1 * km) - 1 * m).quantity_from_origin().numerical_value() == 999);
static_assert(((mean_sea_level + 1 * m) + 1 * m).quantity_from_origin().numerical_value_ref_in(m) == 2);
static_assert((1 * m + (mean_sea_level + 1 * m)).quantity_from_origin().numerical_value_ref_in(m) == 2);
static_assert(((mean_sea_level + 1 * m) + 1 * km).quantity_from_origin().numerical_value_ref_in(m) == 1001);
static_assert((1 * m + (mean_sea_level + 1 * km)).quantity_from_origin().numerical_value_ref_in(m) == 1001);
static_assert(((mean_sea_level + 1 * km) + 1 * m).quantity_from_origin().numerical_value_ref_in(m) == 1001);
static_assert((1 * km + (mean_sea_level + 1 * m)).quantity_from_origin().numerical_value_ref_in(m) == 1001);
static_assert(((mean_sea_level + 2 * m) - 1 * m).quantity_from_origin().numerical_value_ref_in(m) == 1);
static_assert(((mean_sea_level + 1 * km) - 1 * m).quantity_from_origin().numerical_value_ref_in(m) == 999);
static_assert(((mean_sea_level + 1.5 * m) + 1 * m).quantity_from_origin().numerical_value() == 2.5);
static_assert((1.5 * m + (mean_sea_level + 1 * m)).quantity_from_origin().numerical_value() == 2.5);
static_assert(((mean_sea_level + 1.5 * m) + 1 * km).quantity_from_origin().numerical_value() == 1001.5);
static_assert((1.5 * m + (mean_sea_level + 1 * km)).quantity_from_origin().numerical_value() == 1001.5);
static_assert(((mean_sea_level + 1.5 * km) + 1 * m).quantity_from_origin().numerical_value() == 1501);
static_assert((1.5 * km + (mean_sea_level + 1 * m)).quantity_from_origin().numerical_value() == 1501);
static_assert(((mean_sea_level + 2.5 * m) - 1 * m).quantity_from_origin().numerical_value() == 1.5);
static_assert(((mean_sea_level + 1.5 * km) - 1 * m).quantity_from_origin().numerical_value() == 1499);
static_assert(((mean_sea_level + 1.5 * m) + 1 * m).quantity_from_origin().numerical_value_ref_in(m) == 2.5);
static_assert((1.5 * m + (mean_sea_level + 1 * m)).quantity_from_origin().numerical_value_ref_in(m) == 2.5);
static_assert(((mean_sea_level + 1.5 * m) + 1 * km).quantity_from_origin().numerical_value_ref_in(m) == 1001.5);
static_assert((1.5 * m + (mean_sea_level + 1 * km)).quantity_from_origin().numerical_value_ref_in(m) == 1001.5);
static_assert(((mean_sea_level + 1.5 * km) + 1 * m).quantity_from_origin().numerical_value_ref_in(m) == 1501);
static_assert((1.5 * km + (mean_sea_level + 1 * m)).quantity_from_origin().numerical_value_ref_in(m) == 1501);
static_assert(((mean_sea_level + 2.5 * m) - 1 * m).quantity_from_origin().numerical_value_ref_in(m) == 1.5);
static_assert(((mean_sea_level + 1.5 * km) - 1 * m).quantity_from_origin().numerical_value_ref_in(m) == 1499);
static_assert(((mean_sea_level + 1 * m) + 1.5 * m).quantity_from_origin().numerical_value() == 2.5);
static_assert((1 * m + (mean_sea_level + 1.5 * m)).quantity_from_origin().numerical_value() == 2.5);
static_assert(((mean_sea_level + 1 * m) + 1.5 * km).quantity_from_origin().numerical_value() == 1501);
static_assert((1 * m + (mean_sea_level + 1.5 * km)).quantity_from_origin().numerical_value() == 1501);
static_assert(((mean_sea_level + 1 * km) + 1.5 * m).quantity_from_origin().numerical_value() == 1001.5);
static_assert((1 * km + (mean_sea_level + 1.5 * m)).quantity_from_origin().numerical_value() == 1001.5);
static_assert(((mean_sea_level + 2 * m) - 1.5 * m).quantity_from_origin().numerical_value() == 0.5);
static_assert(((mean_sea_level + 1 * km) - 1.5 * m).quantity_from_origin().numerical_value() == 998.5);
static_assert(((mean_sea_level + 1 * m) + 1.5 * m).quantity_from_origin().numerical_value_ref_in(m) == 2.5);
static_assert((1 * m + (mean_sea_level + 1.5 * m)).quantity_from_origin().numerical_value_ref_in(m) == 2.5);
static_assert(((mean_sea_level + 1 * m) + 1.5 * km).quantity_from_origin().numerical_value_ref_in(m) == 1501);
static_assert((1 * m + (mean_sea_level + 1.5 * km)).quantity_from_origin().numerical_value_ref_in(m) == 1501);
static_assert(((mean_sea_level + 1 * km) + 1.5 * m).quantity_from_origin().numerical_value_ref_in(m) == 1001.5);
static_assert((1 * km + (mean_sea_level + 1.5 * m)).quantity_from_origin().numerical_value_ref_in(m) == 1001.5);
static_assert(((mean_sea_level + 2 * m) - 1.5 * m).quantity_from_origin().numerical_value_ref_in(m) == 0.5);
static_assert(((mean_sea_level + 1 * km) - 1.5 * m).quantity_from_origin().numerical_value_ref_in(m) == 998.5);
static_assert(((mean_sea_level + 2 * m) - (mean_sea_level + 1 * m)).numerical_value() == 1);
static_assert(((mean_sea_level + 1 * km) - (mean_sea_level + 1 * m)).numerical_value() == 999);
static_assert(((mean_sea_level + 2.5 * m) - (mean_sea_level + 1 * m)).numerical_value() == 1.5);
static_assert(((mean_sea_level + 1.5 * km) - (mean_sea_level + 1 * m)).numerical_value() == 1499);
static_assert(((mean_sea_level + 2 * m) - (mean_sea_level + 1.5 * m)).numerical_value() == 0.5);
static_assert(((mean_sea_level + 1 * km) - (mean_sea_level + 1.5 * m)).numerical_value() == 998.5);
static_assert(((mean_sea_level + 2 * m) - (mean_sea_level + 1 * m)).numerical_value_ref_in(m) == 1);
static_assert(((mean_sea_level + 1 * km) - (mean_sea_level + 1 * m)).numerical_value_ref_in(m) == 999);
static_assert(((mean_sea_level + 2.5 * m) - (mean_sea_level + 1 * m)).numerical_value_ref_in(m) == 1.5);
static_assert(((mean_sea_level + 1.5 * km) - (mean_sea_level + 1 * m)).numerical_value_ref_in(m) == 1499);
static_assert(((mean_sea_level + 2 * m) - (mean_sea_level + 1.5 * m)).numerical_value_ref_in(m) == 0.5);
static_assert(((mean_sea_level + 1 * km) - (mean_sea_level + 1.5 * m)).numerical_value_ref_in(m) == 998.5);
static_assert((mean_sea_level + 42 * m) - (ground_level + 42 * m) == -42 * m);
static_assert((ground_level + 42 * m) - (mean_sea_level + 42 * m) == 42 * m);

View File

@ -112,14 +112,15 @@ static_assert(is_same_v<quantity<isq::length[m], int>::rep, int>);
// static member functions
////////////////////////////
static_assert(quantity<isq::length[m], int>::zero().numerical_value() == 0);
static_assert(quantity<isq::length[m], int>::one().numerical_value() == 1);
static_assert(quantity<isq::length[m], int>::min().numerical_value() == std::numeric_limits<int>::lowest());
static_assert(quantity<isq::length[m], int>::max().numerical_value() == std::numeric_limits<int>::max());
static_assert(quantity<isq::length[m], double>::zero().numerical_value() == 0.0);
static_assert(quantity<isq::length[m], double>::one().numerical_value() == 1.0);
static_assert(quantity<isq::length[m], double>::min().numerical_value() == std::numeric_limits<double>::lowest());
static_assert(quantity<isq::length[m], double>::max().numerical_value() == std::numeric_limits<double>::max());
static_assert(quantity<isq::length[m], int>::zero().numerical_value_ref_in(m) == 0);
static_assert(quantity<isq::length[m], int>::one().numerical_value_ref_in(m) == 1);
static_assert(quantity<isq::length[m], int>::min().numerical_value_ref_in(m) == std::numeric_limits<int>::lowest());
static_assert(quantity<isq::length[m], int>::max().numerical_value_ref_in(m) == std::numeric_limits<int>::max());
static_assert(quantity<isq::length[m], double>::zero().numerical_value_ref_in(m) == 0.0);
static_assert(quantity<isq::length[m], double>::one().numerical_value_ref_in(m) == 1.0);
static_assert(quantity<isq::length[m], double>::min().numerical_value_ref_in(m) ==
std::numeric_limits<double>::lowest());
static_assert(quantity<isq::length[m], double>::max().numerical_value_ref_in(m) == std::numeric_limits<double>::max());
//////////////////////////////
@ -190,10 +191,10 @@ static_assert(std::convertible_to<quantity<isq::length[m], int>, quantity<isq::l
// obtaining a number
///////////////////////
static_assert(quantity<isq::length[m], int>(123 * m).numerical_value() == 123);
static_assert(quantity<isq::length[m], int>(2 * km).numerical_value() == 2000);
static_assert(quantity<isq::length[km], int>(2 * km).numerical_value() == 2);
static_assert(quantity<isq::length[km]>(1500 * m).numerical_value() == 1.5);
static_assert(quantity<isq::length[m], int>(123 * m).numerical_value_ref_in(m) == 123);
static_assert(quantity<isq::length[m], int>(2 * km).numerical_value_ref_in(m) == 2000);
static_assert(quantity<isq::length[km], int>(2 * km).numerical_value_ref_in(km) == 2);
static_assert(quantity<isq::length[km]>(1500 * m).numerical_value_ref_in(km) == 1.5);
///////////////////////////////////
@ -204,11 +205,11 @@ static_assert(is_of_type<(2. * km).in(m), quantity<si::metre>>);
static_assert(is_of_type<isq::length(2. * km).in(m), quantity<isq::length[m]>>);
static_assert(is_of_type<isq::height(2. * km).in(m), quantity<isq::height[m]>>);
static_assert(quantity<isq::length[km]>(2. * km).in(km).numerical_value() == 2.);
static_assert(quantity<isq::length[km]>(2. * km).in(m).numerical_value() == 2000.);
static_assert(quantity<isq::length[m]>(2000. * m).in(km).numerical_value() == 2.);
static_assert(quantity<isq::length[km], int>(2 * km).in(km).numerical_value() == 2);
static_assert(quantity<isq::length[km], int>(2 * km).in(m).numerical_value() == 2000);
static_assert(quantity<isq::length[km]>(2. * km).in(km).numerical_value_ref_in(km) == 2.);
static_assert(quantity<isq::length[km]>(2. * km).in(m).numerical_value_ref_in(m) == 2000.);
static_assert(quantity<isq::length[m]>(2000. * m).in(km).numerical_value_ref_in(km) == 2.);
static_assert(quantity<isq::length[km], int>(2 * km).in(km).numerical_value_ref_in(km) == 2);
static_assert(quantity<isq::length[km], int>(2 * km).in(m).numerical_value_ref_in(m) == 2000);
#if MP_UNITS_COMP_GCC != 10 || MP_UNITS_COMP_GCC_MINOR > 2
template<template<auto, typename> typename Q>
@ -308,28 +309,28 @@ static_assert([] {
auto l1(1 * m), l2(2 * m);
return l2 = l1;
}()
.numerical_value() == 1);
.numerical_value_ref_in(m) == 1);
static_assert([] {
const auto l1(1 * m);
auto l2(2 * m);
return l2 = l1;
}()
.numerical_value() == 1);
.numerical_value_ref_in(m) == 1);
static_assert([]() {
auto l1(1 * m), l2(2 * m);
return l2 = std::move(l1);
}()
.numerical_value() == 1);
.numerical_value_ref_in(m) == 1);
////////////////////
// unary operators
////////////////////
static_assert((+123 * m).numerical_value() == 123);
static_assert((-123 * m).numerical_value() == -123);
static_assert((+(-123 * m)).numerical_value() == -123);
static_assert((-(-123 * m)).numerical_value() == 123);
static_assert((+123 * m).numerical_value_ref_in(m) == 123);
static_assert((-123 * m).numerical_value_ref_in(m) == -123);
static_assert((+(-123 * m)).numerical_value_ref_in(m) == -123);
static_assert((-(-123 * m)).numerical_value_ref_in(m) == 123);
static_assert([](auto v) {
auto vv = v++;
@ -348,7 +349,7 @@ static_assert([](auto v) {
return std::pair(v, vv);
}(123 * m) == std::pair(122 * m, 122 * m));
static_assert(is_same_v<decltype((+(short{0} * m)).numerical_value()), int&&>);
static_assert(is_same_v<decltype((+(short{0} * m)).numerical_value_ref_in(m)), int&&>);
////////////////////////
@ -356,29 +357,30 @@ static_assert(is_same_v<decltype((+(short{0} * m)).numerical_value()), int&&>);
////////////////////////
// same type
static_assert((1 * m += 1 * m).numerical_value() == 2);
static_assert((2 * m -= 1 * m).numerical_value() == 1);
static_assert((1 * m *= 2).numerical_value() == 2);
static_assert((2 * m /= 2).numerical_value() == 1);
static_assert((1 * m *= 2 * one).numerical_value() == 2);
static_assert((2 * m /= 2 * one).numerical_value() == 1);
static_assert((7 * m %= 2 * m).numerical_value() == 1);
static_assert((1 * m += 1 * m).numerical_value_ref_in(m) == 2);
static_assert((2 * m -= 1 * m).numerical_value_ref_in(m) == 1);
static_assert((1 * m *= 2).numerical_value_ref_in(m) == 2);
static_assert((2 * m /= 2).numerical_value_ref_in(m) == 1);
static_assert((1 * m *= 2 * one).numerical_value_ref_in(m) == 2);
static_assert((2 * m /= 2 * one).numerical_value_ref_in(m) == 1);
static_assert((7 * m %= 2 * m).numerical_value_ref_in(m) == 1);
// different types
static_assert((2.5 * m += 3 * m).numerical_value() == 5.5);
static_assert((123 * m += 1 * km).numerical_value() == 1123);
static_assert((5.5 * m -= 3 * m).numerical_value() == 2.5);
static_assert((1123 * m -= 1 * km).numerical_value() == 123);
static_assert((2.5 * m *= 3).numerical_value() == 7.5);
static_assert((7.5 * m /= 3).numerical_value() == 2.5);
static_assert((2.5 * m *= 3 * one).numerical_value() == 7.5);
static_assert((7.5 * m /= 3 * one).numerical_value() == 2.5);
static_assert((3500 * m %= 1 * km).numerical_value() == 500);
static_assert((2.5 * m += 3 * m).numerical_value_ref_in(m) == 5.5);
static_assert((123 * m += 1 * km).numerical_value_ref_in(m) == 1123);
static_assert((5.5 * m -= 3 * m).numerical_value_ref_in(m) == 2.5);
static_assert((1123 * m -= 1 * km).numerical_value_ref_in(m) == 123);
static_assert((2.5 * m *= 3).numerical_value_ref_in(m) == 7.5);
static_assert((7.5 * m /= 3).numerical_value_ref_in(m) == 2.5);
static_assert((2.5 * m *= 3 * one).numerical_value_ref_in(m) == 7.5);
static_assert((7.5 * m /= 3 * one).numerical_value_ref_in(m) == 2.5);
static_assert((3500 * m %= 1 * km).numerical_value_ref_in(m) == 500);
// static_assert((std::uint8_t(255) * m %= 256 * m).numerical_value() != [] { std::uint8_t ui(255); return ui %= 256;
// static_assert((std::uint8_t(255) * m %= 256 * m).numerical_value_ref_in(m) != [] { std::uint8_t ui(255); return ui %=
// 256;
// }()); // UB
// TODO: Fix
static_assert((std::uint8_t(255) * m %= 257 * m).numerical_value() != [] {
static_assert((std::uint8_t(255) * m %= 257 * m).numerical_value_ref_in(m) != [] {
std::uint8_t ui(255);
return ui %= 257;
}());
@ -388,10 +390,10 @@ static_assert((std::uint8_t(255) * m %= 257 * m).numerical_value() != [] {
#ifndef MP_UNITS_COMP_MSVC
// next two lines trigger conversions warnings
// (warning disabled in CMake for this file)
static_assert((22 * m *= 33.33).numerical_value() == 733);
static_assert((22 * m /= 3.33).numerical_value() == 6);
static_assert((22 * m *= 33.33 * one).numerical_value() == 733);
static_assert((22 * m /= 3.33 * one).numerical_value() == 6);
static_assert((22 * m *= 33.33).numerical_value_ref_in(m) == 733);
static_assert((22 * m /= 3.33).numerical_value_ref_in(m) == 6);
static_assert((22 * m *= 33.33 * one).numerical_value_ref_in(m) == 733);
static_assert((22 * m /= 3.33 * one).numerical_value_ref_in(m) == 6);
#endif
template<template<auto, typename> typename Q>
@ -516,13 +518,14 @@ static_assert(is_of_type<1 * km % (300 * m), quantity<si::metre, int>>);
static_assert(is_of_type<4 * one % (2 * one), quantity<one, int>>);
// check for integral types promotion
static_assert(is_same_v<decltype((std::uint8_t(0) * m + std::uint8_t(0) * m).numerical_value()), int&&>);
static_assert(is_same_v<decltype((std::uint8_t(0) * m - std::uint8_t(0) * m).numerical_value()), int&&>);
static_assert((std::uint8_t(128) * m + std::uint8_t(128) * m).numerical_value() ==
static_assert(is_same_v<decltype((std::uint8_t(0) * m + std::uint8_t(0) * m).numerical_value_ref_in(m)), int&&>);
static_assert(is_same_v<decltype((std::uint8_t(0) * m - std::uint8_t(0) * m).numerical_value_ref_in(m)), int&&>);
static_assert((std::uint8_t(128) * m + std::uint8_t(128) * m).numerical_value_ref_in(m) ==
std::uint8_t(128) + std::uint8_t(128));
static_assert((std::uint8_t(0) * m - std::uint8_t(1) * m).numerical_value() == std::uint8_t(0) - std::uint8_t(1));
static_assert((std::uint8_t(0) * m - std::uint8_t(1) * m).numerical_value_ref_in(m) ==
std::uint8_t(0) - std::uint8_t(1));
static_assert(is_same_v<decltype(((std::uint8_t(0) * m) % (std::uint8_t(0) * m)).numerical_value()),
static_assert(is_same_v<decltype(((std::uint8_t(0) * m) % (std::uint8_t(0) * m)).numerical_value_ref_in(m)),
decltype(std::uint8_t(0) % std::uint8_t(0))&&>);
// different representation types
@ -596,67 +599,67 @@ static_assert(is_of_type<1 * m / (1 * s), quantity<derived_unit<struct si::metre
static_assert(is_of_type<1 * m / (1 * min), quantity<derived_unit<struct si::metre, per<struct si::minute>>{}, int>>);
static_assert(is_of_type<1 * min / (1 * m), quantity<derived_unit<struct si::minute, per<struct si::metre>>{}, int>>);
static_assert((1 * m + 1 * m).numerical_value() == 2);
static_assert((1 * m + 1 * km).numerical_value() == 1001);
static_assert((1 * km + 1 * m).numerical_value() == 1001);
static_assert((2 * m - 1 * m).numerical_value() == 1);
static_assert((1 * km - 1 * m).numerical_value() == 999);
static_assert((2 * m * 2).numerical_value() == 4);
static_assert((2 * m * (2 * one)).numerical_value() == 4);
static_assert((2 * m * (2 * percent)).numerical_value() == 4);
static_assert((3 * 3 * m).numerical_value() == 9);
static_assert(((3 * one) * (3 * m)).numerical_value() == 9);
static_assert(((3 * percent) * (3 * m)).numerical_value() == 9);
static_assert((4 * m / 2).numerical_value() == 2);
static_assert((4 * m / (2 * one)).numerical_value() == 2);
static_assert((4 * m / (2 * percent)).numerical_value() == 2);
static_assert((4 * km / (2 * m)).numerical_value() == 2);
static_assert((4000 * m / (2 * m)).numerical_value() == 2000);
static_assert((1 * m + 1 * m).numerical_value_ref_in(m) == 2);
static_assert((1 * m + 1 * km).numerical_value_ref_in(m) == 1001);
static_assert((1 * km + 1 * m).numerical_value_ref_in(m) == 1001);
static_assert((2 * m - 1 * m).numerical_value_ref_in(m) == 1);
static_assert((1 * km - 1 * m).numerical_value_ref_in(m) == 999);
static_assert((2 * m * 2).numerical_value_ref_in(m) == 4);
static_assert((2 * m * (2 * one)).numerical_value_ref_in(m) == 4);
static_assert((2 * m * (2 * percent)).numerical_value_ref_in(m * percent) == 4);
static_assert((3 * 3 * m).numerical_value_ref_in(m) == 9);
static_assert(((3 * one) * (3 * m)).numerical_value_ref_in(m) == 9);
static_assert(((3 * percent) * (3 * m)).numerical_value_ref_in(m * percent) == 9);
static_assert((4 * m / 2).numerical_value_ref_in(m) == 2);
static_assert((4 * m / (2 * one)).numerical_value_ref_in(m) == 2);
static_assert((4 * m / (2 * percent)).numerical_value_ref_in(m / percent) == 2);
static_assert((4 * km / (2 * m)).numerical_value_ref_in(km / m) == 2);
static_assert((4000 * m / (2 * m)).numerical_value_ref_in(one) == 2000);
static_assert((1.5 * m + 1 * m).numerical_value() == 2.5);
static_assert((1.5 * m + 1 * km).numerical_value() == 1001.5);
static_assert((1.5 * km + 1 * m).numerical_value() == 1501);
static_assert((2.5 * m - 1 * m).numerical_value() == 1.5);
static_assert((1.5 * km - 1 * m).numerical_value() == 1499);
static_assert((2.5 * m * 2).numerical_value() == 5);
static_assert((2.5 * m * (2 * one)).numerical_value() == 5);
static_assert((2.5 * m * (2 * percent)).numerical_value() == 5);
static_assert((2.5L * (2 * m)).numerical_value() == 5);
static_assert((2.5L * one * (2 * m)).numerical_value() == 5);
static_assert((2.5L * percent * (2 * m)).numerical_value() == 5);
static_assert((5. * m / 2).numerical_value() == 2.5);
static_assert((5. * m / (2 * one)).numerical_value() == 2.5);
static_assert((5. * m / (2 * percent)).numerical_value() == 2.5);
static_assert((5. * km / (2 * m)).numerical_value() == 2.5);
static_assert((5000. * m / (2 * m)).numerical_value() == 2500);
static_assert((1.5 * m + 1 * m).numerical_value_ref_in(m) == 2.5);
static_assert((1.5 * m + 1 * km).numerical_value_ref_in(m) == 1001.5);
static_assert((1.5 * km + 1 * m).numerical_value_ref_in(m) == 1501);
static_assert((2.5 * m - 1 * m).numerical_value_ref_in(m) == 1.5);
static_assert((1.5 * km - 1 * m).numerical_value_ref_in(m) == 1499);
static_assert((2.5 * m * 2).numerical_value_ref_in(m) == 5);
static_assert((2.5 * m * (2 * one)).numerical_value_ref_in(m) == 5);
static_assert((2.5 * m * (2 * percent)).numerical_value_ref_in(m * percent) == 5);
static_assert((2.5L * (2 * m)).numerical_value_ref_in(m) == 5);
static_assert((2.5L * one * (2 * m)).numerical_value_ref_in(m) == 5);
static_assert((2.5L * percent * (2 * m)).numerical_value_ref_in(m * percent) == 5);
static_assert((5. * m / 2).numerical_value_ref_in(m) == 2.5);
static_assert((5. * m / (2 * one)).numerical_value_ref_in(m) == 2.5);
static_assert((5. * m / (2 * percent)).numerical_value_ref_in(m / percent) == 2.5);
static_assert((5. * km / (2 * m)).numerical_value_ref_in(km / m) == 2.5);
static_assert((5000. * m / (2 * m)).numerical_value_ref_in(one) == 2500);
static_assert((1 * m + 1.5 * m).numerical_value() == 2.5);
static_assert((1 * m + 1.5 * km).numerical_value() == 1501);
static_assert((1 * km + 1.5 * m).numerical_value() == 1001.5);
static_assert((2 * m - 1.5 * m).numerical_value() == 0.5);
static_assert((1 * km - 1.5 * m).numerical_value() == 998.5);
static_assert((2 * m * 2.5L).numerical_value() == 5);
static_assert((2 * m * (2.5L * one)).numerical_value() == 5);
static_assert((2 * m * (2.5L * percent)).numerical_value() == 5);
static_assert((2 * 2.5 * m).numerical_value() == 5);
static_assert((2 * one * (2.5 * m)).numerical_value() == 5);
static_assert((2 * percent * (2.5 * m)).numerical_value() == 5);
static_assert((5 * m / 2.5L).numerical_value() == 2);
static_assert((5 * m / (2.5L * one)).numerical_value() == 2);
static_assert((5 * m / (2.5L * percent)).numerical_value() == 2);
static_assert((5 * km / (2.5 * m)).numerical_value() == 2);
static_assert((5000 * m / (2.5 * m)).numerical_value() == 2000);
static_assert((1 * m + 1.5 * m).numerical_value_ref_in(m) == 2.5);
static_assert((1 * m + 1.5 * km).numerical_value_ref_in(m) == 1501);
static_assert((1 * km + 1.5 * m).numerical_value_ref_in(m) == 1001.5);
static_assert((2 * m - 1.5 * m).numerical_value_ref_in(m) == 0.5);
static_assert((1 * km - 1.5 * m).numerical_value_ref_in(m) == 998.5);
static_assert((2 * m * 2.5L).numerical_value_ref_in(m) == 5);
static_assert((2 * m * (2.5L * one)).numerical_value_ref_in(m) == 5);
static_assert((2 * m * (2.5L * percent)).numerical_value_ref_in(m * percent) == 5);
static_assert((2 * 2.5 * m).numerical_value_ref_in(m) == 5);
static_assert((2 * one * (2.5 * m)).numerical_value_ref_in(m) == 5);
static_assert((2 * percent * (2.5 * m)).numerical_value_ref_in(m * percent) == 5);
static_assert((5 * m / 2.5L).numerical_value_ref_in(m) == 2);
static_assert((5 * m / (2.5L * one)).numerical_value_ref_in(m) == 2);
static_assert((5 * m / (2.5L * percent)).numerical_value_ref_in(m / percent) == 2);
static_assert((5 * km / (2.5 * m)).numerical_value_ref_in(km / m) == 2);
static_assert((5000 * m / (2.5 * m)).numerical_value_ref_in(one) == 2000);
static_assert((7 * m % (2 * m)).numerical_value() == 1);
static_assert((7 * km % (2000 * m)).numerical_value() == 1000);
static_assert((1300 * m % (1 * km)).numerical_value() == 300);
static_assert((7 * one % (2 * one)).numerical_value() == 1);
static_assert((7 * m % (2 * m)).numerical_value_ref_in(m) == 1);
static_assert((7 * km % (2000 * m)).numerical_value_ref_in(m) == 1000);
static_assert((1300 * m % (1 * km)).numerical_value_ref_in(m) == 300);
static_assert((7 * one % (2 * one)).numerical_value_ref_in(one) == 1);
static_assert((10 * m2 * (10 * m2)) / (50 * m2) == 2 * m2);
static_assert((10 * km / (5 * m)).numerical_value() == 2);
static_assert((10 * km / (5 * m)).in(one).numerical_value() == 2000);
static_assert((10 * s * (2 * kHz)).numerical_value() == 20);
static_assert((10 * km / (5 * m)).numerical_value_ref_in(km / m) == 2);
static_assert((10 * km / (5 * m)).numerical_value_in(one) == 2000);
static_assert((10 * s * (2 * kHz)).numerical_value_ref_in(s * kHz) == 20);
// commutativity and associativity
static_assert(10 * isq::length[si::metre] / (2 * isq::time[s]) + 5 * isq::speed[m / s] == 10 * isq::speed[m / s]);
@ -740,13 +743,15 @@ static_assert(is_same_v<decltype(0.0 * one - 0 * one), decltype(0.0 * one)>);
static_assert(1 * one - 30 * percent == (100 - 30) * percent);
static_assert(1 * one + 30 * percent == (100 + 30) * percent);
static_assert(is_same_v<decltype((std::uint8_t(0) * one + std::uint8_t(0) * one).numerical_value()), int&&>);
static_assert(is_same_v<decltype((std::uint8_t(0) * one - std::uint8_t(0) * one).numerical_value()), int&&>);
static_assert((std::uint8_t(128) * one + std::uint8_t(128) * one).numerical_value() ==
std::uint8_t(128) + std::uint8_t(128));
static_assert((std::uint8_t(0) * one - std::uint8_t(1) * one).numerical_value() == std::uint8_t(0) - std::uint8_t(1));
static_assert(is_same_v<decltype((std::uint8_t(0) * one + std::uint8_t(0) * one).numerical_value_ref_in(one)), int&&>);
static_assert(is_same_v<decltype((std::uint8_t(0) * one - std::uint8_t(0) * one).numerical_value_ref_in(one)), int&&>);
static_assert((std::uint8_t(128) * one + std::uint8_t(128) * one).numerical_value_ref_in(one) ==
static_assert(is_same_v<decltype((std::uint8_t(0) * one % (std::uint8_t(0) * one)).numerical_value()),
std::uint8_t(128) + std::uint8_t(128));
static_assert((std::uint8_t(0) * one - std::uint8_t(1) * one).numerical_value_ref_in(one) ==
std::uint8_t(0) - std::uint8_t(1));
static_assert(is_same_v<decltype((std::uint8_t(0) * one % (std::uint8_t(0) * one)).numerical_value_ref_in(one)),
decltype(std::uint8_t(0) % std::uint8_t(0))&&>);
static_assert(2 * one * (1 * m) == 2 * m);
@ -880,20 +885,20 @@ static_assert(!(123 * km >= 321'000 * m));
static_assert(is_of_type<10 * km / (5 * km), quantity<one, int>>);
static_assert((50. * m / (100. * m)).in(percent).numerical_value() == 50);
static_assert((50. * m / (100. * m)).numerical_value_in(percent) == 50);
static_assert(50. * m / (100. * m) == 50 * percent);
static_assert((50. * percent).in(one).numerical_value() == 0.5);
static_assert((50. * percent).numerical_value_in(one) == 0.5);
//////////////////
// value_cast
//////////////////
static_assert(value_cast<m>(2 * km).numerical_value() == 2000);
static_assert(value_cast<km>(2000 * m).numerical_value() == 2);
static_assert(value_cast<int>(1.23 * m).numerical_value() == 1);
static_assert(value_cast<km / h>(2000.0 * m / (3600.0 * s)).numerical_value() == 2);
static_assert(value_cast<m>(2 * km).numerical_value_ref_in(m) == 2000);
static_assert(value_cast<km>(2000 * m).numerical_value_ref_in(km) == 2);
static_assert(value_cast<int>(1.23 * m).numerical_value_ref_in(m) == 1);
static_assert(value_cast<km / h>(2000.0 * m / (3600.0 * s)).numerical_value_ref_in(km / h) == 2);
//////////////////
// quantity_cast