diff --git a/sprout/complex.hpp b/sprout/complex.hpp index 34dfff14..af66e015 100644 --- a/sprout/complex.hpp +++ b/sprout/complex.hpp @@ -1,588 +1,12 @@ #ifndef SPROUT_COMPLEX_HPP #define SPROUT_COMPLEX_HPP -#include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace sprout { - template - class complex; - template - SPROUT_CONSTEXPR T norm(sprout::complex const& x); - // - // complex - // - template - class complex { - public: - typedef T value_type; - private: - T re_; - T im_; - public: - SPROUT_CONSTEXPR complex(T const& re = T(), T const& im = T()) - : re_(re) - , im_(im) - {} - SPROUT_CONSTEXPR complex(complex const&) = default; - template - SPROUT_CONSTEXPR complex(complex const& other) - : re_(other.real()) - , im_(other.imag()) - {} - SPROUT_CONSTEXPR T real() const { - return re_; - } - void real(T re) { - re_ = re; - } - SPROUT_CONSTEXPR T imag() const{ - return im_; - } - void imag(T im) { - im_ = im; - } - complex& operator=(T const& rhs) { - re_ = rhs; - im_ = T(); - return *this; - } - complex& operator+=(T const& rhs) { - re_ += rhs; - return *this; - } - complex& operator-=(T const& rhs) { - re_ -= rhs; - return *this; - } - complex& operator*=(T const& rhs) { - re_ *= rhs; - im_ *= rhs; - return *this; - } - complex& operator/=(T const& rhs) { - re_ /= rhs; - im_ /= rhs; - return *this; - } - complex& operator=(complex const&) = default; - template - complex& operator=(complex const& rhs) { - re_ = rhs.real(); - im_ = rhs.imag(); - return *this; - } - template - complex& operator+=(complex const& rhs) { - re_ += rhs.real(); - im_ += rhs.imag(); - return *this; - } - template - complex& operator-=(complex const& rhs) { - re_ -= rhs.real(); - im_ -= rhs.imag(); - return *this; - } - template - complex& operator*=(complex const& rhs) { - return *this = complex( - re_ * rhs.real() - im_ * rhs.imag(), - re_ * rhs.imag() + im_ * rhs.real() - ); - } - template - complex& operator/=(complex const& rhs) { - T n = sprout::norm(rhs); - return *this = complex( - (re_ * rhs.real() + im_ * rhs.imag()) / n, - (im_ * rhs.real() - re_ * rhs.imag()) / n - ); - } - }; - // 26.4.6, operators: - template - inline SPROUT_CONSTEXPR sprout::complex operator+(sprout::complex const& lhs, sprout::complex const& rhs) { - return sprout::complex( - lhs.real() + rhs.real(), - lhs.imag() + rhs.imag() - ); - } - template - inline SPROUT_CONSTEXPR sprout::complex operator+(sprout::complex const& lhs, T const& rhs) { - return sprout::complex( - lhs.real() + rhs, - lhs.imag() - ); - } - template - inline SPROUT_CONSTEXPR sprout::complex operator+(T const& lhs, sprout::complex const& rhs) { - return sprout::complex( - lhs + rhs.real(), - rhs.imag() - ); - } - template - inline SPROUT_CONSTEXPR sprout::complex operator-(sprout::complex const& lhs, sprout::complex const& rhs) { - return sprout::complex( - lhs.real() - rhs.real(), - lhs.imag() - rhs.imag() - ); - } - template - inline SPROUT_CONSTEXPR sprout::complex operator-(sprout::complex const& lhs, T const& rhs) { - return sprout::complex( - lhs.real() - rhs, - lhs.imag() - ); - } - template - inline SPROUT_CONSTEXPR sprout::complex operator-(T const& lhs, sprout::complex const& rhs) { - return sprout::complex( - lhs - rhs.real(), - -rhs.imag() - ); - } - template - inline SPROUT_CONSTEXPR sprout::complex operator*(sprout::complex const& lhs, sprout::complex const& rhs) { - return sprout::complex( - lhs.real() * rhs.real() - lhs.imag() * rhs.imag(), - lhs.real() * rhs.imag() + lhs.imag() * rhs.real() - ); - } - template - inline SPROUT_CONSTEXPR sprout::complex operator*(sprout::complex const& lhs, T const& rhs) { - return sprout::complex( - lhs.real() * rhs, - lhs.imag() * rhs - ); - } - template - inline SPROUT_CONSTEXPR sprout::complex operator*(T const& lhs, sprout::complex const& rhs) { - return sprout::complex( - lhs * rhs.real(), - lhs * rhs.imag() - ); - } - namespace detail { - template - inline SPROUT_CONSTEXPR sprout::complex divides_impl( - sprout::complex const& lhs, - sprout::complex const& rhs, - T const& n - ) - { - return sprout::complex( - (lhs.real() * rhs.real() + lhs.imag() * rhs.imag()) / n, - (lhs.imag() * rhs.real() - lhs.real() * rhs.imag()) / n - ); - } - template - inline SPROUT_CONSTEXPR sprout::complex divides_impl( - T const& lhs, - sprout::complex const& rhs, - T const& n - ) - { - return sprout::complex( - lhs * rhs.real() / n, - -lhs * rhs.imag() / n - ); - } - } // namespace detail - template - inline SPROUT_CONSTEXPR sprout::complex operator/(sprout::complex const& lhs, sprout::complex const& rhs) { - return sprout::detail::divides_impl(lhs, rhs, sprout::norm(rhs)); - } - template - inline SPROUT_CONSTEXPR sprout::complex operator/(sprout::complex const& lhs, T const& rhs) { - return sprout::complex( - lhs.real() / rhs, - lhs.imag() / rhs - ); - } - template - inline SPROUT_CONSTEXPR sprout::complex operator/(T const& lhs, sprout::complex const& rhs) { - return sprout::detail::divides_impl(lhs, rhs, sprout::norm(rhs)); - } - template - inline SPROUT_CONSTEXPR sprout::complex operator+(sprout::complex const& x) { - return x; - } - template - inline SPROUT_CONSTEXPR sprout::complex operator-(sprout::complex const& x) { - return sprout::complex(-x.real(), -x.imag()); - } - template - inline SPROUT_CONSTEXPR bool operator==(sprout::complex const& lhs, sprout::complex const& rhs) { - return lhs.real() == rhs.real() && lhs.imag() == rhs.imag(); - } - template - inline SPROUT_CONSTEXPR bool operator==(sprout::complex const& lhs, T const& rhs) { - return lhs.real() == rhs && lhs.imag() == T(); - } - template - inline SPROUT_CONSTEXPR bool operator==(T const& lhs, sprout::complex const& rhs) { - return lhs == rhs.real() && T() == rhs.imag(); - } - template - inline SPROUT_CONSTEXPR bool operator!=(sprout::complex const& lhs, sprout::complex const& rhs) { - return !(lhs == rhs); - } - template - inline SPROUT_CONSTEXPR bool operator!=(sprout::complex const& lhs, T const& rhs) { - return !(lhs == rhs); - } - template - inline SPROUT_CONSTEXPR bool operator!=(T const& lhs, sprout::complex const& rhs) { - return !(lhs == rhs); - } - template - std::basic_istream& operator>>(std::basic_istream& lhs, sprout::complex& rhs) { - T re, im; - Char ch; - lhs >> ch; - if (ch == '(') { - lhs >> re >> ch; - if (ch == ',') { - lhs >> im >> ch; - if (ch == ')') { - rhs = sprout::complex(re, im); - } else { - lhs.setstate(std::ios_base::failbit); - } - } else if (ch == ')') { - rhs = re; - } else { - lhs.setstate(std::ios_base::failbit); - } - } else { - lhs.putback(ch); - lhs >> re; - rhs = re; - } - return lhs; - } - template - std::basic_ostream& operator<<(std::basic_ostream& lhs, sprout::complex const& rhs) { - return lhs << '(' << rhs.real() << ',' << rhs.imag() << ')'; - } - // 26.4.7, values: - template - inline SPROUT_CONSTEXPR T real(sprout::complex const& x) { - return x.real(); - } - template - inline SPROUT_CONSTEXPR T imag(sprout::complex const& x) { - return x.imag(); - } - template - inline SPROUT_CONSTEXPR T abs(sprout::complex const& x) { - return sprout::sqrt(sprout::norm(x)); - } - template - inline SPROUT_CONSTEXPR T arg(sprout::complex const& x) { - return sprout::atan2(x.imag(), x.real()); - } - template - inline SPROUT_CONSTEXPR T norm(sprout::complex const& x) { - return x.real() * x.real() + x.imag() * x.imag(); - } - template - inline SPROUT_CONSTEXPR sprout::complex conj(sprout::complex const& x) { - return sprout::complex(x.real(), -x.imag()); - } - namespace detail { - template - inline SPROUT_CONSTEXPR sprout::complex proj_impl(sprout::complex const& x, T const& den) { - return sprout::complex( - T(2) * x.real() / den, - T(2) * x.imag() / den - ); - } - } // detail - template - inline SPROUT_CONSTEXPR sprout::complex proj(sprout::complex const& x) { - return sprout::detail::proj_impl( - x, - sprout::norm(x) + T(1) - ); - } - template - inline SPROUT_CONSTEXPR sprout::complex polar(T const& rho, T const& theta = 0) { - return sprout::complex(rho * sprout::cos(theta), rho * sprout::sin(theta)); - } - // 26.4.8, transcendentals: - template - SPROUT_CONSTEXPR sprout::complex acos(sprout::complex const& x); - template - SPROUT_CONSTEXPR sprout::complex asin(sprout::complex const& x); - template - SPROUT_CONSTEXPR sprout::complex atan(sprout::complex const& x); - template - SPROUT_CONSTEXPR sprout::complex acosh(sprout::complex const& x); - template - SPROUT_CONSTEXPR sprout::complex asinh(sprout::complex const& x); - template - SPROUT_CONSTEXPR sprout::complex atanh(sprout::complex const& x); - template - SPROUT_CONSTEXPR sprout::complex cos(sprout::complex const& x); - template - SPROUT_CONSTEXPR sprout::complex cosh(sprout::complex const& x); - template - SPROUT_CONSTEXPR sprout::complex exp(sprout::complex const& x); - template - SPROUT_CONSTEXPR sprout::complex log(sprout::complex const& x); - template - SPROUT_CONSTEXPR sprout::complex log10(sprout::complex const& x); - template - SPROUT_CONSTEXPR sprout::complex pow(sprout::complex const& x, T const& y); - template - SPROUT_CONSTEXPR sprout::complex pow(sprout::complex const& x, sprout::complex const& y); - template - SPROUT_CONSTEXPR sprout::complex pow(T const& x, sprout::complex const& y); - template - SPROUT_CONSTEXPR sprout::complex sin(sprout::complex const& x); - template - SPROUT_CONSTEXPR sprout::complex sinh(sprout::complex const& x); - template - SPROUT_CONSTEXPR sprout::complex sqrt(sprout::complex const& x); - template - SPROUT_CONSTEXPR sprout::complex tan(sprout::complex const& x); - template - SPROUT_CONSTEXPR sprout::complex tanh(sprout::complex const& x); - namespace detail { - template - inline SPROUT_CONSTEXPR sprout::complex acos_impl(sprout::complex const& t) { - return sprout::complex(sprout::math::half_pi() - t.real(), -t.imag()); - } - } // namespace detail - template - inline SPROUT_CONSTEXPR sprout::complex acos(sprout::complex const& x) { - return sprout::detail::acos_impl(sprout::asin(x)); - } - namespace detail { - template - inline SPROUT_CONSTEXPR sprout::complex asin_impl(sprout::complex const& t) { - return sprout::complex(t.imag(), -t.real()); - } - } // namespace detail - template - inline SPROUT_CONSTEXPR sprout::complex asin(sprout::complex const& x) { - return sprout::detail::asin_impl(sprout::asinh(sprout::complex(-x.imag(), x.real()))); - } - namespace detail { - template - inline SPROUT_CONSTEXPR sprout::complex atan_impl_1( - sprout::complex const& x, - T const& r2, - T const& z, - T const& num, - T const& den - ) - { - return sprout::complex( - T(0.5) * sprout::atan2(T(2) * x.real(), z), - T(0.25) * sprout::log((r2 + num * num) / (r2 + den * den)) - ); - } - template - inline SPROUT_CONSTEXPR sprout::complex atan_impl( - sprout::complex const& x, - T const& r2 - ) - { - return sprout::detail::atan_impl_1( - x, - r2, - T(1) - r2 - x.imag() * x.imag(), - x.imag() + T(1), - x.imag() - T(1) - ); - } - } // namespace detail - template - inline SPROUT_CONSTEXPR sprout::complex atan(sprout::complex const& x) { - return sprout::detail::atan_impl(x, x.real() * x.real()); - } - template - inline SPROUT_CONSTEXPR sprout::complex acosh(sprout::complex const& x) { - return T(2) * sprout::log(sprout::sqrt(T(0.5) * (x + T(1))) + sprout::sqrt(T(0.5) * (x - T(1)))); - } - template - inline SPROUT_CONSTEXPR sprout::complex asinh(sprout::complex const& x) { - return sprout::log( - sprout::sqrt( - sprout::complex( - (x.real() - x.imag()) * (x.real() + x.imag()) + T(1), - T(2) * x.real() * x.imag() - ) - ) - + x - ); - } - namespace detail { - template - inline SPROUT_CONSTEXPR sprout::complex atanh_impl_1( - sprout::complex const& x, - T const& i2, - T const& z, - T const& num, - T const& den - ) - { - return sprout::complex( - T(0.25) * (sprout::log(i2 + num * num) - sprout::log(i2 + den * den)), - T(0.5) * sprout::atan2(T(2) * x.imag(), z) - ); - } - template - inline SPROUT_CONSTEXPR sprout::complex atanh_impl( - sprout::complex const& x, - T const& i2 - ) - { - return sprout::detail::atanh_impl_1( - x, - i2, - T(1) - i2 - x.real() * x.real(), - T(1) + x.imag(), - T(1) - x.imag() - ); - } - } // namespace detail - template - inline SPROUT_CONSTEXPR sprout::complex atanh(sprout::complex const& x) { - return sprout::detail::atanh_impl(x, x.imag() * x.imag()); - } - template - inline SPROUT_CONSTEXPR sprout::complex cos(sprout::complex const& x) { - return sprout::complex( - sprout::cos(x.real()) * sprout::cosh(x.imag()), - -(sprout::sin(x.real()) * sprout::sinh(x.imag())) - ); - } - template - inline SPROUT_CONSTEXPR sprout::complex cosh(sprout::complex const& x) { - return sprout::complex( - sprout::cosh(x.real()) * sprout::cos(x.imag()), - sprout::sinh(x.real()) * sprout::sin(x.imag()) - ); - } - template - inline SPROUT_CONSTEXPR sprout::complex exp(sprout::complex const& x) { - return sprout::polar(sprout::exp(x.real()), x.imag()); - } - template - inline SPROUT_CONSTEXPR sprout::complex log(sprout::complex const& x) { - return sprout::complex(sprout::log(sprout::abs(x)), sprout::arg(x)); - } - template - inline SPROUT_CONSTEXPR sprout::complex log10(sprout::complex const& x) { - return sprout::log(x) / sprout::log(T(10)); - } - namespace detail { - template - inline SPROUT_CONSTEXPR sprout::complex pow_impl(sprout::complex const& t, T const& y) { - return sprout::polar(sprout::exp(y * t.real()), y * t.imag()); - } - } // namespace detail - template - inline SPROUT_CONSTEXPR sprout::complex pow(sprout::complex const& x, T const& y) { - return x == T() ? T() - : x.imag() == T() && x.real() > T() ? sprout::pow(x.real(), y) - : sprout::detail::pow_impl(sprout::log(x), y) - ; - } - template - inline SPROUT_CONSTEXPR sprout::complex pow(sprout::complex const& x, sprout::complex const& y) { - return x == T() ? T() - : sprout::exp(y * sprout::log(x)) - ; - } - template - inline SPROUT_CONSTEXPR sprout::complex pow(T const& x, sprout::complex const& y) { - return x > T() ? sprout::polar(sprout::pow(x, y.real()), y.imag() * sprout::log(x)) - : sprout::pow(sprout::complex(x), y) - ; - } - template - inline SPROUT_CONSTEXPR sprout::complex sin(sprout::complex const& x) { - return sprout::complex( - sprout::sin(x.real()) * sprout::cosh(x.imag()), - sprout::cos(x.real()) * sprout::sinh(x.imag()) - ); - } - template - inline SPROUT_CONSTEXPR sprout::complex sinh(sprout::complex const& x) { - return sprout::complex( - sprout::sinh(x.real()) * sprout::cos(x.imag()), - sprout::cosh(x.real()) * sprout::sin(x.imag()) - ); - } - namespace detail { - template - inline SPROUT_CONSTEXPR sprout::complex sqrt_impl_1(sprout::complex const& x, T const& t) { - return sprout::complex(t, x.imag() < T() ? -t : t); - } - template - inline SPROUT_CONSTEXPR sprout::complex sqrt_impl_2_1(sprout::complex const& x, T const& t, T const& u) { - return x.real() > T() ? sprout::complex(u, x.imag() / t) - : sprout::complex(sprout::abs(x.imag()) / t, x.imag() < T() ? -u : u) - ; - } - template - inline SPROUT_CONSTEXPR sprout::complex sqrt_impl_2(sprout::complex const& x, T const& t) { - return sprout::detail::sqrt_impl_2_1(x, t, t / 2); - } - } // namespace detail - template - inline SPROUT_CONSTEXPR sprout::complex sqrt(sprout::complex const& x) { - return x.real() == T() ? sprout::detail::sqrt_impl_1(x, sprout::sqrt(abs(x.imag()) / 2)) - : sprout::detail::sqrt_impl_2(x, sprout::sqrt(2 * (sprout::abs(x) + sprout::abs(x.real())))) - ; - } - template - inline SPROUT_CONSTEXPR sprout::complex tan(sprout::complex const& x) { - return sprout::sin(x) / sprout::cos(x); - } - template - inline SPROUT_CONSTEXPR sprout::complex tanh(sprout::complex const& x) { - return sprout::sinh(x) / sprout::cosh(x); - } - - template - inline SPROUT_CONSTEXPR sprout::complex ceil(sprout::complex const& x) { - return sprout::complex(sprout::ceil(x.real()), sprout::ceil(x.imag())); - } - template - inline SPROUT_CONSTEXPR sprout::complex floor(sprout::complex const& x) { - return sprout::complex(sprout::floor(x.real()), sprout::floor(x.imag())); - } - template - inline SPROUT_CONSTEXPR sprout::complex trunc(sprout::complex const& x) { - return sprout::complex(sprout::trunc(x.real()), sprout::trunc(x.imag())); - } - template - inline SPROUT_CONSTEXPR sprout::complex round(sprout::complex const& x) { - return sprout::complex(sprout::round(x.real()), sprout::round(x.imag())); - } -} // namespace sprout +#include +#include +#include +#include +#include +#include #endif // #ifndef SPROUT_COMPLEX_HPP diff --git a/sprout/complex/complex.hpp b/sprout/complex/complex.hpp new file mode 100644 index 00000000..d443b5f0 --- /dev/null +++ b/sprout/complex/complex.hpp @@ -0,0 +1,110 @@ +#ifndef SPROUT_COMPLEX_COMPLEX_HPP +#define SPROUT_COMPLEX_COMPLEX_HPP + +#include + +namespace sprout { + template + class complex; + + namespace detail { + template + inline SPROUT_CONSTEXPR T complex_norm(sprout::complex const& x) { + return x.real() * x.real() + x.imag() * x.imag(); + } + } // namespace detail + + // + // complex + // + template + class complex { + public: + typedef T value_type; + private: + T re_; + T im_; + public: + SPROUT_CONSTEXPR complex(T const& re = T(), T const& im = T()) + : re_(re) + , im_(im) + {} + SPROUT_CONSTEXPR complex(complex const&) = default; + template + SPROUT_CONSTEXPR complex(complex const& other) + : re_(other.real()) + , im_(other.imag()) + {} + SPROUT_CONSTEXPR T real() const { + return re_; + } + void real(T re) { + re_ = re; + } + SPROUT_CONSTEXPR T imag() const{ + return im_; + } + void imag(T im) { + im_ = im; + } + complex& operator=(T const& rhs) { + re_ = rhs; + im_ = T(); + return *this; + } + complex& operator+=(T const& rhs) { + re_ += rhs; + return *this; + } + complex& operator-=(T const& rhs) { + re_ -= rhs; + return *this; + } + complex& operator*=(T const& rhs) { + re_ *= rhs; + im_ *= rhs; + return *this; + } + complex& operator/=(T const& rhs) { + re_ /= rhs; + im_ /= rhs; + return *this; + } + complex& operator=(complex const&) = default; + template + complex& operator=(complex const& rhs) { + re_ = rhs.real(); + im_ = rhs.imag(); + return *this; + } + template + complex& operator+=(complex const& rhs) { + re_ += rhs.real(); + im_ += rhs.imag(); + return *this; + } + template + complex& operator-=(complex const& rhs) { + re_ -= rhs.real(); + im_ -= rhs.imag(); + return *this; + } + template + complex& operator*=(complex const& rhs) { + return *this = complex( + re_ * rhs.real() - im_ * rhs.imag(), + re_ * rhs.imag() + im_ * rhs.real() + ); + } + template + complex& operator/=(complex const& rhs) { + T n = sprout::detail::complex_norm(rhs); + return *this = complex( + (re_ * rhs.real() + im_ * rhs.imag()) / n, + (im_ * rhs.real() - re_ * rhs.imag()) / n + ); + } + }; +} // namespace sprout + +#endif // #ifndef SPROUT_COMPLEX_COMPLEX_HPP diff --git a/sprout/complex/hash.hpp b/sprout/complex/hash.hpp new file mode 100644 index 00000000..d4ef00da --- /dev/null +++ b/sprout/complex/hash.hpp @@ -0,0 +1,19 @@ +#ifndef SPROUT_COMPLEX_HASH_HPP +#define SPROUT_COMPLEX_HASH_HPP + +#include +#include +#include +#include + +namespace sprout { + // + // hash_value + // + template + inline SPROUT_CONSTEXPR std::size_t hash_value(sprout::complex const& v) { + return sprout::hash_values(v.real(), v.imag()); + } +} // namespace sprout + +#endif // #ifndef SPROUT_COMPLEX_HASH_HPP diff --git a/sprout/complex/nearest.hpp b/sprout/complex/nearest.hpp new file mode 100644 index 00000000..ebfdfa9b --- /dev/null +++ b/sprout/complex/nearest.hpp @@ -0,0 +1,30 @@ +#ifndef SPROUT_COMPLEX_NEAREST_HPP +#define SPROUT_COMPLEX_NEAREST_HPP + +#include +#include +#include +#include +#include +#include + +namespace sprout { + template + inline SPROUT_CONSTEXPR sprout::complex ceil(sprout::complex const& x) { + return sprout::complex(sprout::ceil(x.real()), sprout::ceil(x.imag())); + } + template + inline SPROUT_CONSTEXPR sprout::complex floor(sprout::complex const& x) { + return sprout::complex(sprout::floor(x.real()), sprout::floor(x.imag())); + } + template + inline SPROUT_CONSTEXPR sprout::complex trunc(sprout::complex const& x) { + return sprout::complex(sprout::trunc(x.real()), sprout::trunc(x.imag())); + } + template + inline SPROUT_CONSTEXPR sprout::complex round(sprout::complex const& x) { + return sprout::complex(sprout::round(x.real()), sprout::round(x.imag())); + } +} // namespace sprout + +#endif // #ifndef SPROUT_COMPLEX_NEAREST_HPP diff --git a/sprout/complex/operators.hpp b/sprout/complex/operators.hpp new file mode 100644 index 00000000..92776dba --- /dev/null +++ b/sprout/complex/operators.hpp @@ -0,0 +1,179 @@ +#ifndef SPROUT_COMPLEX_OPERATORS_HPP +#define SPROUT_COMPLEX_OPERATORS_HPP + +#include +#include +#include +#include + +namespace sprout { + // 26.4.6, operators: + template + inline SPROUT_CONSTEXPR sprout::complex operator+(sprout::complex const& lhs, sprout::complex const& rhs) { + return sprout::complex( + lhs.real() + rhs.real(), + lhs.imag() + rhs.imag() + ); + } + template + inline SPROUT_CONSTEXPR sprout::complex operator+(sprout::complex const& lhs, T const& rhs) { + return sprout::complex( + lhs.real() + rhs, + lhs.imag() + ); + } + template + inline SPROUT_CONSTEXPR sprout::complex operator+(T const& lhs, sprout::complex const& rhs) { + return sprout::complex( + lhs + rhs.real(), + rhs.imag() + ); + } + template + inline SPROUT_CONSTEXPR sprout::complex operator-(sprout::complex const& lhs, sprout::complex const& rhs) { + return sprout::complex( + lhs.real() - rhs.real(), + lhs.imag() - rhs.imag() + ); + } + template + inline SPROUT_CONSTEXPR sprout::complex operator-(sprout::complex const& lhs, T const& rhs) { + return sprout::complex( + lhs.real() - rhs, + lhs.imag() + ); + } + template + inline SPROUT_CONSTEXPR sprout::complex operator-(T const& lhs, sprout::complex const& rhs) { + return sprout::complex( + lhs - rhs.real(), + -rhs.imag() + ); + } + template + inline SPROUT_CONSTEXPR sprout::complex operator*(sprout::complex const& lhs, sprout::complex const& rhs) { + return sprout::complex( + lhs.real() * rhs.real() - lhs.imag() * rhs.imag(), + lhs.real() * rhs.imag() + lhs.imag() * rhs.real() + ); + } + template + inline SPROUT_CONSTEXPR sprout::complex operator*(sprout::complex const& lhs, T const& rhs) { + return sprout::complex( + lhs.real() * rhs, + lhs.imag() * rhs + ); + } + template + inline SPROUT_CONSTEXPR sprout::complex operator*(T const& lhs, sprout::complex const& rhs) { + return sprout::complex( + lhs * rhs.real(), + lhs * rhs.imag() + ); + } + namespace detail { + template + inline SPROUT_CONSTEXPR sprout::complex divides_impl( + sprout::complex const& lhs, + sprout::complex const& rhs, + T const& n + ) + { + return sprout::complex( + (lhs.real() * rhs.real() + lhs.imag() * rhs.imag()) / n, + (lhs.imag() * rhs.real() - lhs.real() * rhs.imag()) / n + ); + } + template + inline SPROUT_CONSTEXPR sprout::complex divides_impl( + T const& lhs, + sprout::complex const& rhs, + T const& n + ) + { + return sprout::complex( + lhs * rhs.real() / n, + -lhs * rhs.imag() / n + ); + } + } // namespace detail + template + inline SPROUT_CONSTEXPR sprout::complex operator/(sprout::complex const& lhs, sprout::complex const& rhs) { + return sprout::detail::divides_impl(lhs, rhs, sprout::detail::complex_norm(rhs)); + } + template + inline SPROUT_CONSTEXPR sprout::complex operator/(sprout::complex const& lhs, T const& rhs) { + return sprout::complex( + lhs.real() / rhs, + lhs.imag() / rhs + ); + } + template + inline SPROUT_CONSTEXPR sprout::complex operator/(T const& lhs, sprout::complex const& rhs) { + return sprout::detail::divides_impl(lhs, rhs, sprout::detail::complex_norm(rhs)); + } + template + inline SPROUT_CONSTEXPR sprout::complex operator+(sprout::complex const& x) { + return x; + } + template + inline SPROUT_CONSTEXPR sprout::complex operator-(sprout::complex const& x) { + return sprout::complex(-x.real(), -x.imag()); + } + template + inline SPROUT_CONSTEXPR bool operator==(sprout::complex const& lhs, sprout::complex const& rhs) { + return lhs.real() == rhs.real() && lhs.imag() == rhs.imag(); + } + template + inline SPROUT_CONSTEXPR bool operator==(sprout::complex const& lhs, T const& rhs) { + return lhs.real() == rhs && lhs.imag() == T(); + } + template + inline SPROUT_CONSTEXPR bool operator==(T const& lhs, sprout::complex const& rhs) { + return lhs == rhs.real() && T() == rhs.imag(); + } + template + inline SPROUT_CONSTEXPR bool operator!=(sprout::complex const& lhs, sprout::complex const& rhs) { + return !(lhs == rhs); + } + template + inline SPROUT_CONSTEXPR bool operator!=(sprout::complex const& lhs, T const& rhs) { + return !(lhs == rhs); + } + template + inline SPROUT_CONSTEXPR bool operator!=(T const& lhs, sprout::complex const& rhs) { + return !(lhs == rhs); + } + template + std::basic_istream& operator>>(std::basic_istream& lhs, sprout::complex& rhs) { + T re, im; + Char ch; + lhs >> ch; + if (ch == '(') { + lhs >> re >> ch; + if (ch == ',') { + lhs >> im >> ch; + if (ch == ')') { + rhs = sprout::complex(re, im); + } else { + lhs.setstate(std::ios_base::failbit); + } + } else if (ch == ')') { + rhs = re; + } else { + lhs.setstate(std::ios_base::failbit); + } + } else { + lhs.putback(ch); + lhs >> re; + rhs = re; + } + return lhs; + } + template + std::basic_ostream& operator<<(std::basic_ostream& lhs, sprout::complex const& rhs) { + return lhs << '(' << rhs.real() << ',' << rhs.imag() << ')'; + } +} // namespace sprout + +#endif // #ifndef SPROUT_COMPLEX_OPERATORS_HPP diff --git a/sprout/complex/transcendentals.hpp b/sprout/complex/transcendentals.hpp new file mode 100644 index 00000000..81f3e085 --- /dev/null +++ b/sprout/complex/transcendentals.hpp @@ -0,0 +1,261 @@ +#ifndef SPROUT_COMPLEX_TRANSCENDENTALS_HPP +#define SPROUT_COMPLEX_TRANSCENDENTALS_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace sprout { + // 26.4.8, transcendentals: + template + SPROUT_CONSTEXPR sprout::complex acos(sprout::complex const& x); + template + SPROUT_CONSTEXPR sprout::complex asin(sprout::complex const& x); + template + SPROUT_CONSTEXPR sprout::complex atan(sprout::complex const& x); + template + SPROUT_CONSTEXPR sprout::complex acosh(sprout::complex const& x); + template + SPROUT_CONSTEXPR sprout::complex asinh(sprout::complex const& x); + template + SPROUT_CONSTEXPR sprout::complex atanh(sprout::complex const& x); + template + SPROUT_CONSTEXPR sprout::complex cos(sprout::complex const& x); + template + SPROUT_CONSTEXPR sprout::complex cosh(sprout::complex const& x); + template + SPROUT_CONSTEXPR sprout::complex exp(sprout::complex const& x); + template + SPROUT_CONSTEXPR sprout::complex log(sprout::complex const& x); + template + SPROUT_CONSTEXPR sprout::complex log10(sprout::complex const& x); + template + SPROUT_CONSTEXPR sprout::complex pow(sprout::complex const& x, T const& y); + template + SPROUT_CONSTEXPR sprout::complex pow(sprout::complex const& x, sprout::complex const& y); + template + SPROUT_CONSTEXPR sprout::complex pow(T const& x, sprout::complex const& y); + template + SPROUT_CONSTEXPR sprout::complex sin(sprout::complex const& x); + template + SPROUT_CONSTEXPR sprout::complex sinh(sprout::complex const& x); + template + SPROUT_CONSTEXPR sprout::complex sqrt(sprout::complex const& x); + template + SPROUT_CONSTEXPR sprout::complex tan(sprout::complex const& x); + template + SPROUT_CONSTEXPR sprout::complex tanh(sprout::complex const& x); + namespace detail { + template + inline SPROUT_CONSTEXPR sprout::complex acos_impl(sprout::complex const& t) { + return sprout::complex(sprout::math::half_pi() - t.real(), -t.imag()); + } + } // namespace detail + template + inline SPROUT_CONSTEXPR sprout::complex acos(sprout::complex const& x) { + return sprout::detail::acos_impl(sprout::asin(x)); + } + namespace detail { + template + inline SPROUT_CONSTEXPR sprout::complex asin_impl(sprout::complex const& t) { + return sprout::complex(t.imag(), -t.real()); + } + } // namespace detail + template + inline SPROUT_CONSTEXPR sprout::complex asin(sprout::complex const& x) { + return sprout::detail::asin_impl(sprout::asinh(sprout::complex(-x.imag(), x.real()))); + } + namespace detail { + template + inline SPROUT_CONSTEXPR sprout::complex atan_impl_1( + sprout::complex const& x, + T const& r2, + T const& z, + T const& num, + T const& den + ) + { + return sprout::complex( + T(0.5) * sprout::atan2(T(2) * x.real(), z), + T(0.25) * sprout::log((r2 + num * num) / (r2 + den * den)) + ); + } + template + inline SPROUT_CONSTEXPR sprout::complex atan_impl( + sprout::complex const& x, + T const& r2 + ) + { + return sprout::detail::atan_impl_1( + x, + r2, + T(1) - r2 - x.imag() * x.imag(), + x.imag() + T(1), + x.imag() - T(1) + ); + } + } // namespace detail + template + inline SPROUT_CONSTEXPR sprout::complex atan(sprout::complex const& x) { + return sprout::detail::atan_impl(x, x.real() * x.real()); + } + template + inline SPROUT_CONSTEXPR sprout::complex acosh(sprout::complex const& x) { + return T(2) * sprout::log(sprout::sqrt(T(0.5) * (x + T(1))) + sprout::sqrt(T(0.5) * (x - T(1)))); + } + template + inline SPROUT_CONSTEXPR sprout::complex asinh(sprout::complex const& x) { + return sprout::log( + sprout::sqrt( + sprout::complex( + (x.real() - x.imag()) * (x.real() + x.imag()) + T(1), + T(2) * x.real() * x.imag() + ) + ) + + x + ); + } + namespace detail { + template + inline SPROUT_CONSTEXPR sprout::complex atanh_impl_1( + sprout::complex const& x, + T const& i2, + T const& z, + T const& num, + T const& den + ) + { + return sprout::complex( + T(0.25) * (sprout::log(i2 + num * num) - sprout::log(i2 + den * den)), + T(0.5) * sprout::atan2(T(2) * x.imag(), z) + ); + } + template + inline SPROUT_CONSTEXPR sprout::complex atanh_impl( + sprout::complex const& x, + T const& i2 + ) + { + return sprout::detail::atanh_impl_1( + x, + i2, + T(1) - i2 - x.real() * x.real(), + T(1) + x.imag(), + T(1) - x.imag() + ); + } + } // namespace detail + template + inline SPROUT_CONSTEXPR sprout::complex atanh(sprout::complex const& x) { + return sprout::detail::atanh_impl(x, x.imag() * x.imag()); + } + template + inline SPROUT_CONSTEXPR sprout::complex cos(sprout::complex const& x) { + return sprout::complex( + sprout::cos(x.real()) * sprout::cosh(x.imag()), + -(sprout::sin(x.real()) * sprout::sinh(x.imag())) + ); + } + template + inline SPROUT_CONSTEXPR sprout::complex cosh(sprout::complex const& x) { + return sprout::complex( + sprout::cosh(x.real()) * sprout::cos(x.imag()), + sprout::sinh(x.real()) * sprout::sin(x.imag()) + ); + } + template + inline SPROUT_CONSTEXPR sprout::complex exp(sprout::complex const& x) { + return sprout::polar(sprout::exp(x.real()), x.imag()); + } + template + inline SPROUT_CONSTEXPR sprout::complex log(sprout::complex const& x) { + return sprout::complex(sprout::log(sprout::abs(x)), sprout::arg(x)); + } + template + inline SPROUT_CONSTEXPR sprout::complex log10(sprout::complex const& x) { + return sprout::log(x) / sprout::log(T(10)); + } + namespace detail { + template + inline SPROUT_CONSTEXPR sprout::complex pow_impl(sprout::complex const& t, T const& y) { + return sprout::polar(sprout::exp(y * t.real()), y * t.imag()); + } + } // namespace detail + template + inline SPROUT_CONSTEXPR sprout::complex pow(sprout::complex const& x, T const& y) { + return x == T() ? T() + : x.imag() == T() && x.real() > T() ? sprout::pow(x.real(), y) + : sprout::detail::pow_impl(sprout::log(x), y) + ; + } + template + inline SPROUT_CONSTEXPR sprout::complex pow(sprout::complex const& x, sprout::complex const& y) { + return x == T() ? T() + : sprout::exp(y * sprout::log(x)) + ; + } + template + inline SPROUT_CONSTEXPR sprout::complex pow(T const& x, sprout::complex const& y) { + return x > T() ? sprout::polar(sprout::pow(x, y.real()), y.imag() * sprout::log(x)) + : sprout::pow(sprout::complex(x), y) + ; + } + template + inline SPROUT_CONSTEXPR sprout::complex sin(sprout::complex const& x) { + return sprout::complex( + sprout::sin(x.real()) * sprout::cosh(x.imag()), + sprout::cos(x.real()) * sprout::sinh(x.imag()) + ); + } + template + inline SPROUT_CONSTEXPR sprout::complex sinh(sprout::complex const& x) { + return sprout::complex( + sprout::sinh(x.real()) * sprout::cos(x.imag()), + sprout::cosh(x.real()) * sprout::sin(x.imag()) + ); + } + namespace detail { + template + inline SPROUT_CONSTEXPR sprout::complex sqrt_impl_1(sprout::complex const& x, T const& t) { + return sprout::complex(t, x.imag() < T() ? -t : t); + } + template + inline SPROUT_CONSTEXPR sprout::complex sqrt_impl_2_1(sprout::complex const& x, T const& t, T const& u) { + return x.real() > T() ? sprout::complex(u, x.imag() / t) + : sprout::complex(sprout::abs(x.imag()) / t, x.imag() < T() ? -u : u) + ; + } + template + inline SPROUT_CONSTEXPR sprout::complex sqrt_impl_2(sprout::complex const& x, T const& t) { + return sprout::detail::sqrt_impl_2_1(x, t, t / 2); + } + } // namespace detail + template + inline SPROUT_CONSTEXPR sprout::complex sqrt(sprout::complex const& x) { + return x.real() == T() ? sprout::detail::sqrt_impl_1(x, sprout::sqrt(abs(x.imag()) / 2)) + : sprout::detail::sqrt_impl_2(x, sprout::sqrt(2 * (sprout::abs(x) + sprout::abs(x.real())))) + ; + } + template + inline SPROUT_CONSTEXPR sprout::complex tan(sprout::complex const& x) { + return sprout::sin(x) / sprout::cos(x); + } + template + inline SPROUT_CONSTEXPR sprout::complex tanh(sprout::complex const& x) { + return sprout::sinh(x) / sprout::cosh(x); + } +} // namespace sprout + +#endif // #ifndef SPROUT_COMPLEX_TRANSCENDENTALS_HPP diff --git a/sprout/complex/values.hpp b/sprout/complex/values.hpp new file mode 100644 index 00000000..ed715886 --- /dev/null +++ b/sprout/complex/values.hpp @@ -0,0 +1,63 @@ +#ifndef SPROUT_COMPLEX_VALUES_HPP +#define SPROUT_COMPLEX_VALUES_HPP + +#include +#include +#include +#include +#include +#include +#include + +namespace sprout { + template + SPROUT_CONSTEXPR T norm(sprout::complex const& x); + + // 26.4.7, values: + template + inline SPROUT_CONSTEXPR T real(sprout::complex const& x) { + return x.real(); + } + template + inline SPROUT_CONSTEXPR T imag(sprout::complex const& x) { + return x.imag(); + } + template + inline SPROUT_CONSTEXPR T abs(sprout::complex const& x) { + return sprout::sqrt(sprout::norm(x)); + } + template + inline SPROUT_CONSTEXPR T arg(sprout::complex const& x) { + return sprout::atan2(x.imag(), x.real()); + } + template + inline SPROUT_CONSTEXPR T norm(sprout::complex const& x) { + return x.real() * x.real() + x.imag() * x.imag(); + } + template + inline SPROUT_CONSTEXPR sprout::complex conj(sprout::complex const& x) { + return sprout::complex(x.real(), -x.imag()); + } + namespace detail { + template + inline SPROUT_CONSTEXPR sprout::complex proj_impl(sprout::complex const& x, T const& den) { + return sprout::complex( + T(2) * x.real() / den, + T(2) * x.imag() / den + ); + } + } // detail + template + inline SPROUT_CONSTEXPR sprout::complex proj(sprout::complex const& x) { + return sprout::detail::proj_impl( + x, + sprout::norm(x) + T(1) + ); + } + template + inline SPROUT_CONSTEXPR sprout::complex polar(T const& rho, T const& theta = 0) { + return sprout::complex(rho * sprout::cos(theta), rho * sprout::sin(theta)); + } +} // namespace sprout + +#endif // #ifndef SPROUT_COMPLEX_VALUES_HPP diff --git a/sprout/functional/hash/hash.hpp b/sprout/functional/hash/hash.hpp index 446f4702..8645adbb 100644 --- a/sprout/functional/hash/hash.hpp +++ b/sprout/functional/hash/hash.hpp @@ -10,27 +10,76 @@ #include namespace sprout { + namespace hash_detail { + struct enable_hash_value { + public: + typedef std::size_t type; + }; + + template + struct basic_numbers {}; + template + struct basic_numbers< + T, + typename std::enable_if< + (std::is_integral::value && sizeof(T) <= sizeof(std::size_t)) + >::type + > + : public sprout::hash_detail::enable_hash_value + {}; + + template + struct long_numbers {}; + template + struct long_numbers< + T, + typename std::enable_if< + (std::is_integral::value && std::is_signed::value && sizeof(T) > sizeof(std::size_t)) + >::type + > + : public sprout::hash_detail::enable_hash_value + {}; + + template + struct ulong_numbers {}; + template + struct ulong_numbers< + T, + typename std::enable_if< + (std::is_integral::value && std::is_unsigned::value && sizeof(T) > sizeof(std::size_t)) + >::type + > + : public sprout::hash_detail::enable_hash_value + {}; + + template + struct float_numbers {}; + template + struct float_numbers< + T, + typename std::enable_if< + (std::is_floating_point::value) + >::type + > + : public sprout::hash_detail::enable_hash_value + {}; + } // namespace hash_detail + // // hash_value // - inline SPROUT_CONSTEXPR std::size_t hash_value(bool v); - inline SPROUT_CONSTEXPR std::size_t hash_value(char v); - inline SPROUT_CONSTEXPR std::size_t hash_value(unsigned char v); - inline SPROUT_CONSTEXPR std::size_t hash_value(signed char v); - inline SPROUT_CONSTEXPR std::size_t hash_value(char16_t v); - inline SPROUT_CONSTEXPR std::size_t hash_value(char32_t v); - inline SPROUT_CONSTEXPR std::size_t hash_value(wchar_t v); - inline SPROUT_CONSTEXPR std::size_t hash_value(short v); - inline SPROUT_CONSTEXPR std::size_t hash_value(unsigned short v); - inline SPROUT_CONSTEXPR std::size_t hash_value(int v); - inline SPROUT_CONSTEXPR std::size_t hash_value(unsigned int v); - inline SPROUT_CONSTEXPR std::size_t hash_value(long v); - inline SPROUT_CONSTEXPR std::size_t hash_value(unsigned long v); - inline SPROUT_CONSTEXPR std::size_t hash_value(long long v); - inline SPROUT_CONSTEXPR std::size_t hash_value(unsigned long long v); - //inline SPROUT_CONSTEXPR std::size_t hash_value(float v); - //inline SPROUT_CONSTEXPR std::size_t hash_value(double v); - //inline SPROUT_CONSTEXPR std::size_t hash_value(long double v); + template + inline SPROUT_CONSTEXPR typename sprout::hash_detail::basic_numbers::type + hash_value(T); + template + inline SPROUT_CONSTEXPR typename sprout::hash_detail::long_numbers::type + hash_value(T); + template + inline SPROUT_CONSTEXPR typename sprout::hash_detail::ulong_numbers::type + hash_value(T); +// template +// inline SPROUT_CONSTEXPR typename sprout::hash_detail::float_numbers::type +// hash_value(T); template< typename T, typename sprout::enabler_if::type>::value>::type @@ -104,51 +153,26 @@ namespace sprout { // // hash_value // - inline SPROUT_CONSTEXPR std::size_t hash_value(bool v) { + template + inline SPROUT_CONSTEXPR typename sprout::hash_detail::basic_numbers::type + hash_value(T v) { return static_cast(v); } - inline SPROUT_CONSTEXPR std::size_t hash_value(char v) { - return static_cast(v); - } - inline SPROUT_CONSTEXPR std::size_t hash_value(unsigned char v) { - return static_cast(v); - } - inline SPROUT_CONSTEXPR std::size_t hash_value(signed char v) { - return static_cast(v); - } - inline SPROUT_CONSTEXPR std::size_t hash_value(char16_t v) { - return static_cast(v); - } - inline SPROUT_CONSTEXPR std::size_t hash_value(char32_t v) { - return static_cast(v); - } - inline SPROUT_CONSTEXPR std::size_t hash_value(wchar_t v) { - return static_cast(v); - } - inline SPROUT_CONSTEXPR std::size_t hash_value(short v) { - return static_cast(v); - } - inline SPROUT_CONSTEXPR std::size_t hash_value(unsigned short v) { - return static_cast(v); - } - inline SPROUT_CONSTEXPR std::size_t hash_value(int v) { - return static_cast(v); - } - inline SPROUT_CONSTEXPR std::size_t hash_value(unsigned int v) { - return static_cast(v); - } - inline SPROUT_CONSTEXPR std::size_t hash_value(long v) { - return static_cast(v); - } - inline SPROUT_CONSTEXPR std::size_t hash_value(unsigned long v) { - return static_cast(v); - } - inline SPROUT_CONSTEXPR std::size_t hash_value(long long v) { + template + inline SPROUT_CONSTEXPR typename sprout::hash_detail::long_numbers::type + hash_value(T v) { return sprout::hash_detail::hash_value_signed(v); } - inline SPROUT_CONSTEXPR std::size_t hash_value(unsigned long long v) { + template + inline SPROUT_CONSTEXPR typename sprout::hash_detail::ulong_numbers::type + hash_value(T v) { return sprout::hash_detail::hash_value_unsigned(v); } +// template +// inline SPROUT_CONSTEXPR typename sprout::hash_detail::float_numbers::type +// hash_value(T v) { +// return sprout::hash_detail::hash_value_float(v); +// } template< typename T, typename sprout::enabler_if::type>::value>::type = sprout::enabler diff --git a/sprout/pit/hash.hpp b/sprout/pit/hash.hpp index fd78832a..5a35f759 100644 --- a/sprout/pit/hash.hpp +++ b/sprout/pit/hash.hpp @@ -9,7 +9,7 @@ namespace sprout { template inline SPROUT_CONSTEXPR std::size_t hash_value(sprout::pit const& v) { - return sprout::to_hash(v.elem); + return sprout::hash_range(v.begin(), v.end()); } } // namespace sprout diff --git a/sprout/rational.hpp b/sprout/rational.hpp index df1da97c..8f0794db 100644 --- a/sprout/rational.hpp +++ b/sprout/rational.hpp @@ -1,725 +1,14 @@ #ifndef SPROUT_RATIONAL_HPP #define SPROUT_RATIONAL_HPP -#include -#include -#include -#include -#include #include -#include -#include -#include -#include - -namespace sprout { - // - // bad_rational - // - class bad_rational - : public std::domain_error - { - public: - explicit bad_rational() - : std::domain_error("bad rational: zero denominator") - {} - }; - - template - class rational; - - namespace detail { - struct rational_private_constructor_tag {}; - - template - inline SPROUT_CONSTEXPR sprout::rational make_rational( - typename sprout::detail::call_traits::param_type n, - typename sprout::detail::call_traits::param_type d, - sprout::detail::rational_private_constructor_tag - ); - } // namespace detail - - namespace detail { - template - class rational_impl { - protected: - typedef IntType int_type; - typedef typename sprout::detail::call_traits::param_type param_type; - protected: - IntType num_; - IntType den_; - protected: - SPROUT_CONSTEXPR rational_impl() - : num_(0) - , den_(1) - {} - rational_impl(rational_impl const&) = default; - SPROUT_CONSTEXPR rational_impl(param_type n) - : num_(n) - , den_(1) - {} - SPROUT_CONSTEXPR rational_impl(param_type n, param_type d) - : num_(n) - , den_(d) - {} - SPROUT_CONSTEXPR rational_impl(param_type n, param_type d, param_type g) - : num_(n / g) - , den_(d / g) - {} - }; - } // namespace detail - - // - // rational - // - template - class rational - : private sprout::detail::rational_impl - { - static_assert(std::numeric_limits::is_specialized, "std::numeric_limits::is_specialized"); - public: - typedef IntType int_type; - typedef typename sprout::detail::call_traits::param_type param_type; - private: - struct private_constructor_tag {}; - typedef sprout::detail::rational_impl base_type; - private: - static SPROUT_CONSTEXPR IntType normalize_g_1(IntType den, IntType g) { - return den / g < 0 ? -g : g; - } - static SPROUT_CONSTEXPR IntType normalize_g(IntType num, IntType den) { - return den == 0 ? throw sprout::bad_rational() - : num == 0 ? den - : normalize_g_1(den, sprout::math::gcd(num, den)) - ; - } - private: - using base_type::num_; - using base_type::den_; - private: - SPROUT_CONSTEXPR rational(param_type n, param_type d, private_constructor_tag) - : base_type(n, d) - {} - public: - SPROUT_CONSTEXPR rational() - : base_type() - {} - rational(rational const&) = default; - SPROUT_CONSTEXPR rational(param_type n) - : base_type(n) - {} - SPROUT_CONSTEXPR rational(param_type n, param_type d) - : base_type(n, d, normalize_g(n, d)) - {} - - rational& operator=(rational const&) = default; - rational& operator=(param_type n) { - return assign(n, 1); - } - rational& assign(param_type n, param_type d) { - using std::swap; - rational temp(n, d); - swap(temp, *this); - return *this; - } - - SPROUT_CONSTEXPR IntType numerator() const { - return num_; - } - SPROUT_CONSTEXPR IntType denominator() const { - return den_; - } - - rational& operator+=(rational const& rhs) { - IntType g = sprout::math::gcd(den_, rhs.den_); - den_ /= g; - num_ = num_ * (rhs.den_ / g) + rhs.num_ * den_; - g = sprout::math::gcd(num_, g); - num_ /= g; - den_ *= rhs.den_ / g; - return *this; - } - rational& operator-=(rational const& rhs) { - IntType g = sprout::math::gcd(den_, rhs.den_); - den_ /= g; - num_ = num_ * (rhs.den_ / g) - rhs.num_ * den_; - g = sprout::math::gcd(num_, g); - num_ /= g; - den_ *= rhs.den_ / g; - return *this; - } - rational& operator*=(rational const& rhs) { - IntType gcd1 = sprout::math::gcd(num_, rhs.den_); - IntType gcd2 = sprout::math::gcd(rhs.num_, den_); - num_ =(num_ / gcd1) * (rhs.num_ / gcd2); - den_ =(den_ / gcd2) * (rhs.den_ / gcd1); - return *this; - } - rational& operator/=(rational const& rhs) { - if (rhs.num_ == IntType(0)) { - throw bad_rational(); - } - if (num_ == IntType(0)) { - return *this; - } - IntType gcd1 = sprout::math::gcd(num_, rhs.num_); - IntType gcd2 = sprout::math::gcd(rhs.den_, den_); - num_ =(num_ / gcd1) * (rhs.den_ / gcd2); - den_ =(den_ / gcd2) * (rhs.num_ / gcd1); - if (den_ < IntType(0)) { - num_ = -num_; - den_ = -den_; - } - return *this; - } - rational& operator+=(param_type rhs) { - return *this += rational(rhs); - } - rational& operator-=(param_type rhs) { - return *this -= rational(rhs); - } - rational& operator*=(param_type rhs) { - return *this *= rational(rhs); - } - rational& operator/=(param_type rhs) { - return *this /= rational(rhs); - } - - rational& operator++() { - num_ += den_; - return *this; - } - rational& operator--() { - num_ -= den_; - return *this; - } - rational operator++(int) { - rational result(*this); - ++*this; - return result; - } - rational operator--(int) { - rational result(*this); - --*this; - return result; - } - - SPROUT_CONSTEXPR bool operator!() const { - return !num_; - } - SPROUT_CONSTEXPR operator bool() const { - return num_ != 0; - } - - public: - friend sprout::rational sprout::detail::make_rational( - typename sprout::detail::call_traits::param_type n, - typename sprout::detail::call_traits::param_type d, - sprout::detail::rational_private_constructor_tag - ); - }; - - namespace detail { - template - inline SPROUT_CONSTEXPR sprout::rational make_rational( - typename sprout::detail::call_traits::param_type n, - typename sprout::detail::call_traits::param_type d, - sprout::detail::rational_private_constructor_tag - ) - { - return sprout::rational( - n, d, - typename sprout::rational::private_constructor_tag() - ); - } - } // namespace detail - - // - // operator+ - // operator- - // - template - inline SPROUT_CONSTEXPR sprout::rational - operator+(rational const& r) { - return r; - } - template - inline SPROUT_CONSTEXPR sprout::rational - operator-(rational const& r) { - return sprout::detail::make_rational( - -r.numerator(), r.denominator(), - sprout::detail::rational_private_constructor_tag() - ); - } - - // - // operator+ - // operator- - // operator* - // operator/ - // - namespace detail { - template - inline SPROUT_CONSTEXPR sprout::rational - rational_add_impl_3( - sprout::rational const& rhs, - IntType g, IntType den, IntType num - ) - { - return sprout::detail::make_rational( - num / g, den * (rhs.denominator() / g), - sprout::detail::rational_private_constructor_tag() - ); - } - template - inline SPROUT_CONSTEXPR sprout::rational - rational_add_impl_2( - sprout::rational const& rhs, - IntType g, IntType den, IntType num - ) - { - return rational_add_impl_3( - rhs, - sprout::math::gcd(num, g), den, num - ); - } - template - inline SPROUT_CONSTEXPR sprout::rational - rational_add_impl_1( - sprout::rational const& lhs, sprout::rational const& rhs, - IntType g, IntType den - ) - { - return rational_add_impl_2( - rhs, - g, den, lhs.numerator() * (rhs.denominator() / g) + rhs.numerator() * den - ); - } - template - inline SPROUT_CONSTEXPR sprout::rational - rational_add_impl( - sprout::rational const& lhs, sprout::rational const& rhs, - IntType g - ) - { - return rational_add_impl_1( - lhs, rhs, - g, lhs.denominator() / g - ); - } - } // namespace detail - template - inline SPROUT_CONSTEXPR sprout::rational - operator+(sprout::rational const& lhs, sprout::rational const& rhs) { - return sprout::detail::rational_add_impl( - lhs, rhs, - sprout::math::gcd(lhs.denominator(), rhs.denominator()) - ); - } - template - inline SPROUT_CONSTEXPR sprout::rational - operator+(sprout::rational const& lhs, typename sprout::rational::param_type rhs) { - return lhs + sprout::rational(rhs); - } - template - inline SPROUT_CONSTEXPR sprout::rational - operator+(typename sprout::rational::param_type lhs, sprout::rational const& rhs) { - return sprout::rational(lhs) + rhs; - } - - namespace detail { - template - inline SPROUT_CONSTEXPR sprout::rational - rational_sub_impl_3( - sprout::rational const& rhs, - IntType g, IntType den, IntType num - ) - { - return sprout::detail::make_rational( - num / g, den * (rhs.denominator() / g), - sprout::detail::rational_private_constructor_tag() - ); - } - template - inline SPROUT_CONSTEXPR sprout::rational - rational_sub_impl_2( - sprout::rational const& rhs, - IntType g, IntType den, IntType num - ) - { - return rational_sub_impl_3( - rhs, - sprout::math::gcd(num, g), den, num - ); - } - template - inline SPROUT_CONSTEXPR sprout::rational - rational_sub_impl_1( - sprout::rational const& lhs, sprout::rational const& rhs, - IntType g, IntType den - ) - { - return rational_sub_impl_2( - rhs, - g, den, lhs.numerator() * (rhs.denominator() / g) - rhs.numerator() * den - ); - } - template - inline SPROUT_CONSTEXPR sprout::rational - rational_sub_impl( - sprout::rational const& lhs, sprout::rational const& rhs, - IntType g - ) - { - return rational_sub_impl_1( - lhs, rhs, - g, lhs.denominator() / g - ); - } - } // namespace detail - template - inline SPROUT_CONSTEXPR sprout::rational - operator-(sprout::rational const& lhs, sprout::rational const& rhs) { - return sprout::detail::rational_sub_impl( - lhs, rhs, - sprout::math::gcd(lhs.denominator(), rhs.denominator()) - ); - } - template - inline SPROUT_CONSTEXPR sprout::rational - operator-(sprout::rational const& lhs, typename sprout::rational::param_type rhs) { - return lhs - sprout::rational(rhs); - } - template - inline SPROUT_CONSTEXPR sprout::rational - operator-(typename sprout::rational::param_type lhs, sprout::rational const& rhs) { - return sprout::rational(lhs) - rhs; - } - - namespace detail { - template - inline SPROUT_CONSTEXPR sprout::rational - rational_mul_impl( - sprout::rational const& lhs, sprout::rational const& rhs, - IntType gcd1, IntType gcd2 - ) - { - return sprout::detail::make_rational( - (lhs.numerator() / gcd1) * (rhs.numerator() / gcd2), - (lhs.denominator() / gcd2) * (rhs.denominator() / gcd1), - sprout::detail::rational_private_constructor_tag() - ); - } - } // namespace detail - template - inline SPROUT_CONSTEXPR sprout::rational - operator*(sprout::rational const& lhs, sprout::rational const& rhs) { - return sprout::detail::rational_mul_impl( - lhs, rhs, - sprout::math::gcd(lhs.numerator(), rhs.denominator()), - sprout::math::gcd(rhs.numerator(), lhs.denominator()) - ); - } - template - inline SPROUT_CONSTEXPR sprout::rational - operator*(sprout::rational const& lhs, typename sprout::rational::param_type rhs) { - return lhs * sprout::rational(rhs); - } - template - inline SPROUT_CONSTEXPR sprout::rational - operator*(typename sprout::rational::param_type lhs, sprout::rational const& rhs) { - return sprout::rational(lhs) * rhs; - } - - namespace detail { - template - inline SPROUT_CONSTEXPR sprout::rational - rational_div_impl_1(IntType num, IntType den) { - return den < IntType(0) ? sprout::detail::make_rational( - -num, -den, - sprout::detail::rational_private_constructor_tag() - ) - : sprout::detail::make_rational( - num, den, - sprout::detail::rational_private_constructor_tag() - ) - ; - } - template - inline SPROUT_CONSTEXPR sprout::rational - rational_div_impl( - sprout::rational const& lhs, sprout::rational const& rhs, - IntType gcd1, IntType gcd2 - ) - { - return sprout::detail::rational_div_impl_1( - (lhs.numerator() / gcd1) * (rhs.denominator() / gcd2), - (lhs.denominator() / gcd2) * (rhs.numerator() / gcd1) - ); - } - } // namespace detail - template - inline SPROUT_CONSTEXPR sprout::rational - operator/(sprout::rational const& lhs, sprout::rational const& rhs) { - return rhs.numerator() == IntType(0) ? throw sprout::bad_rational() - : lhs.numerator() == IntType(0) ? lhs - : sprout::detail::rational_div_impl( - lhs, rhs, - sprout::math::gcd(lhs.numerator(), rhs.numerator()), - sprout::math::gcd(rhs.denominator(), lhs.denominator()) - ) - ; - } - template - inline SPROUT_CONSTEXPR sprout::rational - operator/(sprout::rational const& lhs, typename sprout::rational::param_type rhs) { - return lhs / sprout::rational(rhs); - } - template - inline SPROUT_CONSTEXPR sprout::rational - operator/(typename sprout::rational::param_type lhs, sprout::rational const& rhs) { - return sprout::rational(lhs) / rhs; - } - - // - // operator== - // operator!= - // - template - inline SPROUT_CONSTEXPR bool - operator==(sprout::rational const& lhs, sprout::rational const& rhs) { - return lhs.numerator() == rhs.numerator() && lhs.denominator() == rhs.denominator(); - } - template - inline SPROUT_CONSTEXPR bool - operator==(sprout::rational const& lhs, typename sprout::rational::param_type rhs) { - return lhs.denominator() == IntType(1) && lhs.numerator() == rhs; - } - template - inline SPROUT_CONSTEXPR bool - operator==(typename sprout::rational::param_type lhs, sprout::rational const& rhs) { - return rhs == lhs; - } - template - inline SPROUT_CONSTEXPR bool - operator!=(sprout::rational const& lhs, sprout::rational const& rhs) { - return !(lhs == rhs); - } - template - inline SPROUT_CONSTEXPR bool - operator!=(sprout::rational const& lhs, typename sprout::rational::param_type rhs) { - return !(lhs == rhs); - } - template - inline SPROUT_CONSTEXPR bool - operator!=(typename sprout::rational::param_type lhs, sprout::rational const& rhs) { - return !(lhs == rhs); - } - - // - // operator< - // operator> - // operator<= - // operator>= - // - namespace detail { - template - inline SPROUT_CONSTEXPR bool - rational_less_impl_2( - sprout::rational const& lhs, sprout::rational const& rhs, - IntType d1, IntType q1, IntType r1, - IntType d2, IntType q2, IntType r2, - unsigned reverse = 0 - ) - { - return q1 != q2 ? reverse ? q1 > q2 : q1 < q2 - : r1 == IntType(0) || r2 == IntType(0) - ? r1 == r2 ? false - : (r1 != IntType(0)) != static_cast(reverse ^ 1) - : sprout::detail::rational_less_impl_2( - lhs, rhs, - r1, d1 / r1, d1 % r1, - r2, d2 / r2, d2 % r2, - reverse ^ 1 - ) - ; - } - template - inline SPROUT_CONSTEXPR bool - rational_less_impl_1( - sprout::rational const& lhs, sprout::rational const& rhs, - IntType d1, IntType q1, IntType r1, - IntType d2, IntType q2, IntType r2 - ) - { - return r2 < IntType(0) ? sprout::detail::rational_less_impl_1( - lhs, rhs, - d1, q1, r1, - d2, q2 - 1, r2 + d2 - ) - : sprout::detail::rational_less_impl_2( - lhs, rhs, - d1, q1, r1, - d2, q2, r2 - ) - ; - } - template - inline SPROUT_CONSTEXPR bool - rational_less_impl( - sprout::rational const& lhs, sprout::rational const& rhs, - IntType d1, IntType q1, IntType r1 - ) - { - return r1 < IntType(0) ? sprout::detail::rational_less_impl( - lhs, rhs, - d1, q1 - 1, r1 + d1 - ) - : sprout::detail::rational_less_impl_1( - lhs, rhs, - d1, q1, r1, - rhs.denominator(), rhs.numerator() / rhs.denominator(), rhs.numerator() % rhs.denominator() - ) - ; - } - - template - inline SPROUT_CONSTEXPR bool - rational_less_impl( - sprout::rational const& lhs, typename sprout::rational::param_type rhs, - IntType q, IntType r - ) - { - return r < IntType(0) ? sprout::detail::rational_less_impl( - lhs, rhs, - r + lhs.denominator(), q - 1 - ) - : q < rhs - ; - } - } // namespace detail - template - inline SPROUT_CONSTEXPR bool - operator<(sprout::rational const& lhs, sprout::rational const& rhs) { - return sprout::detail::rational_less_impl( - lhs, rhs, - lhs.denominator(), lhs.numerator() / lhs.denominator(), lhs.numerator() % lhs.denominator() - ); - } - template - inline SPROUT_CONSTEXPR bool - operator<(sprout::rational const& lhs, typename sprout::rational::param_type rhs) { - return sprout::detail::rational_less_impl( - lhs, rhs, - lhs.numerator() / lhs.denominator(), lhs.numerator() % lhs.denominator() - ); - } - template - inline SPROUT_CONSTEXPR bool - operator<(typename sprout::rational::param_type lhs, sprout::rational const& rhs) { - return lhs != rhs && !(rhs < lhs); - } - - template - inline SPROUT_CONSTEXPR bool - operator>(sprout::rational const& lhs, sprout::rational const& rhs) { - return rhs < lhs; - } - template - inline SPROUT_CONSTEXPR bool - operator>(sprout::rational const& lhs, typename sprout::rational::param_type rhs) { - return rhs < lhs; - } - template - inline SPROUT_CONSTEXPR bool - operator>(typename sprout::rational::param_type lhs, sprout::rational const& rhs) { - return rhs < lhs; - } - - template - inline SPROUT_CONSTEXPR bool - operator<=(sprout::rational const& lhs, sprout::rational const& rhs) { - return !(rhs < lhs); - } - template - inline SPROUT_CONSTEXPR bool - operator<=(sprout::rational const& lhs, typename sprout::rational::param_type rhs) { - return !(rhs < lhs); - } - template - inline SPROUT_CONSTEXPR bool - operator<=(typename sprout::rational::param_type lhs, sprout::rational const& rhs) { - return !(rhs < lhs); - } - - template - inline SPROUT_CONSTEXPR bool - operator>=(sprout::rational const& lhs, sprout::rational const& rhs) { - return !(lhs < rhs); - } - template - inline SPROUT_CONSTEXPR bool - operator>=(sprout::rational const& lhs, typename sprout::rational::param_type rhs) { - return !(lhs < rhs); - } - template - inline SPROUT_CONSTEXPR bool - operator>=(typename sprout::rational::param_type lhs, sprout::rational const& rhs) { - return !(lhs < rhs); - } - - // - // operator>> - // operator<< - // - template - inline std::basic_istream& - operator>>(std::basic_istream& lhs, sprout::rational& rhs) { - IntType n = IntType(0); - IntType d = IntType(1); - Elem c = 0; - sprout::detail::io::ios_flags_saver saver(lhs); - lhs >> n; - c = lhs.get(); - if (c != Elem('/')) { - lhs.clear(std::istream::badbit); - } - lhs >> std::noskipws; - lhs >> d; - if (lhs) { - rhs.assign(n, d); - } - return lhs; - } - template - inline std::basic_ostream& - operator<<(std::basic_ostream& lhs, sprout::rational const& rhs) { - return lhs << rhs.numerator() << Elem('/') << rhs.denominator(); - } - - // - // rational_cast - // - template - inline SPROUT_CONSTEXPR T - rational_cast(sprout::rational const& src) { - return static_cast(src.numerator()) / static_cast(src.denominator()); - } - - // - // abs - // - template - inline SPROUT_CONSTEXPR sprout::rational - abs(sprout::rational const& x) { - return x.numerator() >= IntType(0) ? x - : sprout::detail::make_rational( - -x.numerator(), x.denominator(), - sprout::detail::rational_private_constructor_tag() - ) - ; - } - -} // namespace sprout +#include +#include +#include +#include +#include +#include +#include +#include #endif // SPROUT_RATIONAL_HPP diff --git a/sprout/rational/arithmetic.hpp b/sprout/rational/arithmetic.hpp new file mode 100644 index 00000000..52dd830f --- /dev/null +++ b/sprout/rational/arithmetic.hpp @@ -0,0 +1,258 @@ +#ifndef SPROUT_RATIONAL_ARITHMETIC_HPP +#define SPROUT_RATIONAL_ARITHMETIC_HPP + +#include +#include +#include +#include + +namespace sprout { + // + // operator+ + // operator- + // + template + inline SPROUT_CONSTEXPR sprout::rational + operator+(rational const& r) { + return r; + } + template + inline SPROUT_CONSTEXPR sprout::rational + operator-(rational const& r) { + return sprout::detail::make_rational( + -r.numerator(), r.denominator(), + sprout::detail::rational_private_constructor_tag() + ); + } + + // + // operator+ + // operator- + // operator* + // operator/ + // + namespace detail { + template + inline SPROUT_CONSTEXPR sprout::rational + rational_add_impl_3( + sprout::rational const& rhs, + IntType g, IntType den, IntType num + ) + { + return sprout::detail::make_rational( + num / g, den * (rhs.denominator() / g), + sprout::detail::rational_private_constructor_tag() + ); + } + template + inline SPROUT_CONSTEXPR sprout::rational + rational_add_impl_2( + sprout::rational const& rhs, + IntType g, IntType den, IntType num + ) + { + return rational_add_impl_3( + rhs, + sprout::math::gcd(num, g), den, num + ); + } + template + inline SPROUT_CONSTEXPR sprout::rational + rational_add_impl_1( + sprout::rational const& lhs, sprout::rational const& rhs, + IntType g, IntType den + ) + { + return rational_add_impl_2( + rhs, + g, den, lhs.numerator() * (rhs.denominator() / g) + rhs.numerator() * den + ); + } + template + inline SPROUT_CONSTEXPR sprout::rational + rational_add_impl( + sprout::rational const& lhs, sprout::rational const& rhs, + IntType g + ) + { + return rational_add_impl_1( + lhs, rhs, + g, lhs.denominator() / g + ); + } + } // namespace detail + template + inline SPROUT_CONSTEXPR sprout::rational + operator+(sprout::rational const& lhs, sprout::rational const& rhs) { + return sprout::detail::rational_add_impl( + lhs, rhs, + sprout::math::gcd(lhs.denominator(), rhs.denominator()) + ); + } + template + inline SPROUT_CONSTEXPR sprout::rational + operator+(sprout::rational const& lhs, typename sprout::rational::param_type rhs) { + return lhs + sprout::rational(rhs); + } + template + inline SPROUT_CONSTEXPR sprout::rational + operator+(typename sprout::rational::param_type lhs, sprout::rational const& rhs) { + return sprout::rational(lhs) + rhs; + } + + namespace detail { + template + inline SPROUT_CONSTEXPR sprout::rational + rational_sub_impl_3( + sprout::rational const& rhs, + IntType g, IntType den, IntType num + ) + { + return sprout::detail::make_rational( + num / g, den * (rhs.denominator() / g), + sprout::detail::rational_private_constructor_tag() + ); + } + template + inline SPROUT_CONSTEXPR sprout::rational + rational_sub_impl_2( + sprout::rational const& rhs, + IntType g, IntType den, IntType num + ) + { + return rational_sub_impl_3( + rhs, + sprout::math::gcd(num, g), den, num + ); + } + template + inline SPROUT_CONSTEXPR sprout::rational + rational_sub_impl_1( + sprout::rational const& lhs, sprout::rational const& rhs, + IntType g, IntType den + ) + { + return rational_sub_impl_2( + rhs, + g, den, lhs.numerator() * (rhs.denominator() / g) - rhs.numerator() * den + ); + } + template + inline SPROUT_CONSTEXPR sprout::rational + rational_sub_impl( + sprout::rational const& lhs, sprout::rational const& rhs, + IntType g + ) + { + return rational_sub_impl_1( + lhs, rhs, + g, lhs.denominator() / g + ); + } + } // namespace detail + template + inline SPROUT_CONSTEXPR sprout::rational + operator-(sprout::rational const& lhs, sprout::rational const& rhs) { + return sprout::detail::rational_sub_impl( + lhs, rhs, + sprout::math::gcd(lhs.denominator(), rhs.denominator()) + ); + } + template + inline SPROUT_CONSTEXPR sprout::rational + operator-(sprout::rational const& lhs, typename sprout::rational::param_type rhs) { + return lhs - sprout::rational(rhs); + } + template + inline SPROUT_CONSTEXPR sprout::rational + operator-(typename sprout::rational::param_type lhs, sprout::rational const& rhs) { + return sprout::rational(lhs) - rhs; + } + + namespace detail { + template + inline SPROUT_CONSTEXPR sprout::rational + rational_mul_impl( + sprout::rational const& lhs, sprout::rational const& rhs, + IntType gcd1, IntType gcd2 + ) + { + return sprout::detail::make_rational( + (lhs.numerator() / gcd1) * (rhs.numerator() / gcd2), + (lhs.denominator() / gcd2) * (rhs.denominator() / gcd1), + sprout::detail::rational_private_constructor_tag() + ); + } + } // namespace detail + template + inline SPROUT_CONSTEXPR sprout::rational + operator*(sprout::rational const& lhs, sprout::rational const& rhs) { + return sprout::detail::rational_mul_impl( + lhs, rhs, + sprout::math::gcd(lhs.numerator(), rhs.denominator()), + sprout::math::gcd(rhs.numerator(), lhs.denominator()) + ); + } + template + inline SPROUT_CONSTEXPR sprout::rational + operator*(sprout::rational const& lhs, typename sprout::rational::param_type rhs) { + return lhs * sprout::rational(rhs); + } + template + inline SPROUT_CONSTEXPR sprout::rational + operator*(typename sprout::rational::param_type lhs, sprout::rational const& rhs) { + return sprout::rational(lhs) * rhs; + } + + namespace detail { + template + inline SPROUT_CONSTEXPR sprout::rational + rational_div_impl_1(IntType num, IntType den) { + return den < IntType(0) ? sprout::detail::make_rational( + -num, -den, + sprout::detail::rational_private_constructor_tag() + ) + : sprout::detail::make_rational( + num, den, + sprout::detail::rational_private_constructor_tag() + ) + ; + } + template + inline SPROUT_CONSTEXPR sprout::rational + rational_div_impl( + sprout::rational const& lhs, sprout::rational const& rhs, + IntType gcd1, IntType gcd2 + ) + { + return sprout::detail::rational_div_impl_1( + (lhs.numerator() / gcd1) * (rhs.denominator() / gcd2), + (lhs.denominator() / gcd2) * (rhs.numerator() / gcd1) + ); + } + } // namespace detail + template + inline SPROUT_CONSTEXPR sprout::rational + operator/(sprout::rational const& lhs, sprout::rational const& rhs) { + return rhs.numerator() == IntType(0) ? throw sprout::bad_rational() + : lhs.numerator() == IntType(0) ? lhs + : sprout::detail::rational_div_impl( + lhs, rhs, + sprout::math::gcd(lhs.numerator(), rhs.numerator()), + sprout::math::gcd(rhs.denominator(), lhs.denominator()) + ) + ; + } + template + inline SPROUT_CONSTEXPR sprout::rational + operator/(sprout::rational const& lhs, typename sprout::rational::param_type rhs) { + return lhs / sprout::rational(rhs); + } + template + inline SPROUT_CONSTEXPR sprout::rational + operator/(typename sprout::rational::param_type lhs, sprout::rational const& rhs) { + return sprout::rational(lhs) / rhs; + } +} // namespace sprout + +#endif // SPROUT_RATIONAL_ARITHMETIC_HPP diff --git a/sprout/rational/comparison.hpp b/sprout/rational/comparison.hpp new file mode 100644 index 00000000..83dd32c2 --- /dev/null +++ b/sprout/rational/comparison.hpp @@ -0,0 +1,196 @@ +#ifndef SPROUT_RATIONAL_COMPARISON_HPP +#define SPROUT_RATIONAL_COMPARISON_HPP + +#include +#include + +namespace sprout { + // + // operator== + // operator!= + // + template + inline SPROUT_CONSTEXPR bool + operator==(sprout::rational const& lhs, sprout::rational const& rhs) { + return lhs.numerator() == rhs.numerator() && lhs.denominator() == rhs.denominator(); + } + template + inline SPROUT_CONSTEXPR bool + operator==(sprout::rational const& lhs, typename sprout::rational::param_type rhs) { + return lhs.denominator() == IntType(1) && lhs.numerator() == rhs; + } + template + inline SPROUT_CONSTEXPR bool + operator==(typename sprout::rational::param_type lhs, sprout::rational const& rhs) { + return rhs == lhs; + } + template + inline SPROUT_CONSTEXPR bool + operator!=(sprout::rational const& lhs, sprout::rational const& rhs) { + return !(lhs == rhs); + } + template + inline SPROUT_CONSTEXPR bool + operator!=(sprout::rational const& lhs, typename sprout::rational::param_type rhs) { + return !(lhs == rhs); + } + template + inline SPROUT_CONSTEXPR bool + operator!=(typename sprout::rational::param_type lhs, sprout::rational const& rhs) { + return !(lhs == rhs); + } + + // + // operator< + // operator> + // operator<= + // operator>= + // + namespace detail { + template + inline SPROUT_CONSTEXPR bool + rational_less_impl_2( + sprout::rational const& lhs, sprout::rational const& rhs, + IntType d1, IntType q1, IntType r1, + IntType d2, IntType q2, IntType r2, + unsigned reverse = 0 + ) + { + return q1 != q2 ? reverse ? q1 > q2 : q1 < q2 + : r1 == IntType(0) || r2 == IntType(0) + ? r1 == r2 ? false + : (r1 != IntType(0)) != static_cast(reverse ^ 1) + : sprout::detail::rational_less_impl_2( + lhs, rhs, + r1, d1 / r1, d1 % r1, + r2, d2 / r2, d2 % r2, + reverse ^ 1 + ) + ; + } + template + inline SPROUT_CONSTEXPR bool + rational_less_impl_1( + sprout::rational const& lhs, sprout::rational const& rhs, + IntType d1, IntType q1, IntType r1, + IntType d2, IntType q2, IntType r2 + ) + { + return r2 < IntType(0) ? sprout::detail::rational_less_impl_1( + lhs, rhs, + d1, q1, r1, + d2, q2 - 1, r2 + d2 + ) + : sprout::detail::rational_less_impl_2( + lhs, rhs, + d1, q1, r1, + d2, q2, r2 + ) + ; + } + template + inline SPROUT_CONSTEXPR bool + rational_less_impl( + sprout::rational const& lhs, sprout::rational const& rhs, + IntType d1, IntType q1, IntType r1 + ) + { + return r1 < IntType(0) ? sprout::detail::rational_less_impl( + lhs, rhs, + d1, q1 - 1, r1 + d1 + ) + : sprout::detail::rational_less_impl_1( + lhs, rhs, + d1, q1, r1, + rhs.denominator(), rhs.numerator() / rhs.denominator(), rhs.numerator() % rhs.denominator() + ) + ; + } + + template + inline SPROUT_CONSTEXPR bool + rational_less_impl( + sprout::rational const& lhs, typename sprout::rational::param_type rhs, + IntType q, IntType r + ) + { + return r < IntType(0) ? sprout::detail::rational_less_impl( + lhs, rhs, + r + lhs.denominator(), q - 1 + ) + : q < rhs + ; + } + } // namespace detail + template + inline SPROUT_CONSTEXPR bool + operator<(sprout::rational const& lhs, sprout::rational const& rhs) { + return sprout::detail::rational_less_impl( + lhs, rhs, + lhs.denominator(), lhs.numerator() / lhs.denominator(), lhs.numerator() % lhs.denominator() + ); + } + template + inline SPROUT_CONSTEXPR bool + operator<(sprout::rational const& lhs, typename sprout::rational::param_type rhs) { + return sprout::detail::rational_less_impl( + lhs, rhs, + lhs.numerator() / lhs.denominator(), lhs.numerator() % lhs.denominator() + ); + } + template + inline SPROUT_CONSTEXPR bool + operator<(typename sprout::rational::param_type lhs, sprout::rational const& rhs) { + return lhs != rhs && !(rhs < lhs); + } + + template + inline SPROUT_CONSTEXPR bool + operator>(sprout::rational const& lhs, sprout::rational const& rhs) { + return rhs < lhs; + } + template + inline SPROUT_CONSTEXPR bool + operator>(sprout::rational const& lhs, typename sprout::rational::param_type rhs) { + return rhs < lhs; + } + template + inline SPROUT_CONSTEXPR bool + operator>(typename sprout::rational::param_type lhs, sprout::rational const& rhs) { + return rhs < lhs; + } + + template + inline SPROUT_CONSTEXPR bool + operator<=(sprout::rational const& lhs, sprout::rational const& rhs) { + return !(rhs < lhs); + } + template + inline SPROUT_CONSTEXPR bool + operator<=(sprout::rational const& lhs, typename sprout::rational::param_type rhs) { + return !(rhs < lhs); + } + template + inline SPROUT_CONSTEXPR bool + operator<=(typename sprout::rational::param_type lhs, sprout::rational const& rhs) { + return !(rhs < lhs); + } + + template + inline SPROUT_CONSTEXPR bool + operator>=(sprout::rational const& lhs, sprout::rational const& rhs) { + return !(lhs < rhs); + } + template + inline SPROUT_CONSTEXPR bool + operator>=(sprout::rational const& lhs, typename sprout::rational::param_type rhs) { + return !(lhs < rhs); + } + template + inline SPROUT_CONSTEXPR bool + operator>=(typename sprout::rational::param_type lhs, sprout::rational const& rhs) { + return !(lhs < rhs); + } +} // namespace sprout + +#endif // SPROUT_RATIONAL_COMPARISON_HPP diff --git a/sprout/rational/conversion.hpp b/sprout/rational/conversion.hpp new file mode 100644 index 00000000..30e2df60 --- /dev/null +++ b/sprout/rational/conversion.hpp @@ -0,0 +1,18 @@ +#ifndef SPROUT_RATIONAL_CONVERSION_HPP +#define SPROUT_RATIONAL_CONVERSION_HPP + +#include +#include + +namespace sprout { + // + // rational_cast + // + template + inline SPROUT_CONSTEXPR T + rational_cast(sprout::rational const& src) { + return static_cast(src.numerator()) / static_cast(src.denominator()); + } +} // namespace sprout + +#endif // SPROUT_RATIONAL_CONVERSION_HPP diff --git a/sprout/rational/exceptions.hpp b/sprout/rational/exceptions.hpp new file mode 100644 index 00000000..642462b6 --- /dev/null +++ b/sprout/rational/exceptions.hpp @@ -0,0 +1,21 @@ +#ifndef SPROUT_RATIONAL_EXCEPTIONS_HPP +#define SPROUT_RATIONAL_EXCEPTIONS_HPP + +#include +#include + +namespace sprout { + // + // bad_rational + // + class bad_rational + : public std::domain_error + { + public: + explicit bad_rational() + : std::domain_error("bad rational: zero denominator") + {} + }; +} // namespace sprout + +#endif // SPROUT_RATIONAL_EXCEPTIONS_HPP diff --git a/sprout/rational/hash.hpp b/sprout/rational/hash.hpp new file mode 100644 index 00000000..f9da6a61 --- /dev/null +++ b/sprout/rational/hash.hpp @@ -0,0 +1,19 @@ +#ifndef SPROUT_RATIONAL_HASH_HPP +#define SPROUT_RATIONAL_HASH_HPP + +#include +#include +#include +#include + +namespace sprout { + // + // hash_value + // + template + inline SPROUT_CONSTEXPR std::size_t hash_value(sprout::rational const& v) { + return sprout::hash_values(v.numerator(), v.denominator()); + } +} // namespace sprout + +#endif // SPROUT_RATIONAL_HASH_HPP diff --git a/sprout/rational/io.hpp b/sprout/rational/io.hpp new file mode 100644 index 00000000..008a7a9c --- /dev/null +++ b/sprout/rational/io.hpp @@ -0,0 +1,41 @@ +#ifndef SPROUT_RATIONAL_IO_HPP +#define SPROUT_RATIONAL_IO_HPP + +#include +#include +#include +#include +#include + +namespace sprout { + // + // operator>> + // operator<< + // + template + inline std::basic_istream& + operator>>(std::basic_istream& lhs, sprout::rational& rhs) { + IntType n = IntType(0); + IntType d = IntType(1); + Elem c = 0; + sprout::detail::io::ios_flags_saver saver(lhs); + lhs >> n; + c = lhs.get(); + if (c != Elem('/')) { + lhs.clear(std::istream::badbit); + } + lhs >> std::noskipws; + lhs >> d; + if (lhs) { + rhs.assign(n, d); + } + return lhs; + } + template + inline std::basic_ostream& + operator<<(std::basic_ostream& lhs, sprout::rational const& rhs) { + return lhs << rhs.numerator() << Elem('/') << rhs.denominator(); + } +} // namespace sprout + +#endif // SPROUT_RATIONAL_IO_HPP diff --git a/sprout/rational/rational.hpp b/sprout/rational/rational.hpp new file mode 100644 index 00000000..69168a4a --- /dev/null +++ b/sprout/rational/rational.hpp @@ -0,0 +1,222 @@ +#ifndef SPROUT_RATIONAL_RATIONAL_HPP +#define SPROUT_RATIONAL_RATIONAL_HPP + +#include +#include +#include +#include +#include +#include + +namespace sprout { + template + class rational; + + namespace detail { + struct rational_private_constructor_tag {}; + + template + inline SPROUT_CONSTEXPR sprout::rational make_rational( + typename sprout::detail::call_traits::param_type n, + typename sprout::detail::call_traits::param_type d, + sprout::detail::rational_private_constructor_tag + ); + } // namespace detail + + namespace detail { + template + class rational_impl { + protected: + typedef IntType int_type; + typedef typename sprout::detail::call_traits::param_type param_type; + protected: + IntType num_; + IntType den_; + protected: + SPROUT_CONSTEXPR rational_impl() + : num_(0) + , den_(1) + {} + rational_impl(rational_impl const&) = default; + SPROUT_CONSTEXPR rational_impl(param_type n) + : num_(n) + , den_(1) + {} + SPROUT_CONSTEXPR rational_impl(param_type n, param_type d) + : num_(n) + , den_(d) + {} + SPROUT_CONSTEXPR rational_impl(param_type n, param_type d, param_type g) + : num_(n / g) + , den_(d / g) + {} + }; + } // namespace detail + + // + // rational + // + template + class rational + : private sprout::detail::rational_impl + { + static_assert(std::numeric_limits::is_specialized, "std::numeric_limits::is_specialized"); + public: + typedef IntType int_type; + typedef typename sprout::detail::call_traits::param_type param_type; + private: + struct private_constructor_tag {}; + typedef sprout::detail::rational_impl base_type; + private: + static SPROUT_CONSTEXPR IntType normalize_g_1(IntType den, IntType g) { + return den / g < 0 ? -g : g; + } + static SPROUT_CONSTEXPR IntType normalize_g(IntType num, IntType den) { + return den == 0 ? throw sprout::bad_rational() + : num == 0 ? den + : normalize_g_1(den, sprout::math::gcd(num, den)) + ; + } + private: + using base_type::num_; + using base_type::den_; + private: + SPROUT_CONSTEXPR rational(param_type n, param_type d, private_constructor_tag) + : base_type(n, d) + {} + public: + SPROUT_CONSTEXPR rational() + : base_type() + {} + rational(rational const&) = default; + SPROUT_CONSTEXPR rational(param_type n) + : base_type(n) + {} + SPROUT_CONSTEXPR rational(param_type n, param_type d) + : base_type(n, d, normalize_g(n, d)) + {} + + rational& operator=(rational const&) = default; + rational& operator=(param_type n) { + return assign(n, 1); + } + rational& assign(param_type n, param_type d) { + using std::swap; + rational temp(n, d); + swap(temp, *this); + return *this; + } + + SPROUT_CONSTEXPR IntType numerator() const { + return num_; + } + SPROUT_CONSTEXPR IntType denominator() const { + return den_; + } + + rational& operator+=(rational const& rhs) { + IntType g = sprout::math::gcd(den_, rhs.den_); + den_ /= g; + num_ = num_ * (rhs.den_ / g) + rhs.num_ * den_; + g = sprout::math::gcd(num_, g); + num_ /= g; + den_ *= rhs.den_ / g; + return *this; + } + rational& operator-=(rational const& rhs) { + IntType g = sprout::math::gcd(den_, rhs.den_); + den_ /= g; + num_ = num_ * (rhs.den_ / g) - rhs.num_ * den_; + g = sprout::math::gcd(num_, g); + num_ /= g; + den_ *= rhs.den_ / g; + return *this; + } + rational& operator*=(rational const& rhs) { + IntType gcd1 = sprout::math::gcd(num_, rhs.den_); + IntType gcd2 = sprout::math::gcd(rhs.num_, den_); + num_ =(num_ / gcd1) * (rhs.num_ / gcd2); + den_ =(den_ / gcd2) * (rhs.den_ / gcd1); + return *this; + } + rational& operator/=(rational const& rhs) { + if (rhs.num_ == IntType(0)) { + throw bad_rational(); + } + if (num_ == IntType(0)) { + return *this; + } + IntType gcd1 = sprout::math::gcd(num_, rhs.num_); + IntType gcd2 = sprout::math::gcd(rhs.den_, den_); + num_ =(num_ / gcd1) * (rhs.den_ / gcd2); + den_ =(den_ / gcd2) * (rhs.num_ / gcd1); + if (den_ < IntType(0)) { + num_ = -num_; + den_ = -den_; + } + return *this; + } + rational& operator+=(param_type rhs) { + return *this += rational(rhs); + } + rational& operator-=(param_type rhs) { + return *this -= rational(rhs); + } + rational& operator*=(param_type rhs) { + return *this *= rational(rhs); + } + rational& operator/=(param_type rhs) { + return *this /= rational(rhs); + } + + rational& operator++() { + num_ += den_; + return *this; + } + rational& operator--() { + num_ -= den_; + return *this; + } + rational operator++(int) { + rational result(*this); + ++*this; + return result; + } + rational operator--(int) { + rational result(*this); + --*this; + return result; + } + + SPROUT_CONSTEXPR bool operator!() const { + return !num_; + } + SPROUT_CONSTEXPR operator bool() const { + return num_ != 0; + } + + public: + friend sprout::rational sprout::detail::make_rational( + typename sprout::detail::call_traits::param_type n, + typename sprout::detail::call_traits::param_type d, + sprout::detail::rational_private_constructor_tag + ); + }; + + namespace detail { + template + inline SPROUT_CONSTEXPR sprout::rational make_rational( + typename sprout::detail::call_traits::param_type n, + typename sprout::detail::call_traits::param_type d, + sprout::detail::rational_private_constructor_tag + ) + { + return sprout::rational( + n, d, + typename sprout::rational::private_constructor_tag() + ); + } + } // namespace detail +} // namespace sprout + +#endif // SPROUT_RATIONAL_RATIONAL_HPP diff --git a/sprout/rational/values.hpp b/sprout/rational/values.hpp new file mode 100644 index 00000000..0b7cdd4d --- /dev/null +++ b/sprout/rational/values.hpp @@ -0,0 +1,24 @@ +#ifndef SPROUT_RATIONAL_VALUES_HPP +#define SPROUT_RATIONAL_VALUES_HPP + +#include +#include +#include + +namespace sprout { + // + // abs + // + template + inline SPROUT_CONSTEXPR sprout::rational + abs(sprout::rational const& x) { + return x.numerator() >= IntType(0) ? x + : sprout::detail::make_rational( + -x.numerator(), x.denominator(), + sprout::detail::rational_private_constructor_tag() + ) + ; + } +} // namespace sprout + +#endif // SPROUT_RATIONAL_VALUES_HPP diff --git a/sprout/utility/pair.hpp b/sprout/utility/pair.hpp index 6c0eb7d3..f909ae28 100644 --- a/sprout/utility/pair.hpp +++ b/sprout/utility/pair.hpp @@ -1,6 +1,7 @@ #ifndef SPROUT_UTILITY_PAIR_HPP #define SPROUT_UTILITY_PAIR_HPP +#include #include #include #include @@ -9,6 +10,7 @@ #include #include #include +#include namespace sprout { // Copyright (C) 2011 RiSK (sscrisk) @@ -143,7 +145,7 @@ namespace sprout { // swap // template - inline void swap(pair& x, pair& y) SPROUT_NOEXCEPT_EXPR(SPROUT_NOEXCEPT_EXPR(x.swap(y))) { + inline void swap(sprout::pair& x, sprout::pair& y) SPROUT_NOEXCEPT_EXPR(SPROUT_NOEXCEPT_EXPR(x.swap(y))) { x.swap(y); } @@ -164,6 +166,14 @@ namespace sprout { sprout::forward(y) ); } + + // + // hash_value + // + template + inline SPROUT_CONSTEXPR std::size_t hash_value(sprout::pair const& v) { + return sprout::hash_values(v.first, v.second); + } } // namespace sprout namespace sprout {