The Sparta Modeling Framework
Loading...
Searching...
No Matches
Rational.hpp
1// <Rational.hpp> -*- C++ -*-
2
3#pragma once
4
5#include <iostream>
6#include <sstream>
7#include <inttypes.h>
8#include <cassert>
9#include "sparta/utils/MathUtils.hpp"
10
11namespace sparta
12{
13namespace utils
14{
19 template <class T>
21 {
22 public:
23 Rational(const T &numerator = 0, const T &denominator = 1):
24 n_(numerator),
25 d_(denominator)
26 {
27 assert(denominator != 0);
28 simplify();
29 }
30
31 Rational(const Rational<T> &r):
32 n_(r.n_), d_(r.d_)
33 {}
34
35 inline T getNumerator() const
36 {
37 return n_;
38 }
39
40 inline T getDenominator() const
41 {
42 return d_;
43 }
44
45 explicit inline operator T() const
46 {
47 assert(d_ == 1);
48 return n_;
49 }
50
51 explicit inline operator double() const
52 {
53 return double(n_) / double(d_);
54 }
55
56 inline Rational<T>& operator=(const Rational<T> &r)
57 {
58 if (&r != this) {
59 n_ = r.n_;
60 d_ = r.d_;
61 }
62 return *this;
63 }
64
65 explicit inline operator std::string() const
66 {
67 std::stringstream ss;
68 if (d_ == 0) {
69 if (n_ == 0) {
70 ss << "NaN";
71 } else {
72 ss << "INF";
73 }
74 }
75 else if (n_ == 0) {
76 ss << "0";
77 }
78 else if (d_ == 1) {
79 ss << n_;
80 } else {
81 ss << n_ << "/" << d_;
82 }
83 return ss.str();
84 }
85
86 inline void print(std::ostream& os) const
87 {
88 os << this->operator std::string();
89 }
90
91 inline void simplify()
92 {
93 if (d_ != 0) {
94 if (n_ == 0) {
95 d_ = 1;
96 } else {
97 T g = utils::gcd(n_, d_);
98 if (g > 1) {
99 n_ /= g;
100 d_ /= g;
101 }
102 }
103 }
104 }
105
106 inline Rational<T> operator*(const Rational<T> &r) const
107 {
108 return Rational<T>(n_ * r.n_, d_ * r.d_);
109 }
110
111 inline Rational<T>& operator*=(const Rational<T> &r)
112 {
113 n_ *= r.n_;
114 d_ *= r.d_;
115 simplify();
116 return *this;
117 }
118
119 inline Rational<T> operator/(const Rational<T> &r) const
120 {
121 return Rational<T>(n_ * r.d_, d_ * r.n_);
122 }
123
124 inline Rational<T>& operator/=(const Rational<T> &r)
125 {
126 if (&r != this) {
127 n_ *= r.d_;
128 d_ *= r.n_;
129 } else {
130 T x = r.n_;
131 n_ *= r.d_;
132 d_ *= x;
133 }
134 simplify();
135 return *this;
136 }
137
138 inline Rational<T> operator+(const Rational<T> &r) const
139 {
140 if (d_ != r.d_) {
141 T m = utils::lcm(d_, r.d_);
142 return Rational<T>((n_ * m / d_) + (r.n_ * m / r.d_), m);
143 } else {
144 return Rational<T>(n_ + r.n_, d_);
145 }
146 }
147
148 inline Rational<T>& operator+=(const Rational<T> &r)
149 {
150 if (d_ != r.d_) {
151 T m = utils::lcm(d_, r.d_);
152 n_ = (n_ * m / d_) + (r.n_ * m / r.d_);
153 d_ = m;
154 } else {
155 n_ += r.n_;
156 }
157 simplify();
158 return *this;
159 }
160
161 // Computes absolute difference
162 inline Rational<T> operator-(const Rational<T> &r) const
163 {
164 if (d_ != r.d_) {
165 T m = utils::lcm(d_, r.d_);
166 return Rational<T>(utils::abs((n_ * m / d_) - (r.n_ * m / r.d_)), m);
167 } else {
168 return Rational<T>(utils::abs(n_ - r.n_), d_);
169 }
170 }
171
172 inline Rational<T>& operator-=(const Rational<T> &r)
173 {
174 if (d_ != r.d_) {
175 T m = utils::lcm(d_, r.d_);
176 n_ = utils::abs((n_ * m / d_) - (r.n_ * m / r.d_));
177 d_ = m;
178 } else {
179 n_ = utils::abs(n_ - r.n_);
180 }
181 simplify();
182 return *this;
183 }
184
185 // Invert
186 inline Rational<T> inv()
187 {
188 return Rational<T>(d_, n_);
189 }
190
191 inline bool operator==(const Rational<T> &r)
192 {
193 Rational<T> t(r);
194 t.simplify();
195 return (n_ == t.n_) && (d_ == t.d_);
196 }
197
198 private:
199 T n_; // Numerator
200 T d_; // Denominator
201 };
202
203 template <class T>
204 inline std::ostream& operator<<(std::ostream& os, const sparta::utils::Rational<T>& r)
205 {
206 r.print(os);
207 return os;
208 }
209
210} // utils
211} // sparta
Class to represent a Rational number.
Definition Rational.hpp:21
Macros for handling exponential backoff.
std::ostream & operator<<(std::ostream &o, const SimulationInfo &info)
ostream insertion operator for SimulationInfo