-
Notifications
You must be signed in to change notification settings - Fork 0
/
Fraction.hpp
152 lines (117 loc) · 3.8 KB
/
Fraction.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#ifndef ML_FRACTION_HPP
#define ML_FRACTION_HPP
#include <cassert>
#include <numeric>
template<typename T>
struct Fraction {
private:
static constexpr T DenominatorForZero = 1;
void NormalizeZero() {
if (numerator == 0) {
denominator = DenominatorForZero;
}
}
public:
using value_type = T;
T numerator;
T denominator;
constexpr Fraction<T>(T numerator, T denominator) :
numerator(numerator),
denominator(denominator)
{
assert(denominator >= 1);
Reduce();
}
constexpr Fraction<T>(T numerator = 0) :
Fraction<T>(numerator, 1)
{}
constexpr Fraction<T>& Reduce() {
if (numerator == 0) {
denominator = DenominatorForZero;
return *this;
}
const auto gcd = std::gcd(numerator, denominator);
numerator /= gcd;
denominator /= gcd;
return *this;
}
static constexpr Fraction<T> Reduce(Fraction<T> fraction) {
return fraction.Reduce();
}
constexpr Fraction<T> Inverse() const {
return Fraction<T>(denominator, numerator);
}
static constexpr Fraction<T> Inverse(Fraction<T> fraction) {
return fraction.Inverse();
}
constexpr Fraction<T>& operator+=(const Fraction<T>& rhs) {
const auto gcd = std::gcd(denominator, rhs.denominator);
numerator = numerator * (rhs.denominator / gcd) + rhs.numerator * (denominator / gcd);
denominator *= rhs.denominator / gcd;
NormalizeZero();
return *this;
}
constexpr Fraction<T>& operator-=(const Fraction<T>& rhs) {
const auto gcd = std::gcd(denominator, rhs.denominator);
numerator = numerator * (rhs.denominator / gcd) - rhs.numerator * (denominator / gcd);
denominator *= rhs.denominator / gcd;
NormalizeZero();
return *this;
}
constexpr Fraction<T>& operator*=(const Fraction<T>& rhs) {
if (numerator == 0 || rhs.numerator == 0) {
numerator = 0;
denominator = DenominatorForZero;
return *this;
}
const auto gcd1 = std::gcd(numerator, rhs.denominator);
const auto gcd2 = std::gcd(denominator, rhs.numerator);
numerator = (numerator / gcd1) * (rhs.numerator / gcd2);
denominator = (denominator / gcd2) * (rhs.denominator / gcd1);
return *this;
}
constexpr Fraction<T>& operator/=(const Fraction<T>& rhs) {
return *this *= rhs.Inverse();;
}
friend constexpr Fraction<T> operator+(Fraction<T> lhs, const Fraction<T>& rhs) {
lhs += rhs;
return lhs;
}
friend constexpr Fraction<T> operator-(Fraction<T> lhs, const Fraction<T>& rhs) {
lhs -= rhs;
return lhs;
}
friend constexpr Fraction<T> operator*(Fraction<T> lhs, const Fraction<T>& rhs) {
lhs *= rhs;
return lhs;
}
friend constexpr Fraction<T> operator/(Fraction<T> lhs, const Fraction<T>& rhs) {
lhs /= rhs;
return lhs;
}
friend constexpr bool operator==(const Fraction<T>& lhs, const Fraction<T>& rhs) {
const auto gcd = std::gcd(lhs.denominator, rhs.denominator);
const auto ln = lhs.numerator * (rhs.denominator / gcd);
const auto rn = rhs.numerator * (lhs.denominator / gcd);
return ln == rn;
}
friend constexpr bool operator<(const Fraction<T>& lhs, const Fraction<T>& rhs) {
const auto gcd = std::gcd(lhs.denominator, rhs.denominator);
const auto ln = lhs.numerator * (rhs.denominator / gcd);
const auto rn = rhs.numerator * (lhs.denominator / gcd);
return ln < rn;
}
friend constexpr bool operator!=(const Fraction<T>& lhs, const Fraction<T>& rhs) {
return !operator==(lhs, rhs);
}
friend constexpr bool operator>(const Fraction<T>& lhs, const Fraction<T>& rhs) {
return operator<(rhs, lhs);
}
friend constexpr bool operator<=(const Fraction<T>& lhs, const Fraction<T>& rhs) {
return !operator>(lhs, rhs);
}
friend constexpr bool operator>=(const Fraction<T>& lhs, const Fraction<T>& rhs) {
return !operator<(lhs, rhs);
}
};
#endif