Wildmeshing Toolkit
Loading...
Searching...
No Matches
Rational.cpp
Go to the documentation of this file.
1#include "Rational.hpp"
2
3#include <cassert>
4#include <cmath>
5#include <limits>
6#include <sstream>
7
8namespace wmtk {
10{
11 if (m_is_rounded) return;
12 mpq_canonicalize(value);
13}
14
16{
17 if (m_is_rounded) return d_value == 0 ? 0 : (d_value < 0 ? -1 : 1);
18
19 return mpq_sgn(value);
20}
21
22Rational::Rational(bool rounded)
23 : Rational(0.0, rounded)
24{}
25
26Rational::Rational(int v, bool rounded)
27 : Rational((double)v, rounded)
28{}
29
30Rational::Rational(double d, bool rounded)
31 : m_is_rounded(rounded)
32{
33 if (m_is_rounded) {
34 d_value = d;
35 } else {
36 mpq_init(value);
37 mpq_set_d(value, d);
38
39 d_value = std::numeric_limits<double>::lowest();
40 // canonicalize();
41 }
42}
43
44Rational::Rational(const mpq_t& v_)
45{
46 mpq_init(value);
47 mpq_set(value, v_);
48 // canonicalize();
49 m_is_rounded = false;
50
51 d_value = std::numeric_limits<double>::lowest();
52}
53
55 : d_value(other.d_value)
56 , m_is_rounded(other.m_is_rounded)
57{
58 if (!m_is_rounded) {
59 mpq_init(value);
60 mpq_set(value, other.value);
61 }
62}
63Rational::Rational(const Rational& other, bool rounded)
64 : d_value(other.d_value)
65 , m_is_rounded(rounded)
66{
67 if (!m_is_rounded) {
68 mpq_init(value);
69
70 if (other.m_is_rounded)
71 mpq_set_d(value, other.d_value);
72 else
73 mpq_set(value, other.value);
74
75 d_value = std::numeric_limits<double>::lowest();
76 } else {
77 d_value = other.to_double();
78 }
79}
80
81
82Rational::Rational(const std::string& data, bool rounded)
83 : m_is_rounded(rounded)
84{
85 if (m_is_rounded) {
86 mpq_t tmp_r;
87 mpq_init(tmp_r);
88 mpq_set_str(tmp_r, data.c_str(), 10);
89
90 d_value = mpq_get_d(tmp_r);
91 mpq_clear(tmp_r);
92 } else {
93 mpq_init(value);
94 mpq_set_str(value, data.c_str(), 10);
95 d_value = std::numeric_limits<double>::lowest();
96 }
97}
98
100{
101 if (!m_is_rounded) mpq_clear(value);
102}
103
105{
106 if (x.m_is_rounded && y.m_is_rounded) {
107 return Rational(x.d_value + y.d_value, true);
108 }
109
110 Rational r_out;
111
112 if (x.m_is_rounded && !y.m_is_rounded) {
113 mpq_t tmp;
114 mpq_init(tmp);
115 mpq_set_d(tmp, x.d_value);
116 mpq_add(r_out.value, tmp, y.value);
117 mpq_clear(tmp);
118 } else if (!x.m_is_rounded && y.m_is_rounded) {
119 mpq_t tmp;
120 mpq_init(tmp);
121 mpq_set_d(tmp, y.d_value);
122 mpq_add(r_out.value, x.value, tmp);
123 mpq_clear(tmp);
124 } else
125 mpq_add(r_out.value, x.value, y.value);
126
127 return r_out;
128}
129
131{
132 if (x.m_is_rounded && y.m_is_rounded) {
133 return Rational(x.d_value - y.d_value, true);
134 }
135
136 Rational r_out;
137
138 if (x.m_is_rounded && !y.m_is_rounded) {
139 mpq_t tmp;
140 mpq_init(tmp);
141 mpq_set_d(tmp, x.d_value);
142 mpq_sub(r_out.value, tmp, y.value);
143 mpq_clear(tmp);
144 } else if (!x.m_is_rounded && y.m_is_rounded) {
145 mpq_t tmp;
146 mpq_init(tmp);
147 mpq_set_d(tmp, y.d_value);
148 mpq_sub(r_out.value, x.value, tmp);
149 mpq_clear(tmp);
150 } else
151 mpq_sub(r_out.value, x.value, y.value);
152
153 return r_out;
154}
155
156
158{
159 if (x.m_is_rounded) return Rational(-x.d_value, true);
160
161 Rational r_out;
162 mpq_neg(r_out.value, x.value);
163 return r_out;
164}
165
166Rational pow(const Rational& x, int p)
167{
168 if (x.m_is_rounded) return Rational(std::pow(x.d_value, p), true);
169
170 Rational r_out = x;
171 for (int i = 1; i < std::abs(p); i++) {
172 r_out = r_out * x;
173 }
174 if (p < 0) return Rational(1.0, false) / r_out;
175 return r_out;
176}
177
179{
180 if (x.m_is_rounded && y.m_is_rounded) {
181 return Rational(x.d_value * y.d_value, true);
182 }
183
184 Rational r_out;
185
186 if (x.m_is_rounded && !y.m_is_rounded) {
187 mpq_t tmp;
188 mpq_init(tmp);
189 mpq_set_d(tmp, x.d_value);
190 mpq_mul(r_out.value, tmp, y.value);
191 mpq_clear(tmp);
192 } else if (!x.m_is_rounded && y.m_is_rounded) {
193 mpq_t tmp;
194 mpq_init(tmp);
195 mpq_set_d(tmp, y.d_value);
196 mpq_mul(r_out.value, x.value, tmp);
197 mpq_clear(tmp);
198 } else
199 mpq_mul(r_out.value, x.value, y.value);
200
201 return r_out;
202}
203
205{
206 if (x.m_is_rounded && y.m_is_rounded) {
207 return Rational(x.d_value / y.d_value, true);
208 }
209
210 Rational r_out;
211
212 if (x.m_is_rounded && !y.m_is_rounded) {
213 mpq_t tmp;
214 mpq_init(tmp);
215 mpq_set_d(tmp, x.d_value);
216 mpq_div(r_out.value, tmp, y.value);
217 mpq_clear(tmp);
218 } else if (!x.m_is_rounded && y.m_is_rounded) {
219 mpq_t tmp;
220 mpq_init(tmp);
221 mpq_set_d(tmp, y.d_value);
222 mpq_div(r_out.value, x.value, tmp);
223 mpq_clear(tmp);
224 } else
225 mpq_div(r_out.value, x.value, y.value);
226
227 return r_out;
228}
229
231{
232 if (this == &x) return *this;
233
234 if (!m_is_rounded) mpq_clear(value);
235
237 d_value = x.d_value;
238
239 if (!x.m_is_rounded) { //&& !m_is_rounded
240 mpq_init(value);
241 mpq_set(value, x.value);
242 }
243
244 return *this;
245}
246
248{
249 if (m_is_rounded)
250 d_value = x;
251 else {
252 mpq_set_d(value, x);
253 d_value = std::numeric_limits<double>::lowest();
254 }
255 // canonicalize();
256 return *this;
257}
258
259int cmp(const Rational& r, const Rational& r1)
260{
261 if (r.m_is_rounded && r1.m_is_rounded)
262 return r.d_value == r1.d_value ? 0 : (r.d_value > r1.d_value ? 1 : -1);
263
264 if (r.m_is_rounded && !r1.m_is_rounded) {
265 mpq_t tmp;
266 mpq_init(tmp);
267 mpq_set_d(tmp, r.d_value);
268 int res = mpq_cmp(tmp, r1.value);
269 mpq_clear(tmp);
270 return res;
271 }
272
273 if (!r.m_is_rounded && r1.m_is_rounded) {
274 mpq_t tmp;
275 mpq_init(tmp);
276 mpq_set_d(tmp, r1.d_value);
277 int res = mpq_cmp(r.value, tmp);
278 mpq_clear(tmp);
279 return res;
280 }
281
282 return mpq_cmp(r.value, r1.value);
283}
284
285
286bool operator==(const Rational& r, const Rational& r1)
287{
288 if (r.m_is_rounded && r1.m_is_rounded) return r.d_value == r1.d_value;
289
290 if (r.m_is_rounded && !r1.m_is_rounded) {
291 mpq_t tmp;
292 mpq_init(tmp);
293 mpq_set_d(tmp, r.d_value);
294 bool res = mpq_equal(tmp, r1.value);
295 mpq_clear(tmp);
296 return res;
297 }
298
299 if (!r.m_is_rounded && r1.m_is_rounded) {
300 mpq_t tmp;
301 mpq_init(tmp);
302 mpq_set_d(tmp, r1.d_value);
303 bool res = mpq_equal(r.value, tmp);
304 mpq_clear(tmp);
305 return res;
306 }
307
308 return mpq_equal(r.value, r1.value);
309}
310
311bool operator!=(const Rational& r, const Rational& r1)
312{
313 return !(r == r1);
314}
315
316// to double
318{
319 if (m_is_rounded) return d_value;
320 return mpq_get_d(value);
321}
322
323Rational::operator double() const
324{
325 return to_double();
326}
327
329{
330 if (r0.m_is_rounded) {
331 return Rational(std::abs(r0.d_value), true);
332 } else {
333 Rational r;
334 mpq_abs(r.value, r0.value);
335 return r;
336 }
337}
338
339//<<
340std::ostream& operator<<(std::ostream& os, const Rational& r)
341{
342 os << r.to_double();
343 return os;
344}
345
346void Rational::init_from_binary(const std::string& v)
347{
348 mpq_set_str(value, v.c_str(), 2);
349}
350std::string Rational::to_binary() const
351{
352 if (m_is_rounded) {
353 mpq_t tmp;
354 mpq_init(tmp);
355 mpq_set_d(tmp, d_value);
356
357 std::string v(mpq_get_str(NULL, 2, tmp));
358 mpq_clear(tmp);
359 return v;
360 }
361
362 std::string v(mpq_get_str(NULL, 2, value));
363 return v;
364}
365
366std::string Rational::serialize() const
367{
368 return numerator() + "/" + denominator() + "/" + (m_is_rounded ? "1" : "0");
369}
370
371Rational::Rational(const Eigen::VectorX<char>& data)
372{
373 std::stringstream numss;
374 std::stringstream denomss;
375 int counter = 0;
376 for (int64_t i = 0; i < data.size(); ++i) {
377 if (data[i] == '/') {
378 ++counter;
379 continue;
380 }
381
382 if (counter == 0)
383 numss << data[i];
384 else if (counter == 1)
385 denomss << data[i];
386 else {
387 assert(data[i] == '0' || data[i] == '1');
388 m_is_rounded = data[i] == '1';
389 break;
390 }
391 }
392
393 const auto num = numss.str();
394 const auto denom = denomss.str();
395
396 // const auto num = tokens[0];
397 // const auto denom = tokens[1];
398
399 // std::regex regex{R"([/]+)"}; // split on /
400 // std::sregex_token_iterator it{data.begin(), data.end(), regex, -1};
401 // std::vector<std::string> tokens{it, {}};
402 // assert(tokens.size() >= 3);
403
404 // const auto num = tokens[0];
405 // const auto denom = tokens[1];
406 // assert(tokens[2][0] == '0' || tokens[2][0] == '1');
407 // m_is_rounded = tokens[2][0] == '1';
408
409 if (m_is_rounded) {
410 mpq_t tmp_r;
411 mpq_init(tmp_r);
412 std::string tmp = num + "/" + denom;
413 mpq_set_str(tmp_r, tmp.c_str(), 10);
414
415 d_value = mpq_get_d(tmp_r);
416 mpq_clear(tmp_r);
417
418 } else {
419 mpq_init(value);
420 std::string tmp = num + "/" + denom;
421 mpq_set_str(value, tmp.c_str(), 10);
422 d_value = std::numeric_limits<double>::lowest();
423 }
424}
425
426
427std::string Rational::numerator() const
428{
429 mpq_t tmp;
430 mpq_init(tmp);
431 if (m_is_rounded)
432 mpq_set_d(tmp, d_value);
433 else
434 mpq_set(tmp, value);
435
436
437 mpz_t num;
438 mpz_init(num);
439
440 mpq_get_num(num, tmp);
441 std::string v(mpz_get_str(NULL, 10, num));
442
443 mpz_clear(num);
444 mpq_clear(tmp);
445
446 return v;
447}
448
449std::string Rational::denominator() const
450{
451 mpq_t tmp;
452 mpq_init(tmp);
453 if (m_is_rounded)
454 mpq_set_d(tmp, d_value);
455 else
456 mpq_set(tmp, value);
457
458 mpz_t denom;
459 mpz_init(denom);
460 mpq_get_den(denom, tmp);
461
462 std::string v(mpz_get_str(NULL, 10, denom));
463
464 mpz_clear(denom);
465 mpq_clear(tmp);
466
467 return v;
468}
469
470} // namespace wmtk
Rational(bool rounded=false)
Definition Rational.cpp:22
double to_double() const
Definition Rational.cpp:317
std::string numerator() const
Definition Rational.cpp:427
Rational & operator=(const Rational &x)
Definition Rational.cpp:230
std::string serialize() const
Definition Rational.cpp:366
void init_from_binary(const std::string &v)
Definition Rational.cpp:346
std::string denominator() const
Definition Rational.cpp:449
void canonicalize()
Definition Rational.cpp:9
std::string to_binary() const
Definition Rational.cpp:350
int get_sign() const
Definition Rational.cpp:15
int cmp(const Rational &r, const Rational &r1)
Definition Rational.cpp:259
constexpr bool operator!=(PrimitiveType a, PrimitiveType b)
constexpr bool operator==(PrimitiveType a, PrimitiveType b)
Rational abs(const Rational &r0)
Definition Rational.cpp:328
constexpr PrimitiveType operator-(PrimitiveType pt, int8_t n)
Rational operator/(const Rational &x, const Rational &y)
Definition Rational.cpp:204
std::ostream & operator<<(std::ostream &os, const Tuple &t)
Definition Tuple.cpp:22
Rational operator*(const Rational &x, const Rational &y)
Definition Rational.cpp:178
Rational pow(const Rational &x, int p)
Definition Rational.cpp:166
constexpr PrimitiveType operator+(PrimitiveType pt, int8_t n)