Skip to content

Commit

Permalink
feat: IEEE floating-point division remainder
Browse files Browse the repository at this point in the history
  • Loading branch information
nebkat committed Apr 18, 2024
1 parent da93400 commit 069f2bf
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
- feat: `ppm` parts per million added by [@nebkat](https://github.com/nebkat)
- feat: `atan2` 2-argument arctangent added by [@nebkat](https://github.com/nebkat)
- feat: `fmod` floating-point division remainder added by [@nebkat](https://github.com/nebkat)
- feat: `remainder` IEEE division remainder added by [@nebkat](https://github.com/nebkat)
- feat: `std::format` support added
- feat: unit text output support added
- feat: formatting error messages improved
Expand Down
2 changes: 1 addition & 1 deletion docs/users_guide/framework_basics/quantity_arithmetics.md
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ Among others, we can find there the following:
- `exp()`,
- `abs()`,
- `epsilon()`,
- `fma()`, `fmod()`,
- `fma()`, `fmod()`, `remainder()`,
- `isfinite()`, `isinf()`, `isnan()`,
- `floor()`, `ceil()`, `round()`,
- `inverse()`,
Expand Down
17 changes: 17 additions & 0 deletions src/core/include/mp-units/math.h
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,23 @@ template<auto R1, typename Rep1, auto R2, typename Rep2>
return quantity{fmod(x.numerical_value_in(unit), y.numerical_value_in(unit)), ref};
}

/**
* @brief Computes the IEEE remainder of the floating point division operation x / y.
*/
template<auto R1, typename Rep1, auto R2, typename Rep2>
requires requires(Rep1 v1, Rep2 v2) {
common_reference(R1, R2);
requires requires { remainder(v1, v2); } || requires { std::remainder(v1, v2); };
}
[[nodiscard]] constexpr QuantityOf<get_quantity_spec(R1)> auto remainder(const quantity<R1, Rep1>& x,
const quantity<R2, Rep2>& y) noexcept
{
constexpr auto ref = common_reference(R1, R2);
constexpr auto unit = get_unit(ref);
using std::remainder;
return quantity{remainder(x.numerical_value_in(unit), y.numerical_value_in(unit)), ref};
}


/**
* @brief Returns the epsilon of the quantity
Expand Down
18 changes: 18 additions & 0 deletions test/runtime/math_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,24 @@ TEST_CASE("fmod functions", "[math][fmod]")
}
}

TEST_CASE("remainder functions", "[math][remainder]")
{
SECTION("remainder should work on the same quantities")
{
REQUIRE(remainder(4. * isq::length[km], 3. * isq::length[km]) == 1. * isq::length[km]);
REQUIRE(remainder(-9. * isq::length[km], 3. * isq::length[km]) == -0. * isq::length[km]);
REQUIRE(remainder(3 * isq::length[km], 2 * isq::length[km]) == -1 * isq::length[km]);
REQUIRE(remainder(4 * isq::length[km], 2.75f * isq::length[km]) == 1.25 * isq::length[km]);
}
SECTION("remainder should work with different units of the same dimension")
{
REQUIRE(remainder(4. * isq::length[km], 3000. * isq::length[m]) == 1000. * isq::length[m]);
REQUIRE(remainder(-9. * isq::length[km], 3000. * isq::length[m]) == -0. * isq::length[m]);
REQUIRE(remainder(3. * isq::length[km], 2000. * isq::length[m]) == -1000 * isq::length[m]);
REQUIRE(remainder(4 * isq::length[km], 2750 * isq::length[m]) == 1250 * isq::length[m]);
}
}

TEST_CASE("'isfinite()' accepts dimensioned arguments", "[math][isfinite]") { REQUIRE(isfinite(4.0 * isq::length[m])); }

TEST_CASE("'isinf()' accepts dimensioned arguments", "[math][isinf]") { REQUIRE(!isinf(4.0 * isq::length[m])); }
Expand Down
6 changes: 6 additions & 0 deletions test/static/math_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ static_assert(compare(fmod(9.0 * km, -3.0 * km), 0.0 * km));
static_assert(compare(fmod(9.5 * km, -2000 * m), 1500.0 * m));
static_assert(compare(fmod(3 * km, 2 * km), 1.0 * km));
static_assert(compare(fmod(4 * km, 2.5f * km), 1.5 * km));
static_assert(compare(remainder(4.0 * km, 3.0 * km), 1.0 * km));
static_assert(compare(remainder(-4.0 * km, 3.0 * km), -1.0 * km));
static_assert(compare(remainder(9.0 * km, -3.0 * km), 0.0 * km));
static_assert(compare(remainder(9.5 * km, -2000 * m), -500.0 * m));
static_assert(compare(remainder(3 * km, 2 * km), -1.0 * km));
static_assert(compare(remainder(4 * km, 2.75f * km), 1.25 * km));
static_assert(compare(pow<0>(2 * m), 1 * one));
static_assert(compare(pow<1>(2 * m), 2 * m));
static_assert(compare(pow<2>(2 * m), 4 * pow<2>(m), 4 * m2));
Expand Down

0 comments on commit 069f2bf

Please sign in to comment.