C++ 实数类
这个类我发现我用的地方还不少,所以,我将它重写了。
以前的写法过于沙雕,还用的模板类,还支持小数转换。实际上我整出这个东西,就是为了不使用小数,那么我为什么还要支持小数的转换?
这次我的写法,更多地是为了更简单地使用。
1 #pragma once 2 3 #include <stdint.h> 4 #include <numeric> 5 #include <iostream> 6 7 class Rational 8 { 9 public: 10 Rational() noexcept : _p(0), _q(1) {} 11 Rational(int64_t p, int64_t q = 1) : _p(p) { SetQ(q); } 12 ~Rational() {} 13 14 public: 15 inline int64_t P() const noexcept { return _p; } 16 inline void SetP(int64_t p) noexcept { _p = p; } 17 18 inline int64_t Q() const noexcept { return _q; } 19 inline void SetQ(int64_t q) 20 { 21 if (q == 0) 22 { 23 throw std::logic_error("Integer division by zero."); 24 return; 25 } 26 27 _q = q; 28 } 29 30 inline int64_t Sign() const noexcept { return _p * _q >= 0 ? 1 : -1; } 31 inline void Simplify() noexcept 32 { 33 int64_t g = std::gcd(_p, _q); 34 _p /= g; _q /= g; 35 36 if (_p < 0 && _q < 0) 37 { 38 _p *= -1; 39 _q *= -1; 40 } 41 } 42 43 public: 44 template<typename T, typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr> 45 inline operator T() const noexcept { return _p / _q; } 46 47 template<typename T, typename std::enable_if<std::is_floating_point<T>::value, T>::type* = nullptr> 48 inline operator T() const noexcept { return _p / (_q * 1.0); } 49 50 inline friend std::ostream& operator<<(std::ostream& o, const Rational& num) 51 { 52 o << num.P() << "/" << num.Q(); 53 return o; 54 } 55 56 //+ 57 template<typename T, typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr> 58 inline friend Rational operator+(const Rational& l, T r) noexcept 59 { 60 return Rational(l.Q() * r + l.P(), l.Q()); 61 } 62 63 template<typename T, typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr> 64 inline friend Rational operator+(T l, const Rational& r) noexcept 65 { 66 return Rational(r.Q() * l + r.P(), r.Q()); 67 } 68 69 inline friend Rational operator+(const Rational& l, const Rational& r) noexcept 70 { 71 return Rational(l.P() * r.Q() + l.Q() * r.P(), l.Q() * r.Q()); 72 } 73 74 //- 75 template<typename T, typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr> 76 inline friend Rational operator-(const Rational& l, T r) noexcept 77 { 78 return Rational(l.P() - l.Q() * r, l.Q()); 79 } 80 81 template<typename T, typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr> 82 inline friend Rational operator-(T l, const Rational& r) noexcept 83 { 84 return Rational(r.P() - r.Q() * l, r.Q()); 85 } 86 87 inline friend Rational operator-(const Rational& l, const Rational& r) noexcept 88 { 89 return Rational(l.P() * r.Q() - l.Q() * r.P(), l.Q() * r.Q()); 90 } 91 92 //* 93 template<typename T, typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr> 94 inline friend Rational operator*(const Rational& l, T r) noexcept 95 { 96 return Rational(l.P() * r, l.Q()); 97 } 98 99 template<typename T, typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr> 100 inline friend Rational operator*(T l, const Rational& r) noexcept 101 { 102 return Rational(r.P() * l, r.Q()); 103 } 104 105 inline friend Rational operator*(const Rational& l, const Rational& r) noexcept 106 { 107 return Rational(l.P() * r.P(), l.Q() * r.Q()); 108 } 109 110 // / 111 template<typename T, typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr> 112 inline friend Rational operator/(const Rational& l, T r) noexcept 113 { 114 return Rational(l.P(), l.Q() * r); 115 } 116 117 template<typename T, typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr> 118 inline friend Rational operator/(T l, const Rational& r) noexcept 119 { 120 return Rational(r.P(), r.Q() * l); 121 } 122 123 inline friend Rational operator/(const Rational& l, const Rational& r) noexcept 124 { 125 return Rational(l.P() * r.Q(), l.Q() * r.P()); 126 } 127 128 // = 129 template<typename T, typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr> 130 inline Rational& operator=(T r) noexcept 131 { 132 _p = r; 133 _q = 1; 134 return *this; 135 } 136 137 // += 138 template<typename TL, typename TR, 139 typename std::enable_if<std::is_same<typename std::decay<TL>::type, Rational>::value || std::is_same<typename std::decay<TR>::type, Rational>::value>::type* = nullptr 140 > 141 inline friend TL& operator+=(TL& l, const TR& r) noexcept 142 { 143 l = l + r; 144 return l; 145 } 146 147 //-= 148 template<typename TL, typename TR, 149 typename std::enable_if<std::is_same<typename std::decay<TL>::type, Rational>::value || std::is_same<typename std::decay<TR>::type, Rational>::value>::type* = nullptr 150 > 151 inline friend TL& operator-=(TL& l, const TR& r) noexcept 152 { 153 l = l - r; 154 return l; 155 } 156 157 // *= 158 template<typename TL, typename TR, 159 typename std::enable_if<std::is_same<typename std::decay<TL>::type, Rational>::value || std::is_same<typename std::decay<TR>::type, Rational>::value>::type* = nullptr 160 > 161 inline friend TL& operator*=(TL& l, const TR& r) noexcept 162 { 163 l = l * r; 164 return l; 165 } 166 167 // /= 168 template<typename TL, typename TR, 169 typename std::enable_if<std::is_same<typename std::decay<TL>::type, Rational>::value || std::is_same<typename std::decay<TR>::type, Rational>::value>::type* = nullptr 170 > 171 inline friend TL& operator/=(TL& l, const TR& r) noexcept 172 { 173 l = l / r; 174 return l; 175 } 176 177 // < 178 template<typename T, typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr> 179 inline friend bool operator<(const Rational& l, T r) noexcept 180 { 181 return l.P() < (r * l.Q()); 182 } 183 184 template<typename T, typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr> 185 inline friend bool operator<(T l, const Rational& r) noexcept 186 { 187 return (l * r.Q()) < r.P(); 188 } 189 190 inline friend bool operator<(const Rational& l, const Rational& r) noexcept 191 { 192 return (l.P() * r.Q()) < (r.P() * l.Q()); 193 } 194 195 // == 196 template<typename T, typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr> 197 inline friend bool operator==(const Rational& l, T r) noexcept 198 { 199 return l.P() == (r * l.Q()); 200 } 201 202 template<typename T, typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr> 203 inline friend bool operator==(T l, const Rational& r) noexcept 204 { 205 return (l * r.Q()) == r.P(); 206 } 207 208 inline friend bool operator==(const Rational& l, const Rational& r) noexcept 209 { 210 return (l.P() * r.Q()) == (r.P() * l.Q()); 211 } 212 213 // > 214 template<typename T, typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr> 215 inline friend bool operator>(const Rational& l, T r) noexcept 216 { 217 return l.P() > (r * l.Q()); 218 } 219 220 template<typename T, typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr> 221 inline friend bool operator>(T l, const Rational& r) noexcept 222 { 223 return (l * r.Q()) > r.P(); 224 } 225 226 inline friend bool operator>(const Rational& l, const Rational& r) noexcept 227 { 228 return (l.P() * r.Q()) > (r.P() * l.Q()); 229 } 230 231 // <= 232 template<typename TL, typename TR, 233 typename std::enable_if<std::is_same<typename std::decay<TL>::type, Rational>::value || std::is_same<typename std::decay<TR>::type, Rational>::value>::type* = nullptr 234 > 235 inline friend bool operator<=(TL& l, const TR& r) noexcept 236 { 237 return !(l > r); 238 } 239 240 // >= 241 template<typename TL, typename TR, 242 typename std::enable_if<std::is_same<typename std::decay<TL>::type, Rational>::value || std::is_same<typename std::decay<TR>::type, Rational>::value>::type* = nullptr 243 > 244 inline friend bool operator>=(TL& l, const TR& r) noexcept 245 { 246 return !(l < r); 247 } 248 249 // ! 250 inline bool operator!() const noexcept 251 { 252 return !(P() == 0); 253 } 254 255 // ~ (Transposition) 256 inline Rational& operator~() noexcept 257 { 258 int64_t tmp_ = std::move(_p); 259 _p = std::move(_q); 260 SetQ(tmp_); 261 262 return *this; 263 } 264 265 //abs 266 inline Rational& Abs() noexcept 267 { 268 std::abs(_p); std::abs(_q); 269 return *this; 270 } 271 272 private: 273 int64_t _p = 0; 274 int64_t _q = 1; 275 };