Line data Source code
1 0 : // Distributed under the MIT License. 2 : // See LICENSE.txt for details. 3 : 4 : #pragma once 5 : 6 : #include <cstddef> 7 : #include <cstdint> 8 : #include <functional> 9 : #include <iosfwd> 10 : 11 : #include "Utilities/ErrorHandling/Assert.hpp" 12 : #include "Utilities/MakeWithValue.hpp" 13 : #include "Utilities/Requires.hpp" 14 : #include "Utilities/TypeTraits/IsInteger.hpp" 15 : 16 : /// \cond 17 : namespace PUP { 18 : class er; 19 : } // namespace PUP 20 : /// \endcond 21 : 22 : /// \ingroup UtilitiesGroup 23 : /// A rational number 24 : /// 25 : /// This serves as a faster replacement for 26 : /// `boost::rational<std::int32_t>`. As of Boost 1.65.0, arithmetic 27 : /// operators average about twice as fast, and ordering operators are 28 : /// about eight times as fast. 29 1 : class Rational { 30 : public: 31 0 : Rational() = default; 32 0 : Rational(std::int32_t numerator, std::int32_t denominator); 33 : 34 : // Allow implicit conversion of integers to Rationals, but don't 35 : // allow doubles to implicitly convert to an integer and then to a 36 : // Rational. 37 : template <typename T, Requires<tt::is_integer_v<T>> = nullptr> 38 : // NOLINTNEXTLINE(google-explicit-constructor,readability-avoid-const-params-in-decls) 39 0 : Rational(const T integral_value) : Rational(integral_value, 1) {} 40 : 41 0 : std::int32_t numerator() const { return numerator_; } 42 0 : std::int32_t denominator() const { return denominator_; } 43 : 44 0 : double value() const; 45 : 46 0 : Rational inverse() const; 47 : 48 0 : Rational& operator+=(const Rational& other); 49 0 : Rational& operator-=(const Rational& other); 50 0 : Rational& operator*=(const Rational& other); 51 0 : Rational& operator/=(const Rational& other); 52 : 53 : // NOLINTNEXTLINE(google-runtime-references) 54 0 : void pup(PUP::er& p); 55 : 56 0 : friend Rational operator-(Rational r); 57 : 58 : private: 59 0 : std::int32_t numerator_{0}; 60 0 : std::int32_t denominator_{1}; 61 : }; 62 : 63 0 : Rational operator+(const Rational& a, const Rational& b); 64 0 : Rational operator-(const Rational& a, const Rational& b); 65 0 : Rational operator*(const Rational& a, const Rational& b); 66 0 : Rational operator/(const Rational& a, const Rational& b); 67 : 68 0 : bool operator==(const Rational& a, const Rational& b); 69 0 : bool operator!=(const Rational& a, const Rational& b); 70 0 : bool operator<(const Rational& a, const Rational& b); 71 0 : bool operator>(const Rational& a, const Rational& b); 72 0 : bool operator<=(const Rational& a, const Rational& b); 73 0 : bool operator>=(const Rational& a, const Rational& b); 74 : 75 0 : Rational abs(const Rational& r); 76 : 77 0 : std::ostream& operator<<(std::ostream& os, const Rational& r); 78 : 79 0 : size_t hash_value(const Rational& r); 80 : 81 : namespace std { 82 : template <> 83 : struct hash<Rational> { 84 : size_t operator()(const Rational& r) const; 85 : }; 86 : } // namespace std 87 : 88 : namespace MakeWithValueImpls { 89 : template <typename T> 90 0 : struct MakeWithValueImpl<Rational, T> { 91 0 : static Rational apply(const T& /*input*/, double value) { 92 : ASSERT(static_cast<std::int32_t>(value) == value, 93 : "Only integer-valued Rationals can be created with MakeWithValue."); 94 : return Rational(static_cast<std::int32_t>(value)); 95 : } 96 : }; 97 : } // namespace MakeWithValueImpls