From c42fd3b38d78f745134fb625a4cd1e2004cabad5 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Tue, 30 Jan 2018 17:00:07 +0100 Subject: [PATCH] implement division by scalar for Time and container ops Add division by integer plus related operations over containers. As per C++ convention the division functions themselves will not attempt to handle the case when zero is passed as the divisor. The functions operating on containers will simply return a zero- initialized Time object if the argument container is empty. --- src/timefunc.cpp | 28 ++++++++- src/timefunc.hxx | 58 +++++++++++++++- test/test_timefunc.cpp | 171 +++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 222 insertions(+), 35 deletions(-) diff --git a/src/timefunc.cpp b/src/timefunc.cpp index b84acb8..8fe5000 100644 --- a/src/timefunc.cpp +++ b/src/timefunc.cpp @@ -1112,7 +1112,7 @@ namespace clock { } Time & - Time::scale (const time_t factor) NOEXCEPT + Time::scale (const int64_t factor) NOEXCEPT { this->value.tv_sec *= factor; this->value.tv_nsec *= factor; @@ -1122,6 +1122,32 @@ namespace clock { return *this; } + /* + * Below division code purposely does not attempt to handle divide- + * by-zero just as any other C++ division function does. It is up to + * the caller to ensure that the divisor is not zero. + */ + Time & + Time::divide (const int64_t divisor) NOEXCEPT + { + const long sec = static_cast (this->value.tv_sec ); + int64_t nsec = static_cast (this->value.tv_nsec); + const ldiv_t div = ldiv (sec, divisor); + + if (div.rem != 0) { + nsec += div.rem * TIME_CONST_FACTOR_NANO; + } + + nsec /= divisor; + + this->value.tv_sec = static_cast (div.quot); + this->value.tv_nsec = static_cast (nsec); + + this->carry_nsec (); + + return *this; + } + boost::optional Time::format_iso8601 (const bool utc, const bool date, diff --git a/src/timefunc.hxx b/src/timefunc.hxx index 43c5f20..4b4e3c9 100644 --- a/src/timefunc.hxx +++ b/src/timefunc.hxx @@ -30,6 +30,7 @@ on this file might be covered by the GNU General Public License. #include #include #include +#include #include @@ -445,7 +446,9 @@ namespace clock { inline Time &subtract (const time_t t2) NOEXCEPT { return this->subtract (t2, 0L); }; - Time &scale (const time_t factor) NOEXCEPT; + Time &scale (const int64_t factor) NOEXCEPT; + + Time ÷ (const int64_t divisor) NOEXCEPT; friend int compare (const Time &t1, const Time &t2) NOEXCEPT; @@ -489,13 +492,21 @@ namespace clock { { return this->subtract (t2); } inline Time - operator* (const time_t factor) const NOEXCEPT + operator* (const int64_t factor) const NOEXCEPT { return Time (*this).scale (factor); } inline Time & - operator*= (const time_t factor) NOEXCEPT + operator*= (const int64_t factor) NOEXCEPT { return this->scale (factor); } + inline Time + operator/ (const int64_t divisor) const NOEXCEPT + { return Time (*this).divide (divisor); } + + inline Time & + operator/= (const int64_t divisor) NOEXCEPT + { return this->divide (divisor); } + friend CONSTEXPR bool operator== (const Time &t1, const Time &t2) NOEXCEPT; @@ -531,6 +542,10 @@ namespace clock { operator- (const time_t t1, const Time &t2) NOEXCEPT { return Time (t1) - t2; } + inline Time + operator* (const time_t t1, const Time &t2) NOEXCEPT + { return t2 * t1; } + int compare (const Time &t1, const Time &t2) NOEXCEPT; /* @@ -591,6 +606,43 @@ namespace clock { const enum type::id id = type::real, const enum type::variant var = type::dflt) NOEXCEPT; + template + Time + mean (const ContT &data) + { + Time sum (0, 0); + + if (data.size () == 0) { + return sum; + } + + for (typename ContT::const_iterator it = data.begin (); + it != data.end (); ++it) + { + sum += *it; + }; + + return sum.divide (static_cast (data.size ())); + }; + + template + Time + median (const ContT &data) + { + if (data.size () == 0) { + return zero (); + } + if (data.size () == 1) { + return *data.begin (); + } + + std::vector sorted; + std::copy (data.begin (), data.end (), std::back_inserter (sorted)); + std::sort (sorted.begin (), sorted.end ()); + + return sorted [data.size () / 2]; + }; + } /* [namespace clock] */ } /* [namespace I2n] */ diff --git a/test/test_timefunc.cpp b/test/test_timefunc.cpp index 08ac8ef..9217261 100644 --- a/test/test_timefunc.cpp +++ b/test/test_timefunc.cpp @@ -966,37 +966,6 @@ BOOST_AUTO_TEST_SUITE(Clock) BOOST_CHECK_GT( t2, *t1); } - BOOST_AUTO_TEST_CASE(containers_list) - { - std::list ts; - - ts.push_back (I2n::clock::zero ()); - ts.push_back (I2n::clock::zero ()); - - BOOST_CHECK_EQUAL(ts.size (), 2); - } - - BOOST_AUTO_TEST_CASE(containers_vec) - { - std::vector ts; - - ts.push_back (I2n::clock::zero ()); - ts.push_back (I2n::clock::zero ()); - - BOOST_CHECK_EQUAL(ts.size (), 2); - } - - BOOST_AUTO_TEST_CASE(containers_set) - { - std::set ts; - - ts.insert (I2n::clock::zero ()); - ts.insert (I2n::clock::Time (42, 2187)); - ts.insert (I2n::clock::zero ()); - - BOOST_CHECK_EQUAL(ts.size (), 2); - } - BOOST_AUTO_TEST_CASE(FormatISO8601_T) { I2n::clock::Time t (42, 42); @@ -1107,6 +1076,146 @@ BOOST_AUTO_TEST_SUITE(Clock) BOOST_CHECK_EQUAL(*t3->format_iso8601 (true, false, true, false), in3); } + BOOST_AUTO_TEST_CASE(containers_list) + { + std::list ts; + + ts.push_back (I2n::clock::zero ()); + ts.push_back (I2n::clock::zero ()); + + BOOST_CHECK_EQUAL(ts.size (), 2); + } + + BOOST_AUTO_TEST_CASE(containers_vec) + { + std::vector ts; + + ts.push_back (I2n::clock::zero ()); + ts.push_back (I2n::clock::zero ()); + + BOOST_CHECK_EQUAL(ts.size (), 2); + } + + BOOST_AUTO_TEST_CASE(containers_set) + { + std::set ts; + + ts.insert (I2n::clock::zero ()); + ts.insert (I2n::clock::Time (42, 2187)); + ts.insert (I2n::clock::zero ()); + + BOOST_CHECK_EQUAL(ts.size (), 2); + } + + BOOST_AUTO_TEST_CASE(containers_list_mean) + { + std::list ts; + + ts.push_back (I2n::clock::Time (42, 42)); + ts.push_back (I2n::clock::Time (1337, 1337)); + + BOOST_CHECK_EQUAL(I2n::clock::mean (ts), + I2n::clock::Time (689, 500000689)); + } + + BOOST_AUTO_TEST_CASE(containers_list_mean_zero) + { + std::list ts; + + ts.push_back (I2n::clock::Time (0, 0)); + ts.push_back (I2n::clock::Time (0, 0)); + ts.push_back (I2n::clock::Time (0, 0)); + ts.push_back (I2n::clock::Time (0, 0)); + + BOOST_CHECK_EQUAL(I2n::clock::mean (ts), + I2n::clock::zero ()); + } + + BOOST_AUTO_TEST_CASE(containers_list_mean_empty) + { + std::list ts; + + BOOST_CHECK_EQUAL(I2n::clock::mean (ts), I2n::clock::Time (0, 0)); + } + + BOOST_AUTO_TEST_CASE(containers_set_mean) + { + std::set ts; + + ts.insert (I2n::clock::Time (42)); + ts.insert (I2n::clock::Time (1337)); + ts.insert (I2n::clock::Time (2187)); + + BOOST_CHECK_EQUAL(I2n::clock::mean (ts), + I2n::clock::Time (1188, 666666666)); + } + + BOOST_AUTO_TEST_CASE(containers_set_median_empty) + { + std::set ts; + + BOOST_CHECK_EQUAL(I2n::clock::median (ts), I2n::clock::Time (0, 0)); + } + + BOOST_AUTO_TEST_CASE(containers_set_median_one) + { + std::set ts; + + ts.insert (I2n::clock::Time (42, 0)); + + BOOST_CHECK_EQUAL(I2n::clock::median (ts), + I2n::clock::Time (42, 0)); + } + + BOOST_AUTO_TEST_CASE(containers_set_median_multi) + { + std::set ts; + + ts.insert (I2n::clock::Time (42)); + ts.insert (I2n::clock::Time (1337)); + ts.insert (I2n::clock::Time (2187)); + + BOOST_CHECK_EQUAL(I2n::clock::median (ts), I2n::clock::Time (1337)); + } + + BOOST_AUTO_TEST_CASE(containers_vec_median_multi) + { + std::vector ts; + + ts.push_back (I2n::clock::Time (42)); + ts.push_back (I2n::clock::Time (1337)); + ts.push_back (I2n::clock::Time (2187)); + + BOOST_CHECK_EQUAL(I2n::clock::median (ts), I2n::clock::Time (1337)); + } + + BOOST_AUTO_TEST_CASE(containers_list_median_multi) + { + std::list ts; + + ts.push_back (I2n::clock::Time (42)); + ts.push_back (I2n::clock::Time (1337)); + ts.push_back (I2n::clock::Time (2187)); + ts.push_back (I2n::clock::Time (0xcafebabe)); + ts.push_back (I2n::clock::Time (0xdeadbeef)); + + BOOST_CHECK_EQUAL(I2n::clock::median (ts), I2n::clock::Time (2187)); + } + + BOOST_AUTO_TEST_CASE(containers_list_median_multi_evensize) + { + std::list ts; + + ts.push_back (I2n::clock::Time (42)); + ts.push_back (I2n::clock::Time (1337)); + ts.push_back (I2n::clock::Time (2187)); + ts.push_back (I2n::clock::Time (0xf00d)); + ts.push_back (I2n::clock::Time (0xcafebabe)); + ts.push_back (I2n::clock::Time (0xdeadbeef)); + + BOOST_CHECK_EQUAL(I2n::clock::median (ts), I2n::clock::Time (0xf00d)); + } + BOOST_AUTO_TEST_SUITE_END() /* [Clock] */ BOOST_AUTO_TEST_SUITE_END() -- 1.7.1