feat: dimensionless quantities with a unit one are not special anymore

This commit is contained in:
Mateusz Pusz
2023-07-10 16:53:49 +02:00
parent 9370c61022
commit 5d73cd0730
7 changed files with 27 additions and 224 deletions

View File

@@ -124,7 +124,7 @@ constexpr state<Q1, Q2, Q3> state_update(const state<Q1, Q2, Q3>& predicted, QM
template<mp_units::Quantity Q, mp_units::QuantityOf<mp_units::dimensionless> K>
constexpr Q covariance_update(Q uncertainty, K gain)
{
return (1 - gain) * uncertainty;
return (1 * mp_units::one - gain) * uncertainty;
}
// state extrapolation

View File

@@ -121,7 +121,7 @@ int main()
const QuantityOf<isq::mass_change_rate> auto input_flow_rate = measured_mass / fill_time;
const QuantityOf<isq::speed> auto float_rise_rate = fill_level / fill_time;
const QuantityOf<isq::time> auto fill_time_left = (height / fill_level - 1) * fill_time;
const QuantityOf<isq::time> auto fill_time_left = (height / fill_level - 1 * one) * fill_time;
const auto fill_ratio = fill_level / height;

View File

@@ -147,13 +147,6 @@ public:
{
}
template<typename Value>
requires(dimension == dimension_one) &&
(unit == ::mp_units::one) && detail::RepSafeConstructibleFrom<rep, Value&&, unit>
constexpr explicit(!std::convertible_to<Value, Rep>) quantity(Value&& v) : number_(std::forward<Value>(v))
{
}
quantity& operator=(const quantity&) = default;
quantity& operator=(quantity&&) = default;
@@ -433,65 +426,6 @@ template<auto R1, typename Rep1, auto R2, typename Rep2>
return ct(lhs).number() <=> ct(rhs).number();
}
// binary operators on dimensionless quantities
template<auto R, typename Rep, typename Value>
requires(!Quantity<Value>) && (quantity<R, Rep>::dimension == dimension_one) &&
detail::InvokeResultOf<get_quantity_spec(R).character, std::plus<>, Rep, Value>
[[nodiscard]] constexpr Quantity auto operator+(const quantity<R, Rep>& q, const Value& v)
{
return q + make_quantity<::mp_units::one>(v);
}
template<typename Value, auto R, typename Rep>
requires(!Quantity<Value>) && (quantity<R, Rep>::dimension == dimension_one) &&
detail::InvokeResultOf<get_quantity_spec(R).character, std::plus<>, Value, Rep>
[[nodiscard]] constexpr Quantity auto operator+(const Value& v, const quantity<R, Rep>& q)
{
return make_quantity<::mp_units::one>(v) + q;
}
template<auto R, typename Rep, typename Value>
requires(!Quantity<Value>) && (quantity<R, Rep>::dimension == dimension_one) &&
detail::InvokeResultOf<get_quantity_spec(R).character, std::minus<>, Rep, Value>
[[nodiscard]] constexpr Quantity auto operator-(const quantity<R, Rep>& q, const Value& v)
{
return q - make_quantity<::mp_units::one>(v);
}
template<typename Value, auto R, typename Rep>
requires(!Quantity<Value>) && (quantity<R, Rep>::dimension == dimension_one) &&
detail::InvokeResultOf<get_quantity_spec(R).character, std::minus<>, Value, Rep>
[[nodiscard]] constexpr Quantity auto operator-(const Value& v, const quantity<R, Rep>& q)
{
return make_quantity<::mp_units::one>(v) - q;
}
template<typename Value, auto R, typename Rep>
requires(!Quantity<Value>) && (quantity<R, Rep>::dimension == dimension_one) && (get_unit(R) == ::mp_units::one) &&
(!treat_as_floating_point<Value>) && (!treat_as_floating_point<Rep>) &&
detail::InvokeResultOf<get_quantity_spec(R).character, std::modulus<>, Value, Rep>
[[nodiscard]] constexpr Quantity auto operator%(const Value& v, const quantity<R, Rep>& q)
{
gsl_ExpectsAudit(q.number() != quantity_values<Rep>::zero());
return make_quantity<R>(v % q.number());
}
template<auto R, typename Rep, typename Value>
requires(!Quantity<Value>) &&
(quantity<R, Rep>::dimension == dimension_one) && std::equality_comparable_with<Rep, Value>
[[nodiscard]] constexpr bool operator==(const quantity<R, Rep>& q, const Value& v)
{
return q == make_quantity<::mp_units::one>(v);
}
template<auto R, typename Rep, typename Value>
requires(!Quantity<Value>) &&
(quantity<R, Rep>::dimension == dimension_one) && std::three_way_comparable_with<Rep, Value>
[[nodiscard]] constexpr auto operator<=>(const quantity<R, Rep>& q, const Value& v)
{
return q <=> make_quantity<::mp_units::one>(v);
}
// make_quantity
template<Reference auto R, typename Rep>
requires quantity<R, std::remove_cvref_t<Rep>>::_rep_safe_constructible_

View File

@@ -37,7 +37,7 @@ using namespace mp_units::si::unit_symbols;
TEST_CASE("'pow<N>()' on quantity changes the value and the dimension accordingly", "[math][pow]")
{
SECTION("'pow<0>(q)' returns '1'") { CHECK(pow<0>(2 * isq::length[m]) == 1); }
SECTION("'pow<0>(q)' returns '1'") { CHECK(pow<0>(2 * isq::length[m]) == 1 * one); }
SECTION("'pow<1>(q)' returns 'q'") { CHECK(pow<1>(2 * isq::length[m]) == 2 * isq::length[m]); }

View File

@@ -80,45 +80,6 @@ concept creates_quantity = Unit<std::remove_cvref_t<decltype(U)>> && requires {
static_assert(creates_quantity<min_impl<int>, si::metre>);
static_assert(creates_quantity<min_impl<double>, si::metre>);
// dimensionless quantity is constructible and convertible from a value
static_assert(std::constructible_from<quantity<one, min_impl<int>>, min_impl<int>>);
static_assert(std::convertible_to<min_impl<int>, quantity<one, min_impl<int>>>);
static_assert(std::constructible_from<quantity<one, min_impl<double>>, min_impl<double>>);
static_assert(std::convertible_to<min_impl<double>, quantity<one, min_impl<double>>>);
static_assert(std::constructible_from<quantity<one, min_impl<double>>, min_impl<int>>);
static_assert(std::convertible_to<min_impl<int>, quantity<one, min_impl<double>>>);
static_assert(!std::constructible_from<quantity<one, min_impl<int>>, min_impl<double>>); // narrowing conversion
static_assert(!std::convertible_to<min_impl<double>, quantity<one, min_impl<int>>>);
// and underlying type
static_assert(std::constructible_from<quantity<one, min_impl<int>>, int>);
static_assert(std::convertible_to<int, quantity<one, min_impl<int>>>);
static_assert(std::constructible_from<quantity<one, min_impl<double>>, double>);
static_assert(std::convertible_to<double, quantity<one, min_impl<double>>>);
static_assert(std::constructible_from<quantity<one, min_impl<double>>, int>);
static_assert(std::convertible_to<int, quantity<one, min_impl<double>>>);
static_assert(!std::constructible_from<quantity<one, min_impl<int>>, double>); // narrowing conversion
static_assert(!std::convertible_to<double, quantity<one, min_impl<int>>>);
// but only for ratio(1)
static_assert(!std::constructible_from<quantity<percent, min_impl<int>>, min_impl<int>>);
static_assert(!std::convertible_to<min_impl<int>, quantity<percent, min_impl<int>>>);
static_assert(!std::constructible_from<quantity<percent, min_impl<double>>, min_impl<double>>);
static_assert(!std::convertible_to<min_impl<double>, quantity<percent, min_impl<double>>>);
static_assert(!std::constructible_from<quantity<percent, min_impl<double>>, min_impl<int>>);
static_assert(!std::convertible_to<min_impl<int>, quantity<percent, min_impl<double>>>);
static_assert(!std::constructible_from<quantity<percent, min_impl<int>>, min_impl<double>>); // narrowing conversion
static_assert(!std::convertible_to<min_impl<double>, quantity<percent, min_impl<int>>>);
// multiply syntax
static_assert(creates_quantity<min_impl<int>, one>);
static_assert(creates_quantity<min_impl<double>, one>);
@@ -258,9 +219,9 @@ static_assert(min_impl<int>{123} * si::metre / (min_impl<double>(2.) * one) == m
static_assert(min_impl<int>{123} * si::metre / (2. * one) == min_impl<double>{61.5} * si::metre);
static_assert(123 * si::metre / (min_impl<double>(2.) * one) == min_impl<double>{61.5} * si::metre);
static_assert(min_impl<int>{123} * si::metre / (min_impl<double>{2.} * si::metre) == 61.5);
static_assert(min_impl<int>{123} * si::metre / (double{2.} * si::metre) == 61.5);
static_assert(123 * si::metre / (min_impl<double>{2.} * si::metre) == 61.5);
static_assert(min_impl<int>{123} * si::metre / (min_impl<double>{2.} * si::metre) == 61.5 * one);
static_assert(min_impl<int>{123} * si::metre / (double{2.} * si::metre) == 61.5 * one);
static_assert(123 * si::metre / (min_impl<double>{2.} * si::metre) == 61.5 * one);
static_assert(min_impl<int>{123} * si::metre % (min_impl<int>(100) * si::metre) == 23 * si::metre);
static_assert(min_impl<int>{123} * si::metre % (100 * si::metre) == 23 * si::metre);

View File

@@ -131,43 +131,11 @@ static_assert(!std::convertible_to<double, quantity<isq::length[m]>>);
static_assert(!std::constructible_from<quantity<isq::length[m], int>, int>);
static_assert(!std::convertible_to<int, quantity<isq::length[m], int>>);
// exception, implicit construction from a value allowed for a dimensionless quantity
static_assert(std::constructible_from<quantity<dimensionless[one]>, double>);
static_assert(std::convertible_to<double, quantity<dimensionless[one]>>);
static_assert(!std::constructible_from<quantity<dimensionless[one]>, double>);
static_assert(!std::convertible_to<double, quantity<dimensionless[one]>>);
static_assert(std::constructible_from<quantity<dimensionless[one]>, float>);
static_assert(std::convertible_to<float, quantity<dimensionless[one]>>);
static_assert(std::constructible_from<quantity<dimensionless[one], float>, double>);
static_assert(std::convertible_to<double, quantity<dimensionless[one], float>>);
static_assert(std::constructible_from<quantity<dimensionless[one]>, int>);
static_assert(std::convertible_to<int, quantity<dimensionless[one]>>);
static_assert(std::constructible_from<quantity<dimensionless[one]>, short>);
static_assert(std::convertible_to<short, quantity<dimensionless[one]>>);
static_assert(std::constructible_from<quantity<dimensionless[one], short>, int>);
static_assert(std::convertible_to<int, quantity<dimensionless[one], short>>);
// but only if a dimensionless quantity has a ratio(1)
static_assert(!std::constructible_from<quantity<dimensionless[percent]>, double>);
static_assert(!std::convertible_to<double, quantity<dimensionless[percent]>>);
static_assert(!std::constructible_from<quantity<dimensionless[percent]>, float>);
static_assert(!std::convertible_to<float, quantity<dimensionless[percent]>>);
static_assert(!std::constructible_from<quantity<dimensionless[percent], float>, double>);
static_assert(!std::convertible_to<double, quantity<dimensionless[percent], float>>);
static_assert(!std::constructible_from<quantity<dimensionless[percent]>, int>);
static_assert(!std::convertible_to<int, quantity<dimensionless[percent]>>);
static_assert(!std::constructible_from<quantity<dimensionless[percent]>, short>);
static_assert(!std::convertible_to<short, quantity<dimensionless[percent]>>);
static_assert(!std::constructible_from<quantity<dimensionless[percent], short>, int>);
static_assert(!std::convertible_to<int, quantity<dimensionless[percent], short>>);
static_assert(!std::constructible_from<quantity<dimensionless[one]>, int>);
static_assert(!std::convertible_to<int, quantity<dimensionless[one]>>);
///////////////////////////////////////
@@ -715,29 +683,20 @@ static_assert(1 * si::si2019::speed_of_light_in_vacuum + 10 * isq::speed[m / s]
// Implicit conversions allowed between quantities of `convertible` references
constexpr quantity<isq::speed[km / h]> speed = 120 * isq::length[km] / (2 * isq::time[h]);
// dimensionless
static_assert((3 * one *= 2 * one) == 6);
static_assert((6 * one /= 2 * one) == 3);
static_assert(1 * one + 1 * one == 2);
static_assert(1 + 1 * one == 2);
static_assert(1 * one + 1 == 2);
static_assert(2 * one - 1 * one == 1);
static_assert(2 - 1 * one == 1);
static_assert(2 * one - 1 == 1);
static_assert(2 * one * (2 * one) == 4);
static_assert(2 * (2 * one) == 4);
static_assert(2 * one * 2 == 4);
static_assert(4 * one / (2 * one) == 2);
static_assert(4 / (2 * one) == 2);
static_assert(4 * one / 2 == 2);
static_assert(4 * one % (2 * one) == 0);
static_assert(4 % (2 * one) == 0);
static_assert(4 % (2 * one) == 0);
static_assert((3 * one *= 2 * one) == 6 * one);
static_assert((6 * one /= 2 * one) == 3 * one);
static_assert(1 * one + 1 * one == 2 * one);
static_assert(2 * one - 1 * one == 1 * one);
static_assert(2 * one * (2 * one) == 4 * one);
static_assert(2 * (2 * one) == 4 * one);
static_assert(2 * one * 2 == 4 * one);
static_assert(4 * one / (2 * one) == 2 * one);
static_assert(4 / (2 * one) == 2 * one);
static_assert(4 * one / 2 == 2 * one);
static_assert(4 * one % (2 * one) == 0 * one);
// modulo arithmetics
static_assert(5 * h % (120 * min) == 60 * min);
static_assert(300 * min % (2 * h) == 60 * min);
static_assert(300 * min % (120 * min) == 60 * min);
@@ -754,17 +713,13 @@ constexpr auto quotient_remainder_theorem(auto q1, auto q2)
static_assert(quotient_remainder_theorem(7 * m, 3 * m) == 7 * m);
static_assert(quotient_remainder_theorem(3'000 * m, 400 * m) == 3'000 * m);
static_assert(is_same_v<decltype(0 * one + 0.0), decltype(0.0 * one)>);
static_assert(is_same_v<decltype(0 * one - 0.0), decltype(0.0 * one)>);
static_assert(is_same_v<decltype(0.0 + 0 * one), decltype(0.0 * one)>);
static_assert(is_same_v<decltype(0.0 + 0 * one), decltype(0.0 * one)>);
static_assert(1 * one + 2.3 == (1 + 2.3) * one);
static_assert(1 * one - 2.3 == (1 - 2.3) * one);
static_assert(1.2 + 3 * one == (1.2 + 3) * one);
static_assert(1.2 - 3 * one == (1.2 - 3) * one);
static_assert(is_same_v<decltype(0 * one + 0.0 * one), decltype(0.0 * one)>);
static_assert(is_same_v<decltype(0 * one - 0.0 * one), decltype(0.0 * one)>);
static_assert(is_same_v<decltype(0.0 * one + 0 * one), decltype(0.0 * one)>);
static_assert(is_same_v<decltype(0.0 * one - 0 * one), decltype(0.0 * one)>);
static_assert(1 - 30 * percent == (100 - 30) * percent);
static_assert(1 + 30 * percent == (100 + 30) * percent);
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).number()), int&&>);
static_assert(is_same_v<decltype((std::uint8_t(0) * one - std::uint8_t(0) * one).number()), int&&>);
@@ -821,17 +776,6 @@ static_assert(321 * km != 123'000 * m);
static_assert(!(123 * km == 321'000 * m));
static_assert(!(123 * km != 123'000 * m));
// dimensionless
static_assert(std::equality_comparable_with<quantity<dimensionless[one]>, double>);
static_assert(std::equality_comparable_with<quantity<dimensionless[one]>, int>);
static_assert(std::equality_comparable_with<quantity<dimensionless[one], int>, int>);
static_assert(std::equality_comparable_with<quantity<dimensionless[one], int>, double>);
static_assert(123 * one == 123);
static_assert(321 * one != 123);
static_assert(123 == 123 * one);
static_assert(123 != 321 * one);
// Named and derived dimensions (same units)
static_assert(10 * isq::length[m] / (2 * isq::time[s]) == 5 * isq::speed[m / s]);
static_assert(5 * isq::speed[m / s] == 10 * isq::length[m] / (2 * isq::time[s]));
@@ -908,21 +852,6 @@ static_assert(!(123 * km > 321'000 * m));
static_assert(!(123 * km > 123'000 * m));
static_assert(!(123 * km >= 321'000 * m));
// dimensionless
static_assert(123 * one < 321);
static_assert(123 * one <= 123);
static_assert(123 * one <= 321);
static_assert(321 * one > 123);
static_assert(123 * one >= 123);
static_assert(321 * one >= 123);
static_assert(123 < 321 * one);
static_assert(123 <= 123 * one);
static_assert(123 <= 321 * one);
static_assert(321 > 123 * one);
static_assert(123 >= 123 * one);
static_assert(321 >= 123 * one);
//////////////////
// dimensionless

View File

@@ -285,60 +285,39 @@ static_assert(no_common_reference<radian, solid_angular_measure[steradian]>);
static_assert(no_common_reference<angular_measure[radian], solid_angular_measure[steradian]>);
// addition of various dimensionless quantities
static_assert(is_of_type<1 * one + 1, quantity<one, int>>);
static_assert(is_of_type<dimensionless(1 * one) + 1, quantity<dimensionless[one], int>>);
static_assert(is_of_type<1 * radian + 1, quantity<radian, int>>);
static_assert(is_of_type<1 * radian + 1 * one, quantity<radian, int>>);
static_assert(is_of_type<1 * radian + dimensionless(1 * one), quantity<angular_measure[radian], int>>);
static_assert(is_of_type<angular_measure(1 * radian) + 1, quantity<angular_measure[radian], int>>);
static_assert(is_of_type<angular_measure(1 * radian) + 1 * one, quantity<angular_measure[radian], int>>);
static_assert(is_of_type<angular_measure(1 * radian) + dimensionless(1 * one), quantity<angular_measure[radian], int>>);
static_assert(is_of_type<1 * steradian + 1, quantity<steradian, int>>);
static_assert(is_of_type<1 * steradian + 1 * one, quantity<steradian, int>>);
static_assert(is_of_type<1 * steradian + dimensionless(1 * one), quantity<solid_angular_measure[steradian], int>>);
static_assert(is_of_type<solid_angular_measure(1 * steradian) + 1, quantity<solid_angular_measure[steradian], int>>);
static_assert(
is_of_type<solid_angular_measure(1 * steradian) + 1 * one, quantity<solid_angular_measure[steradian], int>>);
static_assert(is_of_type<solid_angular_measure(1 * steradian) + dimensionless(1 * one),
quantity<solid_angular_measure[steradian], int>>);
// subtraction of various dimensionless quantities
static_assert(is_of_type<1 * one - 1, quantity<one, int>>);
static_assert(is_of_type<dimensionless(1 * one) - 1, quantity<dimensionless[one], int>>);
static_assert(is_of_type<1 * radian - 1, quantity<radian, int>>);
static_assert(is_of_type<1 * radian - 1 * one, quantity<radian, int>>);
static_assert(is_of_type<1 * radian - dimensionless(1 * one), quantity<angular_measure[radian], int>>);
static_assert(is_of_type<angular_measure(1 * radian) - 1, quantity<angular_measure[radian], int>>);
static_assert(is_of_type<angular_measure(1 * radian) - 1 * one, quantity<angular_measure[radian], int>>);
static_assert(is_of_type<angular_measure(1 * radian) - dimensionless(1 * one), quantity<angular_measure[radian], int>>);
static_assert(is_of_type<1 * steradian - 1, quantity<steradian, int>>);
static_assert(is_of_type<1 * steradian - 1 * one, quantity<steradian, int>>);
static_assert(is_of_type<1 * steradian - dimensionless(1 * one), quantity<solid_angular_measure[steradian], int>>);
static_assert(is_of_type<solid_angular_measure(1 * steradian) - 1, quantity<solid_angular_measure[steradian], int>>);
static_assert(
is_of_type<solid_angular_measure(1 * steradian) - 1 * one, quantity<solid_angular_measure[steradian], int>>);
static_assert(is_of_type<solid_angular_measure(1 * steradian) - dimensionless(1 * one),
quantity<solid_angular_measure[steradian], int>>);
// comparison of various dimensionless quantities
static_assert(1 * one == 1);
static_assert(dimensionless(1 * one) == 1);
static_assert(1 * radian == 1);
static_assert(1 * radian == 1 * one);
static_assert(1 * radian == dimensionless(1 * one));
static_assert(angular_measure(1 * radian) == 1);
static_assert(angular_measure(1 * radian) == 1 * one);
static_assert(angular_measure(1 * radian) == dimensionless(1 * one));
static_assert(1 * steradian == 1);
static_assert(1 * steradian == 1 * one);
static_assert(1 * steradian == dimensionless(1 * one));
static_assert(solid_angular_measure(1 * steradian) == 1);
static_assert(solid_angular_measure(1 * steradian) == 1 * one);
static_assert(solid_angular_measure(1 * steradian) == dimensionless(1 * one));