Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #ifndef CUMMAS_RATIONAL_H
- #define CUMMAS_RATIONAL_H
- #include <iostream>
- #include <cmath>
- #include <string>
- #include <sstream>
- #include <random>
- #include <type_traits>
- #include <common.cuh>
- template <typename T>
- class Rational
- {
- public:
- constexpr __host__ __device__ Rational() = default;
- constexpr __host__ __device__ Rational(
- T num /*= static_cast<T>(0)*/,
- T den/* = static_cast<T>(1)*/) noexcept:
- num{num},
- den{den}
- {
- static_assert(std::is_integral_v<T> && std::is_signed_v<T>, "Underlying type must be of integral type");
- Make();
- }
- constexpr __host__ __device__ void Make() noexcept
- {
- // See https://godbolt.org/z/jeK5z7 for optimisations
- // make5 is significally faster (no conditionals),
- // but relies on the fact that last bit is a sign bit
- if (den < 0)
- {
- num = -num;
- den = -den;
- }
- }
- #pragma region operators
- template <typename T>
- friend std::ostream& operator << (std::ostream& , Rational<T> const&) noexcept;
- template <typename T>
- friend std::istream& operator >> (std::istream& , Rational<T>&) noexcept;
- template <typename T>
- constexpr __host__ __device__ friend Rational<T> const operator + (Rational<T> const& lhs, Rational<T> const& rhs) noexcept;
- template <typename T>
- constexpr __host__ __device__ friend Rational<T> const operator - (Rational<T> const&, Rational<T> const&) noexcept;
- template <typename T>
- constexpr __host__ __device__ friend Rational<T> const operator* (Rational<T> const&, Rational<T> const&) noexcept;
- template <typename T>
- constexpr __host__ __device__ friend Rational<T> const operator/ (Rational<T> const&, Rational<T> const&) noexcept;
- template <typename T>
- constexpr __host__ __device__ friend bool operator < (Rational<T> const&, Rational<T> const&) noexcept;
- template <typename T>
- constexpr __host__ __device__ friend bool operator == (Rational<T> const&, Rational<T> const&) noexcept;
- template <typename T>
- constexpr __host__ __device__ friend bool operator > (Rational<T> const&, Rational<T> const&) noexcept;
- template <typename T>
- constexpr __host__ __device__ friend bool operator <= (Rational<T> const&, Rational<T> const&) noexcept;
- template <typename T>
- constexpr __host__ __device__ friend bool operator >= (Rational<T> const&, Rational<T> const&) noexcept;
- template <typename T>
- constexpr __host__ __device__ friend bool operator != (Rational<T> const&, Rational<T> const&) noexcept;
- #pragma endregion
- template <typename T>
- constexpr __host__ __device__ friend Rational<T> const fabs (Rational<T> const&) noexcept;
- template <typename T>
- constexpr __host__ __device__ friend Rational<T> const gcd (Rational<T> const&) noexcept;
- template <typename T>
- __host__ friend Rational<T> const random(Rational<T> const&) noexcept;
- private:
- int num, den;
- };
- #pragma region constants
- template <typename T>
- struct Id<Rational<T>>
- {
- constexpr static Rational<T> value{Rational<T>{1, 1}};
- };
- template <typename T>
- struct Zero<Rational<T>>
- {
- constexpr static Rational<T> value{Rational<T>{0, 1}};
- };
- template <typename T>
- struct mId<Rational<T>>
- {
- constexpr static Rational<T> value{Rational<T>{-1, 1}};
- };
- #pragma endregion
- #pragma region operators
- template <typename T>
- [[nodiscard]] constexpr __host__ __device__ Rational<T> const gcd (Rational<T> const& lhs) noexcept
- {
- if (lhs.num==0)
- return Rational<T>(0, 1);
- int a=abs(lhs.num);
- int b=abs(lhs.den);
- while (a != b)
- {
- if (a > b)
- {
- int tmp = a;
- a = b;
- b = tmp;
- }
- b = b - a;
- }
- return Rational<T>(lhs.num/a, lhs.den/a);
- }
- template <typename T>
- [[nodiscard]] std::ostream& operator <<(std::ostream& ost, Rational<T> const& r) noexcept
- {
- return ost << r.num << '/' << r.den;
- }
- template <typename T>
- [[nodiscard]] std::istream& operator>>(std::istream& ist, Rational<T>& r) noexcept// e.g. (5, -2)
- {
- std::string s;
- std::getline(ist, s, ')');
- std::string::size_type ind;
- while((ind = s.find_first_of("(,)")) != std::string::npos)
- s.replace(ind, 1, 1, ' ');
- std::istringstream iss(s);
- iss >> r.num >> r.den;
- r.Make();
- return ist;
- }
- template <typename T>
- [[nodiscard]] __host__ Rational<T> const random(Rational<T> const& lhs) noexcept
- {
- std::random_device random_device; // Entropy source
- std::mt19937 generator(random_device());
- std::uniform_int_distribution<> distribution(lhs.num, lhs.den);
- return gcd(Rational<T>(distribution(generator), 1));
- }
- template <typename T>
- [[nodiscard]] constexpr __host__ __device__ Rational<T> const fabs (Rational<T> const& lhs) noexcept
- {
- return gcd(Rational<T>(abs(lhs.num), abs(lhs.den)));
- }
- template <typename T>
- [[nodiscard]] constexpr __host__ __device__ Rational<T> const operator + (Rational<T> const& lhs, Rational<T> const& rhs) noexcept
- {
- return gcd(Rational<T>(lhs.num * rhs.den + rhs.num * lhs.den, lhs.den * rhs.den));
- }
- template <typename T>
- [[nodiscard]] constexpr __host__ __device__ Rational<T> const operator - (Rational<T> const& lhs, Rational<T> const& rhs) noexcept
- {
- return gcd(lhs + Rational<T>(-rhs.num, rhs.den));
- }
- template <typename T>
- [[nodiscard]] constexpr __host__ __device__ Rational<T> const operator * (Rational<T> const& lhs, Rational<T> const& rhs) noexcept
- {
- return gcd(Rational<T>(lhs.num * rhs.num, lhs.den * rhs.den));
- }
- template <typename T>
- [[nodiscard]] constexpr __host__ __device__ Rational<T> const operator / (Rational<T> const& lhs, Rational<T> const& rhs) noexcept
- {
- return gcd(lhs * Rational<T>(rhs.den, rhs.num));
- }
- template <typename T>
- [[nodiscard]] constexpr __host__ __device__ bool operator < (Rational<T> const& lhs, Rational<T> const& rhs) noexcept
- {
- return double(lhs.num) / lhs.den < double(rhs.num) / rhs.den;
- }
- template <typename T>
- [[nodiscard]] constexpr __host__ __device__ bool operator == (Rational<T> const& lhs, Rational<T> const& rhs) noexcept
- {
- return !(lhs < rhs || rhs < lhs);
- }
- template <typename T>
- [[nodiscard]] constexpr __host__ __device__ bool operator != (Rational<T> const& lhs, Rational<T> const& rhs) noexcept
- {
- return (lhs < rhs || rhs < lhs);
- }
- template <typename T>
- [[nodiscard]] constexpr __host__ __device__ bool operator> (Rational<T> const& lhs, Rational<T> const& rhs) noexcept
- {
- return rhs < lhs;
- }
- template <typename T>
- [[nodiscard]] constexpr __host__ __device__ bool operator<= (Rational<T> const& lhs, Rational<T> const& rhs) noexcept
- {
- return !(rhs < lhs);
- }
- template <typename T>
- [[nodiscard]] constexpr __host__ __device__ bool operator>= (Rational<T> const& lhs, Rational<T> const& rhs) noexcept
- {
- return !(lhs < rhs);
- }
- #pragma endregion
- #endif // CUMMAS_Rational<T>_H
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement