From d0eceefe800b719d7b25fbb969ed26bc9ba84f5e Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Tue, 6 Sep 2022 23:45:47 +0200 Subject: [PATCH] refactor: dead ratio code removed --- src/core/include/units/bits/constexpr_math.h | 1 - src/core/include/units/bits/pow.h | 46 --------- src/core/include/units/bits/root.h | 99 -------------------- src/core/include/units/quantity_cast.h | 1 - src/core/include/units/ratio.h | 20 ---- test/unit_test/runtime/math_test.cpp | 73 --------------- test/unit_test/static/ratio_test.cpp | 9 -- 7 files changed, 249 deletions(-) delete mode 100644 src/core/include/units/bits/pow.h delete mode 100644 src/core/include/units/bits/root.h diff --git a/src/core/include/units/bits/constexpr_math.h b/src/core/include/units/bits/constexpr_math.h index da7fc2cf..c675579b 100644 --- a/src/core/include/units/bits/constexpr_math.h +++ b/src/core/include/units/bits/constexpr_math.h @@ -25,7 +25,6 @@ #include #include #include -#include #include namespace units::detail { diff --git a/src/core/include/units/bits/pow.h b/src/core/include/units/bits/pow.h deleted file mode 100644 index e4216fdb..00000000 --- a/src/core/include/units/bits/pow.h +++ /dev/null @@ -1,46 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2018 Mateusz Pusz -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -#pragma once - -#include -#include - -namespace units::detail { - -template -constexpr T pow_impl(const T& v) noexcept -{ - if constexpr (N == 0) { - return T(1); - } else if constexpr (N == 1) { - return v; - } else if constexpr (N < 0) { - return 1 / pow_impl<-N>(v); - } else if constexpr (N % 2 == 0) { // even - return pow_impl(v * v); - } else { // odd - return v * pow_impl<(N - 1) / 2>(v * v); - } -} - -} // namespace units::detail diff --git a/src/core/include/units/bits/root.h b/src/core/include/units/bits/root.h deleted file mode 100644 index 8e074e16..00000000 --- a/src/core/include/units/bits/root.h +++ /dev/null @@ -1,99 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2018 Mateusz Pusz -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -#pragma once - -#include -#include -#include -#include -#include -#include - -namespace units::detail { - -template - requires gt_zero -[[nodiscard]] constexpr std::intmax_t iroot_impl(std::intmax_t v, const F& pow_function) noexcept -{ - if constexpr (N == 1) { - return v; - } else { - gsl_Expects(v >= 0); - if (v == 0) { - return 0; - } - - constexpr double exponent = 1.0 / static_cast(N); - const auto root = static_cast(pow_function(static_cast(v), exponent)); - - // integer roots may be truncated down by 1 or in even rarer cases up by 1 due to finite precision of pow and - // exponent, check both cases - if (v == pow_impl(root + 1)) { - return root + 1; - } - if (v < pow_impl(root)) { - return root - 1; - } - return root; - } -} - -// maximum v is std::numeric_limits::max() which is the worst case for exp convergence -// ExpOrder = 12 and Factor = 64 give a precision of about O(1e-15) for a wide range of 1 / N exponents -// Factor = 32 needs quite a few more terms to converge -// https://godbolt.org/z/odWq1o -template - requires gt_zero -[[nodiscard]] constexpr std::intmax_t iroot_compile(std::intmax_t v) noexcept -{ - return iroot_impl(v, [](double x, double exponent) { return constexpr_pow(x, exponent); }); -} - -template - requires gt_zero -[[nodiscard]] std::intmax_t iroot_runtime(std::intmax_t v) noexcept -{ - return iroot_impl(v, [](double x, [[maybe_unused]] double exponent) { - if constexpr (N == 2) { - return std::sqrt(x); - } else if constexpr (N == 3) { - return std::cbrt(x); - } else { - return std::pow(x, exponent); - } - }); -} - -template - requires gt_zero -[[nodiscard]] constexpr std::intmax_t iroot(std::intmax_t v) noexcept -{ - // compile time version is much slower, use faster version at runtime - if (std::is_constant_evaluated()) { - return iroot_compile(v); - } - - return iroot_runtime(v); -} - -} // namespace units::detail diff --git a/src/core/include/units/quantity_cast.h b/src/core/include/units/quantity_cast.h index 61678558..4449d722 100644 --- a/src/core/include/units/quantity_cast.h +++ b/src/core/include/units/quantity_cast.h @@ -24,7 +24,6 @@ #include #include -#include #include #include #include diff --git a/src/core/include/units/ratio.h b/src/core/include/units/ratio.h index d0bd8ec3..7b045de3 100644 --- a/src/core/include/units/ratio.h +++ b/src/core/include/units/ratio.h @@ -24,9 +24,7 @@ // IWYU pragma: begin_exports #include -#include #include -#include #include // IWYU pragma: end_exports @@ -84,24 +82,6 @@ struct ratio { [[nodiscard]] constexpr bool is_integral(const ratio& r) { return r.num % r.den == 0; } -template -[[nodiscard]] constexpr ratio pow(const ratio& r) -{ - if constexpr (Num == 0) { - return ratio(1); - } else if constexpr (Num == 1) { - return r; - } else { - const ratio result = detail::pow_impl(r); - - if constexpr (Num < 0) { // account for negative exponent - return inverse(result); - } else { - return result; - } - } -} - // common_ratio [[nodiscard]] constexpr ratio common_ratio(const ratio& r1, const ratio& r2) { diff --git a/test/unit_test/runtime/math_test.cpp b/test/unit_test/runtime/math_test.cpp index 91b8ef82..cf2e4c3d 100644 --- a/test/unit_test/runtime/math_test.cpp +++ b/test/unit_test/runtime/math_test.cpp @@ -294,79 +294,6 @@ TEST_CASE("round functions", "[round]") } } -TEMPLATE_TEST_CASE_SIG("pow() implementation exponentiates values to power N", "[math][pow][exp]", - (std::intmax_t N, N), 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25) -{ - auto v = GENERATE(range(0.5, 20.0, 0.5)); - REQUIRE(detail::pow_impl(v) == Catch::Approx(std::pow(v, N)).epsilon(1e-15).margin(0)); -} - -template -struct Pow { - constexpr static std::intmax_t exponent = N; - template - [[nodiscard]] constexpr static auto pow(const T& v) noexcept - { - return detail::pow_impl(v); - } -}; - -template -struct CompileRoot : Pow { - [[nodiscard]] constexpr static std::intmax_t root(std::intmax_t v) noexcept { return detail::iroot_compile(v); } -}; - -template -struct RuntimeRoot : Pow { - [[nodiscard]] static std::intmax_t root(std::intmax_t v) noexcept { return detail::iroot_runtime(v); } -}; - -// test to make sure precision is not lost when rounding what should be integer roots -template -static void root_test() -{ - SECTION("Roots are truncated down") - { - auto base = GENERATE(range(1.0, 10.0, 1.0)); // doubles to guard against overflow - - if (TestType::pow(base) < static_cast(std::numeric_limits::max())) { - const std::intmax_t x = TestType::pow(static_cast(base)); - const auto expect = static_cast(base); - - REQUIRE(TestType::root(x - 1) == expect - 1); - REQUIRE(TestType::root(x) == expect); - } - } - - SECTION("Roots are truncated correctly for very large inputs") - { - auto exponent = GENERATE(range(10, std::numeric_limits::digits10, 1)); - const auto large_val = static_cast(std::pow(10, exponent)); - const auto expected = static_cast(std::pow(10, exponent / static_cast(TestType::exponent))); - - REQUIRE(TestType::root(large_val) == expected); - } -} - -/* Catch2 uses int for indexing in TEMPLATE_PRODUCT_TEST_CASE_SIG so it does not compile with -Werror=sign-conversion - * https://github.com/catchorg/Catch2/pull/2074 - -TEMPLATE_PRODUCT_TEST_CASE_SIG("detail::iroot()", "[math][pow][iroot]", (std::intmax_t N, N), - (CompileRoot, RuntimeRoot), (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25)) -{ - root_test(); -} - */ -#define ROOT_TEST_CASE(Type) \ - TEMPLATE_TEST_CASE_SIG("detail::iroot() - " #Type, "[math][pow][iroot]", (std::intmax_t N, N), 1, 2, 3, 4, 5, 6, \ - 7, 8, 9, 10, 15, 20, 25) \ - { \ - root_test>(); \ - } - -ROOT_TEST_CASE(CompileRoot) -ROOT_TEST_CASE(RuntimeRoot) - TEST_CASE("hypot functions", "[hypot]") { using namespace units::aliases::isq::si; diff --git a/test/unit_test/static/ratio_test.cpp b/test/unit_test/static/ratio_test.cpp index 02828115..57c8f3e0 100644 --- a/test/unit_test/static/ratio_test.cpp +++ b/test/unit_test/static/ratio_test.cpp @@ -46,15 +46,6 @@ static_assert(ratio(2) / ratio(8) == ratio(1, 4)); static_assert(ratio(1, 8) / ratio(2) == ratio(1, 16)); static_assert(ratio(6) / ratio(3) == ratio(2)); -static_assert(pow<0>(ratio(2)) == ratio(1)); -static_assert(pow<1>(ratio(2)) == ratio(2)); -static_assert(pow<2>(ratio(2)) == ratio(4)); -static_assert(pow<3>(ratio(2)) == ratio(8)); -static_assert(pow<0>(ratio(1, 2)) == ratio(1)); -static_assert(pow<1>(ratio(1, 2)) == ratio(1, 2)); -static_assert(pow<2>(ratio(1, 2)) == ratio(1, 4)); -static_assert(pow<3>(ratio(1, 2)) == ratio(1, 8)); - // common_ratio static_assert(common_ratio(ratio(1), ratio(1000)) == ratio(1)); static_assert(common_ratio(ratio(1000), ratio(1)) == ratio(1));