diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index a049249b0..0429f5533 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -112,6 +112,7 @@ boost_hana_add_test(sandbox.function) boost_hana_add_test(sandbox.infix) boost_hana_add_test(sandbox.llist) boost_hana_add_test(sandbox.operator) +boost_hana_add_test(sandbox.ratio) boost_hana_add_test(sandbox.sfinae) boost_hana_add_test(sandbox.string) boost_hana_add_test(sandbox.worksheet) diff --git a/test/sandbox/ratio.cpp b/test/sandbox/ratio.cpp new file mode 100644 index 000000000..cf6826f27 --- /dev/null +++ b/test/sandbox/ratio.cpp @@ -0,0 +1,170 @@ +/* +@copyright Louis Dionne 2014 +Distributed under the Boost Software License, Version 1.0. +(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + */ + +#include + + +constexpr struct sign_ { + template + constexpr X operator()(X x) const { + return x < X{0} ? -X{1} : + x == X{0} ? X{0} : + X{1} ; + } +} sign{}; + +constexpr struct abs_ { + template + constexpr X operator()(X x) const { + return x * sign(x); + } +} abs{}; + +constexpr struct gcd_ { + template + constexpr X operator()(X a, X b) const { + return b == X{0} ? a : (*this)(b, a % b); + } +} gcd{}; + +constexpr struct lcm_ { + template + constexpr X operator()(X a, X b) const { + return a == X{0} && b == X{0} ? X{0} : (a / gcd(a, b)) * b; + } +} lcm{}; + +constexpr struct fac_ { + template + constexpr X operator()(X n) const { + return n == X{0} ? X{1} : n * (*this)(n - X{1}); + } +} fac{}; + +template +struct ratio { + T num, den; + + constexpr ratio(T numerator, T denominator = T{1}) + : num{sign(numerator) * sign(denominator) * abs(numerator) / gcd(numerator, denominator)}, + den{abs(denominator) / gcd(numerator, denominator)} + { } + + template + constexpr ratio(ratio other) + : ratio{other.num, other.den} + { } + + constexpr ratio operator+() const { + return {num, den}; + } + + constexpr ratio operator-() const { + return {-num, den}; + } + + template + friend Ostream& operator<<(Ostream& os, ratio x) { + if (x.den == 1) return os << x.num; + else return os << x.num << '/' << x.den; + } +}; + +template +constexpr ratio> operator+(ratio x, ratio y) { + return {x.num * y.den + x.den * y.num, x.den * y.den}; +} + +template +constexpr auto operator-(ratio x, ratio y) { + return x + (-y); +} + +template +constexpr ratio> operator*(ratio x, ratio y) { + return {x.num * y.num, x.den * y.den}; +} + +template +constexpr ratio> operator/(ratio x, ratio y) { + return {x.num * y.den, x.den * y.num}; +} + +template +constexpr bool operator==(ratio x, ratio y) { + return x.num * y.den == y.num * x.den; +} + +template +constexpr bool operator!=(ratio x, ratio y) { + return !(x == y); +} + + +template +constexpr bool operator<(ratio x, ratio y) { + return x.num * y.den < y.num * x.den; +} + +template +constexpr bool operator<=(ratio x, ratio y) { + return !(y < x); +} + +template +constexpr bool operator>(ratio x, ratio y) { + return y < x; +} + +template +constexpr bool operator>=(ratio x, ratio y) { + return !(x < y); +} + + +constexpr ratio operator"" _r(unsigned long long num) { + return {num}; +} + +////////////////////////////////////////////////////////////////////////////// + +static_assert(sign(-100) == -1, ""); +static_assert(sign(0) == 0, ""); +static_assert(sign(20) == 1, ""); + +static_assert(abs(0) == 0, ""); +static_assert(abs(20) == 20, ""); +static_assert(abs(-20) == 20, ""); + +static_assert(gcd(3, 5) == 1, ""); +static_assert(gcd(5, 10) == 5, ""); +static_assert(gcd(8, 6) == 2, ""); +static_assert(gcd(8, 0) == 8, ""); +static_assert(gcd(0, 8) == 8, ""); +static_assert(gcd(0, 0) == 0, ""); + +static_assert(lcm(0, 0) == 0, ""); +static_assert(lcm(1, 0) == 0, ""); +static_assert(lcm(0, 1) == 0, ""); +static_assert(lcm(2, 3) == 6, ""); +static_assert(lcm(2, 4) == 4, ""); + +static_assert(fac(0) == 1, ""); +static_assert(fac(1) == 1 * 1, ""); +static_assert(fac(2) == 1 * 1 * 2, ""); +static_assert(fac(3) == 1 * 1 * 2 * 3, ""); +static_assert(fac(4) == 1 * 1 * 2 * 3 * 4, ""); + + + +constexpr ratio two{4, 2}, three{3}; +static_assert(two + three == 5_r, ""); +static_assert(two * three < 10_r, ""); + +static_assert(1_r / 2_r == ratio{1, 2}, ""); + + +int main() { }