ProjGeom 1.0.11
Loading...
Searching...
No Matches
fractions.hpp
Go to the documentation of this file.
1// -*- coding: utf-16 -*-
2#pragma once
3
8// #include <boost/operators.hpp>
9// #include <cmath>
10#include <numeric>
11#include <type_traits>
12#include <utility>
13
14#include "common_concepts.h"
15
16namespace fun {
17
25 template <typename T> constexpr auto abs(const T& a) -> T {
26 if constexpr (std::is_unsigned_v<T>) {
27 return a;
28 } else {
29 return (a < T(0)) ? -a : a;
30 }
31 }
32
41 template <Integral Mn> constexpr auto gcd_recur(const Mn& _m, const Mn& _n) -> Mn {
42 if (_n == 0) {
43 return abs(_m);
44 }
45 return gcd_recur(_n, _m % _n);
46 }
47
62 template <Integral Mn> constexpr auto gcd(const Mn& _m, const Mn& _n) -> Mn {
63 if (_m == 0) {
64 return abs(_n);
65 }
66 return gcd_recur(_m, _n);
67 }
68
80 template <Integral Mn> constexpr auto lcm(const Mn& _m, const Mn& _n) -> Mn {
81 if (_m == 0 || _n == 0) {
82 return 0;
83 }
84 return (abs(_m) / gcd(_m, _n)) * abs(_n);
85 }
86
92 template <Integral Z> struct Fraction {
95
102 constexpr Fraction(Z num, Z den) : _num{std::move(num)}, _den{std::move(den)} {
103 this->normalize();
104 }
105
111 constexpr auto normalize() -> Z {
112 this->normalize1();
113 return this->normalize2();
114 }
115
121 constexpr void normalize1() {
122 if (this->_den < Z(0)) {
123 this->_num = -this->_num;
124 this->_den = -this->_den;
125 }
126 }
127
133 constexpr auto normalize2() -> Z {
134 Z common = gcd(this->_num, this->_den);
135 if (common == Z(1) || common == Z(0)) {
136 return common;
137 }
138 this->_num /= common;
139 this->_den /= common;
140 return common;
141 }
142
146 constexpr explicit Fraction(Z&& num) : _num{std::move(num)}, _den(Z(1)) {}
147
151 constexpr explicit Fraction(const Z& num) : _num{num}, _den(1) {}
152
156 constexpr Fraction() : _num(0), _den(1) {}
157
163 [[nodiscard]] constexpr auto num() const noexcept -> const Z& { return _num; }
164
170 [[nodiscard]] constexpr auto den() const noexcept -> const Z& { return _den; }
171
181 constexpr auto cross(const Fraction& rhs) const -> Z {
182 return this->_num * rhs._den - this->_den * rhs._num;
183 }
184
189
198 friend constexpr auto operator==(Fraction lhs, Z rhs) -> bool {
199 if (lhs._den == Z(1) || rhs == Z(0)) {
200 return lhs._num == rhs;
201 }
202 std::swap(lhs._den, rhs);
203 lhs.normalize2();
204 return lhs._num == lhs._den * rhs;
205 }
206
215 friend constexpr auto operator<(Fraction lhs, Z rhs) -> bool {
216 if (lhs._den == Z(1) || rhs == Z(0)) {
217 return lhs._num < rhs;
218 }
219 std::swap(lhs._den, rhs._num);
220 lhs.normalize2();
221 return lhs._num < lhs._den * rhs;
222 }
223
232 friend constexpr auto operator<(Z lhs, Fraction rhs) -> bool {
233 if (rhs._den == Z(1) || lhs == Z(0)) {
234 return lhs < rhs._num;
235 }
236 std::swap(rhs._den, lhs);
237 rhs.normalize2();
238 return rhs._den * lhs < rhs._num;
239 }
240
249 friend constexpr auto operator==(const Z& lhs, const Fraction& rhs) -> bool {
250 return rhs == lhs;
251 }
252
269 constexpr friend auto operator==(Fraction lhs, Fraction rhs) -> bool {
270 if (lhs._den == rhs._den) {
271 return lhs._num == rhs._num;
272 }
273 std::swap(lhs._den, rhs._num);
274 lhs.normalize2();
275 rhs.normalize2();
276 return lhs._num * rhs._den == lhs._den * rhs._num;
277 }
278
287 constexpr friend auto operator<(Fraction lhs, Fraction rhs) -> bool {
288 if (lhs._den == rhs._den) {
289 return lhs._num < rhs._num;
290 }
291 std::swap(lhs._den, rhs._num);
292 lhs.normalize2();
293 rhs.normalize2();
294 return lhs._num * rhs._den < lhs._den * rhs._num;
295 }
296
304 constexpr auto operator!=(const Fraction& rhs) const -> bool { return !(*this == rhs); }
305
313 constexpr auto operator>(const Fraction& rhs) const -> bool { return rhs < *this; }
314
322 constexpr auto operator>=(const Fraction& rhs) const -> bool { return !(*this < rhs); }
323
331 constexpr auto operator<=(const Fraction& rhs) const -> bool { return !(rhs < *this); }
332
340 constexpr auto operator>(const Z& rhs) const -> bool { return rhs < *this; }
341
349 constexpr auto operator<=(const Z& rhs) const -> bool { return !(rhs < *this); }
350
358 constexpr auto operator>=(const Z& rhs) const -> bool { return !(*this < rhs); }
359
368 friend constexpr auto operator>(const Z& lhs, const Fraction& rhs) -> bool {
369 return rhs < lhs;
370 }
371
380 friend constexpr auto operator<=(const Z& lhs, const Fraction& rhs) -> bool {
381 return !(rhs < lhs);
382 }
383
392 friend constexpr auto operator>=(const Z& lhs, const Fraction& rhs) -> bool {
393 return !(lhs < rhs);
394 }
395
397
402 constexpr void reciprocal() noexcept(std::is_nothrow_swappable_v<Z>) {
403 std::swap(this->_num, this->_den);
404 this->normalize1();
405 }
406
413 constexpr auto operator*=(Fraction rhs) -> Fraction& {
414 std::swap(this->_num, rhs._num);
415 this->normalize2();
416 rhs.normalize2();
417 this->_num *= rhs._num;
418 this->_den *= rhs._den;
419 return *this;
420 }
421
429 friend constexpr auto operator*(Fraction lhs, const Fraction& rhs) -> Fraction {
430 return lhs *= rhs;
431 }
432
439 constexpr auto operator*=(Z rhs) -> Fraction& {
440 std::swap(this->_num, rhs);
441 this->normalize2();
442 this->_num *= rhs;
443 return *this;
444 }
445
453 friend constexpr auto operator*(Fraction lhs, const Z& rhs) -> Fraction {
454 return lhs *= rhs;
455 }
456
464 friend constexpr auto operator*(const Z& lhs, Fraction rhs) -> Fraction {
465 return rhs *= lhs;
466 }
467
474 constexpr auto operator/=(Fraction rhs) -> Fraction& {
475 std::swap(this->_den, rhs._num);
476 this->normalize();
477 rhs.normalize2();
478 this->_num *= rhs._den;
479 this->_den *= rhs._num;
480 return *this;
481 }
482
490 friend constexpr auto operator/(Fraction lhs, const Fraction& rhs) -> Fraction {
491 return lhs /= rhs;
492 }
493
500 constexpr auto operator/=(const Z& rhs) -> Fraction& {
501 std::swap(this->_den, rhs);
502 this->normalize();
503 this->_den *= rhs;
504 return *this;
505 }
506
514 friend constexpr auto operator/(Fraction lhs, const Z& rhs) -> Fraction {
515 return lhs /= rhs;
516 }
517
525 friend constexpr auto operator/(const Z& lhs, Fraction rhs) -> Fraction {
526 rhs.reciprocal();
527 return rhs *= lhs;
528 }
529
535 constexpr auto operator-() const -> Fraction {
536 auto res = Fraction(*this);
537 res._num = -res._num;
538 return res;
539 }
540
547 constexpr auto operator+(const Fraction& rhs) const -> Fraction {
548 if (this->_den == rhs._den) {
549 return Fraction(this->_num + rhs._num, this->_den);
550 }
551 const auto common = gcd(this->_den, rhs._den);
552 if (common == Z(0)) {
553 return Fraction(rhs._den * this->_num + this->_den * rhs._num, Z(0));
554 }
555 const auto l = this->_den / common;
556 const auto r = rhs._den / common;
557 auto d = this->_den * r;
558 auto n = r * this->_num + l * rhs._num;
559 return Fraction(std::move(n), std::move(d));
560 }
561
568 constexpr auto operator-(const Fraction& frac) const -> Fraction { return *this + (-frac); }
569
577 friend constexpr auto operator+(Fraction frac, const Z& i) -> Fraction { return frac += i; }
578
586 friend constexpr auto operator+(const Z& i, Fraction frac) -> Fraction { return frac += i; }
587
594 constexpr auto operator-(const Z& i) const -> Fraction { return *this + (-i); }
595
602 constexpr auto operator+=(const Fraction& rhs) -> Fraction& { return *this -= (-rhs); }
603
610 constexpr auto operator-=(const Fraction& rhs) -> Fraction& {
611 if (this->_den == rhs._den) {
612 this->_num -= rhs._num;
613 this->normalize2();
614 return *this;
615 }
616
617 auto other{rhs};
618 std::swap(this->_den, other._num);
619 auto common_n = this->normalize2();
620 auto common_d = other.normalize2();
621 std::swap(this->_den, other._num);
622 this->_num = this->cross(other);
623 this->_den *= other._den;
624 std::swap(this->_den, common_d);
625 this->normalize2();
626 this->_num *= common_n;
627 this->_den *= common_d;
628 this->normalize2();
629 return *this;
630 }
631
638 constexpr auto operator+=(const Z& i) -> Fraction& { return *this -= (-i); }
639
646 constexpr auto operator-=(const Z& rhs) -> Fraction& {
647 if (this->_den == Z(1)) {
648 this->_num -= rhs;
649 return *this;
650 }
651
652 auto other{rhs};
653 std::swap(this->_den, other);
654 auto common_n = this->normalize2();
655 std::swap(this->_den, other);
656 this->_num -= other * this->_den;
657 this->_num *= common_n;
658 this->normalize2();
659 return *this;
660 }
661
669 friend constexpr auto operator-(const Z& c, const Fraction& frac) -> Fraction {
670 return c + (-frac);
671 }
672
680 friend constexpr auto operator+(int&& c, const Fraction& frac) -> Fraction {
681 return frac + Z(c);
682 }
683
691 friend constexpr auto operator-(int&& c, const Fraction& frac) -> Fraction {
692 return (-frac) + Z(c);
693 }
694
702 friend constexpr auto operator*(int&& c, const Fraction& frac) -> Fraction {
703 return frac * Z(c);
704 }
705
715 template <typename Stream> friend auto operator<<(Stream& os, const Fraction& frac)
716 -> Stream& {
717 os << "(" << frac.num() << "/" << frac.den() << ")";
718 return os;
719 }
720 };
721} // namespace fun
Common C++20 concepts: Ring, OrderedRing, Integral, Sequence.
Definition ck_concepts.hpp:11
constexpr auto lcm(const Mn &_m, const Mn &_n) -> Mn
Least common multiple.
Definition fractions.hpp:80
constexpr auto gcd_recur(const Mn &_m, const Mn &_n) -> Mn
Greatest common divider.
Definition fractions.hpp:41
constexpr auto abs(const T &a) -> T
absolute
Definition fractions.hpp:25
constexpr auto gcd(const Mn &_m, const Mn &_n) -> Mn
Greatest common divisor.
Definition fractions.hpp:62
Fraction.
Definition fractions.hpp:92
friend constexpr auto operator*(const Z &lhs, Fraction rhs) -> Fraction
multiply
Definition fractions.hpp:464
friend constexpr auto operator<(Fraction lhs, Z rhs) -> bool
Less than.
Definition fractions.hpp:215
constexpr void reciprocal() noexcept(std::is_nothrow_swappable_v< Z >)
reciprocal
Definition fractions.hpp:402
friend auto operator<<(Stream &os, const Fraction &frac) -> Stream &
Definition fractions.hpp:715
friend constexpr auto operator*(int &&c, const Fraction &frac) -> Fraction
Definition fractions.hpp:702
Z _den
Definition fractions.hpp:94
constexpr auto operator+=(const Fraction &rhs) -> Fraction &
Definition fractions.hpp:602
friend constexpr auto operator+(int &&c, const Fraction &frac) -> Fraction
Definition fractions.hpp:680
constexpr auto operator-=(const Fraction &rhs) -> Fraction &
Definition fractions.hpp:610
constexpr auto operator-(const Fraction &frac) const -> Fraction
Subtract.
Definition fractions.hpp:568
constexpr auto operator-(const Z &i) const -> Fraction
Definition fractions.hpp:594
friend constexpr auto operator-(int &&c, const Fraction &frac) -> Fraction
Definition fractions.hpp:691
constexpr Fraction()
Default construct a new Fraction object (0/1).
Definition fractions.hpp:156
constexpr Fraction(Z num, Z den)
Construct a new Fraction object from two values.
Definition fractions.hpp:102
friend constexpr auto operator/(Fraction lhs, const Fraction &rhs) -> Fraction
divide
Definition fractions.hpp:490
constexpr auto operator*=(Fraction rhs) -> Fraction &
multiply and assign
Definition fractions.hpp:413
friend constexpr auto operator>=(const Z &lhs, const Fraction &rhs) -> bool
Greater than or euqal to.
Definition fractions.hpp:392
constexpr auto operator>=(const Z &rhs) const -> bool
Greater than or equal to.
Definition fractions.hpp:358
constexpr auto normalize() -> Z
normalize to a canonical form
Definition fractions.hpp:111
constexpr auto num() const noexcept -> const Z &
Definition fractions.hpp:163
constexpr Fraction(const Z &num)
Construct a new Fraction object from a single value (const ref).
Definition fractions.hpp:151
constexpr auto cross(const Fraction &rhs) const -> Z
Cross product of two fractions.
Definition fractions.hpp:181
friend constexpr auto operator<=(const Z &lhs, const Fraction &rhs) -> bool
Less than or equal to.
Definition fractions.hpp:380
constexpr void normalize1()
normalize to a canonical form
Definition fractions.hpp:121
friend constexpr auto operator==(Fraction lhs, Z rhs) -> bool
Equal to.
Definition fractions.hpp:198
friend constexpr auto operator-(const Z &c, const Fraction &frac) -> Fraction
Definition fractions.hpp:669
friend constexpr auto operator/(Fraction lhs, const Z &rhs) -> Fraction
divide
Definition fractions.hpp:514
Z _num
Definition fractions.hpp:93
constexpr auto operator>=(const Fraction &rhs) const -> bool
Greater than or euqal to.
Definition fractions.hpp:322
friend constexpr auto operator+(const Z &i, Fraction frac) -> Fraction
Add.
Definition fractions.hpp:586
constexpr auto operator/=(Fraction rhs) -> Fraction &
divide and assign
Definition fractions.hpp:474
friend constexpr auto operator==(const Z &lhs, const Fraction &rhs) -> bool
Equal to.
Definition fractions.hpp:249
constexpr auto operator>(const Fraction &rhs) const -> bool
Greater than.
Definition fractions.hpp:313
friend constexpr auto operator*(Fraction lhs, const Z &rhs) -> Fraction
multiply
Definition fractions.hpp:453
constexpr auto operator-() const -> Fraction
Negate.
Definition fractions.hpp:535
constexpr friend auto operator==(Fraction lhs, Fraction rhs) -> bool
Equal to.
Definition fractions.hpp:269
constexpr auto operator+=(const Z &i) -> Fraction &
Definition fractions.hpp:638
constexpr auto operator*=(Z rhs) -> Fraction &
multiply and assign
Definition fractions.hpp:439
constexpr auto operator<=(const Fraction &rhs) const -> bool
Less than or equal to.
Definition fractions.hpp:331
constexpr friend auto operator<(Fraction lhs, Fraction rhs) -> bool
Less than.
Definition fractions.hpp:287
constexpr auto operator!=(const Fraction &rhs) const -> bool
Definition fractions.hpp:304
constexpr Fraction(Z &&num)
Construct a new Fraction object from a single value (rvalue).
Definition fractions.hpp:146
friend constexpr auto operator+(Fraction frac, const Z &i) -> Fraction
Add.
Definition fractions.hpp:577
constexpr auto operator-=(const Z &rhs) -> Fraction &
Definition fractions.hpp:646
constexpr auto operator<=(const Z &rhs) const -> bool
Less than or equal to.
Definition fractions.hpp:349
constexpr auto operator/=(const Z &rhs) -> Fraction &
divide and assign
Definition fractions.hpp:500
constexpr auto den() const noexcept -> const Z &
Definition fractions.hpp:170
constexpr auto normalize2() -> Z
normalize to a canonical form
Definition fractions.hpp:133
friend constexpr auto operator*(Fraction lhs, const Fraction &rhs) -> Fraction
multiply
Definition fractions.hpp:429
friend constexpr auto operator<(Z lhs, Fraction rhs) -> bool
Less than.
Definition fractions.hpp:232
constexpr auto operator>(const Z &rhs) const -> bool
Greater than.
Definition fractions.hpp:340
friend constexpr auto operator/(const Z &lhs, Fraction rhs) -> Fraction
divide
Definition fractions.hpp:525
constexpr auto operator+(const Fraction &rhs) const -> Fraction
Add.
Definition fractions.hpp:547
friend constexpr auto operator>(const Z &lhs, const Fraction &rhs) -> bool
Greater than.
Definition fractions.hpp:368