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
|