1
1
#pragma once
2
+ #include < cassert>
2
3
#include < limits>
3
4
4
5
// Rational number + {infinity(1 / 0), -infiity(-1 / 0), nan(0 / 0)} (有理数)
5
- // Do not compare any number with nan
6
6
// Verified: Yandex Cup 2022 Final E https://contest.yandex.com/contest/42710/problems/K
7
- template <class Int , bool AlwaysReduce = false > struct Rational {
8
- Int num, den;
7
+ template <class Int , bool AutoReduce = false > struct Rational {
8
+ Int num, den; // den >= 0
9
+
9
10
static constexpr Int my_gcd (Int a, Int b) {
10
11
// return __gcd(a, b);
11
12
if (a < 0 ) a = -a;
12
13
if (b < 0 ) b = -b;
13
14
while (a and b) {
14
- if (a > b)
15
+ if (a > b) {
15
16
a %= b;
16
- else
17
+ } else {
17
18
b %= a;
19
+ }
18
20
}
19
21
return a + b;
20
22
}
23
+
21
24
constexpr Rational (Int num = 0 , Int den = 1 ) : num(num), den(den) { normalize (); }
22
25
constexpr void normalize () noexcept {
23
- if constexpr (AlwaysReduce ) { // reduction
26
+ if constexpr (AutoReduce ) { // reduction
24
27
Int g = my_gcd (num, den);
25
28
if (g) num /= g, den /= g;
26
29
} else {
@@ -31,12 +34,16 @@ template <class Int, bool AlwaysReduce = false> struct Rational {
31
34
}
32
35
if (den < 0 ) num = -num, den = -den; // denominator >= 0
33
36
}
37
+
38
+ constexpr bool is_finite () const noexcept { return den != 0 ; }
39
+ constexpr bool is_infinite_or_nan () const noexcept { return den == 0 ; }
40
+
34
41
constexpr Rational operator +(const Rational &r) const noexcept {
35
- if (!den and !r. den ) return Rational (num + r.num , den );
42
+ if (is_infinite_or_nan () and r. is_infinite_or_nan ()) return Rational (num + r.num , 0 );
36
43
return Rational (num * r.den + den * r.num , den * r.den );
37
44
}
38
45
constexpr Rational operator -(const Rational &r) const noexcept {
39
- if (!den and !r. den ) return Rational (num - r.num , den );
46
+ if (is_infinite_or_nan () and r. is_infinite_or_nan ()) return Rational (num - r.num , 0 );
40
47
return Rational (num * r.den - den * r.num , den * r.den );
41
48
}
42
49
constexpr Rational operator *(const Rational &r) const noexcept {
@@ -51,23 +58,36 @@ template <class Int, bool AlwaysReduce = false> struct Rational {
51
58
constexpr Rational &operator /=(const Rational &r) noexcept { return *this = *this / r; }
52
59
constexpr Rational operator -() const noexcept { return Rational (-num, den); }
53
60
constexpr Rational abs () const noexcept { return Rational (num > 0 ? num : -num, den); }
61
+
62
+ constexpr Int floor () const {
63
+ assert (is_finite ());
64
+ if (num > 0 ) {
65
+ return num / den;
66
+ } else {
67
+ return -((-num + den - 1 ) / den);
68
+ }
69
+ }
70
+
54
71
constexpr bool operator ==(const Rational &r) const noexcept {
55
- if constexpr (AlwaysReduce ) {
72
+ if ( is_infinite_or_nan () or r. is_infinite_or_nan () ) {
56
73
return num == r.num and den == r.den ;
57
74
} else {
58
75
return num * r.den == r.num * den;
59
76
}
60
77
}
78
+
61
79
constexpr bool operator !=(const Rational &r) const noexcept { return !(*this == r); }
80
+
62
81
constexpr bool operator <(const Rational &r) const noexcept {
63
- if (den == 0 and r.den == 0 )
82
+ if (is_infinite_or_nan () and r.is_infinite_or_nan () )
64
83
return num < r.num ;
65
- else if (den == 0 )
84
+ else if (is_infinite_or_nan ()) {
66
85
return num < 0 ;
67
- else if (r.den == 0 )
86
+ } else if (r.is_infinite_or_nan ()) {
68
87
return r.num > 0 ;
69
- else
88
+ } else {
70
89
return num * r.den < den * r.num ;
90
+ }
71
91
}
72
92
constexpr bool operator <=(const Rational &r) const noexcept {
73
93
return (*this == r) or (*this < r);
@@ -76,6 +96,7 @@ template <class Int, bool AlwaysReduce = false> struct Rational {
76
96
constexpr bool operator >=(const Rational &r) const noexcept {
77
97
return (r == *this ) or (r < *this );
78
98
}
99
+
79
100
constexpr explicit operator double () const noexcept { return (double )num / (double )den; }
80
101
constexpr explicit operator long double () const noexcept {
81
102
return (long double )num / (long double )den;
0 commit comments