From 4741c71e340888c4dff8488f546fca8ddc554cd4 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sat, 14 Sep 2024 20:02:25 +0100 Subject: [PATCH] etl::ratio work-in-progress --- include/etl/ratio.h | 62 +++++++++++++++++++-- test/test_ratio.cpp | 133 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 191 insertions(+), 4 deletions(-) create mode 100644 test/test_ratio.cpp diff --git a/include/etl/ratio.h b/include/etl/ratio.h index b5034c3f..77a89093 100644 --- a/include/etl/ratio.h +++ b/include/etl/ratio.h @@ -32,6 +32,7 @@ SOFTWARE. #define ETL_RATIO_INCLUDED #include "platform.h" +#include "static_assert.h" #include #include @@ -71,6 +72,7 @@ namespace etl struct ratio { ETL_STATIC_ASSERT(Num != 0, "Numerator cannot be zero"); + ETL_STATIC_ASSERT(Den != 0, "Denominator cannot be zero"); static ETL_CONSTANT intmax_t num = Num / private_ratio::gcd::value; static ETL_CONSTANT intmax_t den = Den / private_ratio::gcd::value; @@ -103,13 +105,67 @@ namespace etl typedef etl::ratio type; }; + //*********************************************************************** + /// ratio_multiply + //*********************************************************************** + template + struct ratio_multiply + { + private: + + static ETL_CONSTANT intmax_t N = TRatio1::num * TRatio2::num; + static ETL_CONSTANT intmax_t D = TRatio1::den * TRatio2::den; + + static ETL_CONSTANT intmax_t Num = N / private_ratio::gcd::value; + static ETL_CONSTANT intmax_t Den = D / private_ratio::gcd::value; + + public: + + typedef etl::ratio type; + }; + + //*********************************************************************** + /// ratio_add + //*********************************************************************** + template + struct ratio_add + { + private: + + static ETL_CONSTANT intmax_t N = (TRatio1::num * TRatio2::den) + (TRatio2::num * TRatio1::den); + static ETL_CONSTANT intmax_t D = TRatio1::den * TRatio2::den;; + + static ETL_CONSTANT intmax_t Num = N / private_ratio::gcd::value; + static ETL_CONSTANT intmax_t Den = D / private_ratio::gcd::value; + + public: + + typedef etl::ratio type; + }; + + //*********************************************************************** + /// ratio_subtract + //*********************************************************************** + template + struct ratio_subtract + { + private: + + static ETL_CONSTANT intmax_t N = (TRatio1::num * TRatio2::den) - (TRatio2::num * TRatio1::den); + static ETL_CONSTANT intmax_t D = TRatio1::den * TRatio2::den;; + + static ETL_CONSTANT intmax_t Num = N / private_ratio::gcd::value; + static ETL_CONSTANT intmax_t Den = D / private_ratio::gcd::value; + + public: + + typedef etl::ratio type; + }; //*********************************************************************** /// Predefined ration types. //*********************************************************************** #if INT_MAX > INT32_MAX - typedef ratio<1, 1000000000000000000000000> yocto; - typedef ratio<1, 1000000000000000000000> zepto; typedef ratio<1, 1000000000000000000> atto; typedef ratio<1, 1000000000000000> femto; typedef ratio<1, 1000000000000> pico; @@ -138,8 +194,6 @@ namespace etl typedef ratio<1000000000000, 1> tera; typedef ratio<1000000000000000, 1> peta; typedef ratio<1000000000000000000, 1> exa; - typedef ratio<1000000000000000000000, 1> zetta; - typedef ratio<1000000000000000000000000, 1> yotta; #endif /// An approximation of PI to 6 digits. diff --git a/test/test_ratio.cpp b/test/test_ratio.cpp new file mode 100644 index 00000000..7f061d49 --- /dev/null +++ b/test/test_ratio.cpp @@ -0,0 +1,133 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Documentation: + +Copyright(c) 2024 John Wellbelove + +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. +******************************************************************************/ + +#include "unit_test_framework.h" + +#include "etl/ratio.h" + +namespace +{ + // Helper to find the greatest common divisor + template + struct gcd + { + static ETL_CONSTANT intmax_t value = gcd::value; + }; + + template + struct gcd + { + static ETL_CONSTANT intmax_t value = A; + }; + + // Helper to find the least common multiple + template + struct lcm + { + static ETL_CONSTANT intmax_t value = (A / gcd::value) * B; + }; + + SUITE(test_ratio) + { + //************************************************************************* + TEST(test_constructor) + { + constexpr intmax_t Num = 20; + constexpr intmax_t Den = 600; + + intmax_t N = Num / gcd::value; + intmax_t D = Den / gcd::value; + + using ratio = etl::ratio; + using ratio_type = ratio::type; + + CHECK_FALSE((std::is_same::value)); + + CHECK_EQUAL(N, ratio::num); + CHECK_EQUAL(D, ratio::den); + + CHECK_EQUAL(N, ratio_type::num); + CHECK_EQUAL(D, ratio_type::den); + } + + //************************************************************************* + TEST(test_predefined_ratios) + { +#if INT_MAX > INT32_MAX + CHECK_EQUAL(etl::atto::num, 1); + CHECK_EQUAL(etl::atto::den, 1000000000000000000); + CHECK_EQUAL(etl::femto::num, 1); + CHECK_EQUAL(etl::femto::den, 1000000000000000); + CHECK_EQUAL(etl::pico::num, 1); + CHECK_EQUAL(etl::pico::den, 1000000000000); +#endif +#if (INT_MAX >= INT32_MAX) + CHECK_EQUAL(etl::nano::num, 1); + CHECK_EQUAL(etl::nano::den, 1000000000); + CHECK_EQUAL(etl::micro::num, 1); + CHECK_EQUAL(etl::micro::den, 1000000); +#endif +#if (INT_MAX >= INT16_MAX) + CHECK_EQUAL(etl::milli::num, 1); + CHECK_EQUAL(etl::milli::den, 1000); + CHECK_EQUAL(etl::centi::num, 1); + CHECK_EQUAL(etl::centi::den, 100); + CHECK_EQUAL(etl::deci::num, 1); + CHECK_EQUAL(etl::deci::den, 10); + CHECK_EQUAL(etl::deca::num, 10); + CHECK_EQUAL(etl::deca::den, 1); + CHECK_EQUAL(etl::hecto::num, 100); + CHECK_EQUAL(etl::hecto::den, 1); + CHECK_EQUAL(etl::kilo::num, 1000); + CHECK_EQUAL(etl::kilo::den, 1); +#endif +#if (INT_MAX >= INT32_MAX) + CHECK_EQUAL(etl::mega::num, 1000000); + CHECK_EQUAL(etl::mega::den, 1); + CHECK_EQUAL(etl::giga::num, 1000000000); + CHECK_EQUAL(etl::giga::den, 1); +#endif + +#if INT_MAX > INT32_MAX + CHECK_EQUAL(etl::tera::num, 1000000000000); + CHECK_EQUAL(etl::tera::den, 1); + CHECK_EQUAL(etl::peta::num, 1000000000000000); + CHECK_EQUAL(etl::peta::den, 1); + CHECK_EQUAL(etl::exa::num, 1000000000000000000); + CHECK_EQUAL(etl::exa::den, 1); +#endif + + double expected_pi = 3.1415926535897931; + double actual_pi = double(etl::ratio_pi::num) / double(etl::ratio_pi::den); + + CHECK_CLOSE(expected_pi, actual_pi, 0.0000003); + } + }; +}