fix: quantity modulo arithmetics fixed

Resolves #231
This commit is contained in:
Mateusz Pusz
2021-05-11 15:03:04 +02:00
parent 68203b6a9f
commit 1783d243da
4 changed files with 69 additions and 21 deletions

View File

@@ -34,6 +34,7 @@
- fix: downcasting facility for non-default-constructible types - fix: downcasting facility for non-default-constructible types
- fix: restore user-warnings within the library implementation - fix: restore user-warnings within the library implementation
- fix: the text symbol of `foot_pound_force` and `foot_pound_force_per_second` - fix: the text symbol of `foot_pound_force` and `foot_pound_force_per_second`
- fix: quantity modulo arithmetics fixed
- (!) build: Conan testing version is now hosted on [Artifactory](https://mpusz.jfrog.io/ui/packages/conan:%2F%2Fmp-units) - (!) build: Conan testing version is now hosted on [Artifactory](https://mpusz.jfrog.io/ui/packages/conan:%2F%2Fmp-units)
- (!) build: Linear Algebra is now hosted on its [Artifactory](https://twonington.jfrog.io/artifactory/api/conan/conan-oss) - (!) build: Linear Algebra is now hosted on its [Artifactory](https://twonington.jfrog.io/artifactory/api/conan/conan-oss)
- (!) build: `BUILD_DOCS` CMake option renamed to `UNITS_BUILD_DOCS` - (!) build: `BUILD_DOCS` CMake option renamed to `UNITS_BUILD_DOCS`

View File

@@ -426,25 +426,15 @@ template<Quantity Q1, Quantity Q2>
return detail::make_quantity<Q1::reference / Q2::reference>(lhs.number() / rhs.number()); return detail::make_quantity<Q1::reference / Q2::reference>(lhs.number() / rhs.number());
} }
template<typename D1, typename U1, typename Rep1, typename U2, typename Rep2> template<Quantity Q1, Quantity Q2>
requires (!floating_point_<Rep1>) && (!floating_point_<Rep2>) &&
quantity_value_for_<std::modulus<>, Rep1, Rep2>
[[nodiscard]] constexpr Quantity auto operator%(const quantity<D1, U1, Rep1>& lhs, const quantity<dim_one, U2, Rep2>& rhs)
{
gsl_ExpectsAudit(rhs.number() != quantity_values<Rep2>::zero());
using unit = downcast_unit<D1, U1::ratio * U2::ratio>;
using ret = quantity<D1, unit, std::invoke_result_t<std::modulus<>, Rep1, Rep2>>;
return ret(lhs.number() % rhs.number());
}
template<Quantity Q1, QuantityEquivalentTo<Q1> Q2>
requires (!floating_point_<typename Q1::rep>) && (!floating_point_<typename Q2::rep>) && requires (!floating_point_<typename Q1::rep>) && (!floating_point_<typename Q2::rep>) &&
(QuantityEquivalentTo<Q2, Q1> || Dimensionless<Q2>) &&
quantity_value_for_<std::modulus<>, typename Q1::rep, typename Q2::rep> quantity_value_for_<std::modulus<>, typename Q1::rep, typename Q2::rep>
[[nodiscard]] constexpr Quantity auto operator%(const Q1& lhs, const Q2& rhs) [[nodiscard]] constexpr Quantity auto operator%(const Q1& lhs, const Q2& rhs)
{ {
gsl_ExpectsAudit(rhs.number() != quantity_values<typename Q2::rep>::zero()); gsl_ExpectsAudit(rhs.number() != quantity_values<typename Q2::rep>::zero());
using ret = common_quantity_for<std::modulus<>, Q1, Q2>; using ret = quantity<typename Q1::dimension, typename Q1::unit, std::invoke_result_t<std::modulus<>, typename Q1::rep, typename Q2::rep>>;
return ret(ret(lhs).number() % ret(rhs).number()); return ret(lhs.number() % rhs.number());
} }
template<Quantity Q1, QuantityEquivalentTo<Q1> Q2> template<Quantity Q1, QuantityEquivalentTo<Q1> Q2>

View File

@@ -612,7 +612,7 @@ static_assert(same(height<metre, double>(2. * m) / (3 * s), rate_of_climb<metre_
static_assert(same(width<metre, int>(2 * m) * dimensionless<percent, int>(3), width<centimetre, int>(6 * cm))); static_assert(same(width<metre, int>(2 * m) * dimensionless<percent, int>(3), width<centimetre, int>(6 * cm)));
static_assert(same(dimensionless<percent, int>(2) * width<metre, int>(3 * m), width<centimetre, int>(6 * cm))); static_assert(same(dimensionless<percent, int>(2) * width<metre, int>(3 * m), width<centimetre, int>(6 * cm)));
static_assert(same(width<metre, int>(2 * m) / dimensionless<percent, double>(3), width<hectometre, double>(2. / 3 * hm))); static_assert(same(width<metre, int>(2 * m) / dimensionless<percent, double>(3), width<hectometre, double>(2. / 3 * hm)));
static_assert(same(width<metre, int>(2 * m) % dimensionless<percent, int>(3), width<centimetre, int>(2 * cm))); static_assert(same(width<metre, int>(2 * m) % dimensionless<percent, int>(3), width<metre, int>(2 * m)));
static_assert(same(height<metre, int>(2 * m) / (3 * m), static_assert(same(height<metre, int>(2 * m) / (3 * m),
quantity_kind<downcast_kind<height_kind, dim_one>, one, int>(0))); quantity_kind<downcast_kind<height_kind, dim_one>, one, int>(0)));

View File

@@ -399,7 +399,7 @@ static_assert(is_same_v<decltype(1_q_m % 1_q_m), length<metre, std::int64_t>>);
static_assert(compare<decltype(1_q_m * dimensionless<percent, std::int64_t>(1)), length<centimetre, std::int64_t>>); static_assert(compare<decltype(1_q_m * dimensionless<percent, std::int64_t>(1)), length<centimetre, std::int64_t>>);
static_assert(compare<decltype(dimensionless<percent, std::int64_t>(1) * 1_q_m), length<centimetre, std::int64_t>>); static_assert(compare<decltype(dimensionless<percent, std::int64_t>(1) * 1_q_m), length<centimetre, std::int64_t>>);
static_assert(compare<decltype(1_q_m / dimensionless<percent, std::int64_t>(1)), length<hectometre, std::int64_t>>); static_assert(compare<decltype(1_q_m / dimensionless<percent, std::int64_t>(1)), length<hectometre, std::int64_t>>);
static_assert(compare<decltype(1_q_m % dimensionless<percent, std::int64_t>(1)), length<centimetre, std::int64_t>>); static_assert(compare<decltype(1_q_m % dimensionless<percent, std::int64_t>(1)), length<metre, std::int64_t>>);
static_assert(compare<decltype(1_q_m * 1_q_m), area<square_metre, std::int64_t>>); static_assert(compare<decltype(1_q_m * 1_q_m), area<square_metre, std::int64_t>>);
static_assert(compare<decltype(1_q_m / 1_q_m), dimensionless<one, std::int64_t>>); static_assert(compare<decltype(1_q_m / 1_q_m), dimensionless<one, std::int64_t>>);
static_assert(compare<decltype(1 / 1_q_s), frequency<hertz, std::int64_t>>); static_assert(compare<decltype(1 / 1_q_s), frequency<hertz, std::int64_t>>);
@@ -433,7 +433,7 @@ static_assert(compare<decltype(quantity{1} / 1._q_s), frequency<hertz, long doub
static_assert(compare<decltype(dimensionless<percent, std::int64_t>(1) / 1._q_s), frequency<scaled_unit<ratio(1, 100), hertz>, long double>>); static_assert(compare<decltype(dimensionless<percent, std::int64_t>(1) / 1._q_s), frequency<scaled_unit<ratio(1, 100), hertz>, long double>>);
static_assert(compare<decltype(1_q_m % short(1)), length<metre, std::int64_t>>); static_assert(compare<decltype(1_q_m % short(1)), length<metre, std::int64_t>>);
static_assert(compare<decltype(1_q_m % quantity{short(1)}), length<metre, std::int64_t>>); static_assert(compare<decltype(1_q_m % quantity{short(1)}), length<metre, std::int64_t>>);
static_assert(compare<decltype(1_q_m % dimensionless<percent, short>(1)), length<centimetre, std::int64_t>>); static_assert(compare<decltype(1_q_m % dimensionless<percent, short>(1)), length<metre, std::int64_t>>);
static_assert(compare<decltype(1_q_m % length<metre, short>(1)), length<metre, std::int64_t>>); static_assert(compare<decltype(1_q_m % length<metre, short>(1)), length<metre, std::int64_t>>);
static_assert(is_same_v<decltype(1._q_m + 1_q_m), length<metre, long double>>); static_assert(is_same_v<decltype(1._q_m + 1_q_m), length<metre, long double>>);
@@ -475,7 +475,7 @@ static_assert(is_same_v<decltype(1_q_km - 1._q_m), length<metre, long double>>);
static_assert(is_same_v<decltype(1._q_km - 1._q_m), length<metre, long double>>); static_assert(is_same_v<decltype(1._q_km - 1._q_m), length<metre, long double>>);
static_assert(is_same_v<decltype(1_q_m % 1_q_km), length<metre, std::int64_t>>); static_assert(is_same_v<decltype(1_q_m % 1_q_km), length<metre, std::int64_t>>);
static_assert(is_same_v<decltype(1_q_km % 1_q_m), length<metre, std::int64_t>>); static_assert(is_same_v<decltype(1_q_km % 1_q_m), length<kilometre, std::int64_t>>);
// different dimensions // different dimensions
static_assert(compare<decltype(1_q_m_per_s * 1_q_s), length<metre, std::int64_t>>); static_assert(compare<decltype(1_q_m_per_s * 1_q_s), length<metre, std::int64_t>>);
@@ -545,7 +545,7 @@ static_assert((7_q_m % 2).number() == 1);
static_assert((7_q_m % quantity{2}).number() == 1); static_assert((7_q_m % quantity{2}).number() == 1);
static_assert((7_q_m % dimensionless<percent, int>(2)).number() == 1); static_assert((7_q_m % dimensionless<percent, int>(2)).number() == 1);
static_assert((7_q_m % 2_q_m).number() == 1); static_assert((7_q_m % 2_q_m).number() == 1);
static_assert((7_q_km % 2000_q_m).number() == 1000); static_assert((7_q_km % 2000_q_m).number() == 7);
static_assert((10_q_km2 * 10_q_km2) / 50_q_km2 == 2_q_km2); static_assert((10_q_km2 * 10_q_km2) / 50_q_km2 == 2_q_km2);
@@ -560,8 +560,7 @@ static_assert(quantity_cast<one>(10_q_km / 5_q_m).number() == 2000);
static_assert((10_q_s * 2_q_kHz).number() == 20); static_assert((10_q_s * 2_q_kHz).number() == 20);
// unit constants // quantity references
static_assert(2_q_m * (1 * m) == (2_q_m2)); static_assert(2_q_m * (1 * m) == (2_q_m2));
static_assert(2_q_m2 / (1 * m) == (2_q_m)); static_assert(2_q_m2 / (1 * m) == (2_q_m));
@@ -787,4 +786,62 @@ static_assert(is_same_v<decltype(1_q_mm + 1_q_km), length<millimetre, std::int64
#endif #endif
// modulo arithmetics
constexpr auto quotient_remainder_theorem(auto q1, auto q2)
{
auto quotient = q1 / q2;
auto reminder = q1 % q2;
auto q = quotient * q2 + reminder;
return q;
}
constexpr auto qr1 = quotient_remainder_theorem(3'000 * m, 400 * m);
static_assert(qr1 == 3'000 * m);
static_assert(is_same_v<std::remove_cvref_t<decltype(qr1)>, decltype(3'000 * m)>);
constexpr auto qr2 = quotient_remainder_theorem(3 * km, 400 * m);
static_assert(qr2 == 3 * km);
static_assert(is_same_v<std::remove_cvref_t<decltype(qr2)>, decltype(3 * km)>);
constexpr auto qr3 = quotient_remainder_theorem(3 * km, 2 * m);
static_assert(qr3 == 3 * km);
static_assert(is_same_v<std::remove_cvref_t<decltype(qr2)>, decltype(3 * km)>);
constexpr auto qr4 = quotient_remainder_theorem(3 * km, 400'000 * mm);
static_assert(qr4 == 3 * km);
static_assert(is_same_v<std::remove_cvref_t<decltype(qr4)>, decltype(3 * km)>);
constexpr auto qr5 = quotient_remainder_theorem(3 * km, 2'000 * mm);
static_assert(qr5 == 3 * km);
static_assert(is_same_v<std::remove_cvref_t<decltype(qr5)>, decltype(3 * km)>);
constexpr auto qr6 = quotient_remainder_theorem(3 * km, 400 * mm);
static_assert(qr6 == 3 * km);
static_assert(is_same_v<std::remove_cvref_t<decltype(qr6)>, decltype(3 * km)>);
constexpr auto qr7 = quotient_remainder_theorem(3 * km, 2 * mm);
static_assert(qr7 == 3 * km);
static_assert(is_same_v<std::remove_cvref_t<decltype(qr7)>, decltype(3 * km)>);
constexpr auto qr8 = quotient_remainder_theorem(3'000 * m, 400);
static_assert(qr8 == 3'000 * m);
static_assert(is_same_v<std::remove_cvref_t<decltype(qr8)>, decltype(3'000 * m)>);
constexpr auto qr9 = quotient_remainder_theorem(3'000 * m, quantity(400));
static_assert(qr9 == 3'000 * m);
static_assert(is_same_v<std::remove_cvref_t<decltype(qr9)>, decltype(3'000 * m)>);
constexpr auto qr10 = quotient_remainder_theorem(3 * km, quantity(400));
static_assert(qr10 == 3 * km);
static_assert(is_same_v<std::remove_cvref_t<decltype(qr10)>, decltype(3 * km)>);
constexpr auto qr11 = quotient_remainder_theorem(3 * km, quantity(2));
static_assert(qr11 == 3 * km);
static_assert(is_same_v<std::remove_cvref_t<decltype(qr11)>, decltype(3 * km)>);
constexpr auto qr12 = quotient_remainder_theorem(3 * km, dimensionless<scaled_unit<ratio(1, 1000), one>, int>(400));
static_assert(qr12 == 3 * km);
static_assert(is_same_v<std::remove_cvref_t<decltype(qr12)>, decltype(3 * km)>);
} // namespace } // namespace