Console Library 8.0.0
A header-only library that makes C++ simple
Loading...
Searching...
No Matches
rational.h
Go to the documentation of this file.
1
11
12/*
13Copyright (c) 2026 MrXie1109
14
15Permission is hereby granted, free of charge, to any person obtaining a copy
16of this software and associated documentation files (the "Software"), to deal
17in the Software without restriction, including without limitation the rights
18to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
19copies of the Software, and to permit persons to whom the Software is
20furnished to do so, subject to the following conditions:
21
22The above copyright notice and this permission notice shall be included in all
23copies or substantial portions of the Software.
24
25THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31SOFTWARE.
32*/
33
34#pragma once
35#include <cmath>
36#include <cstdint>
37#include <cstdlib>
38#include <iostream>
39#include <ostream>
40#include <type_traits>
41
42#include "../core/csexc.h"
43
44namespace console {
50 template <class T>
52 static_assert(std::is_integral<T>::value && std::is_signed<T>::value,
53 "T must be signed integral type");
54
57
64 static T gcd(T a, T b) {
65 a = std::abs(a);
66 b = std::abs(b);
67 while (b != 0) {
68 T temp = b;
69 b = a % b;
70 a = temp;
71 }
72 return a;
73 }
74
79 void reduce() {
80 if (den == 0) {
81 throw DomainError("Denominator cannot be zero");
82 }
83 if (den < 0) {
84 num = -num;
85 den = -den;
86 }
87 T g = gcd(num, den);
88 num /= g;
89 den /= g;
90 }
91
92 public:
94 constexpr BasicRational() : num(0), den(1) {}
95
100 constexpr BasicRational(T n) : num(n), den(1) {}
101
109 BasicRational(T n, T d) : num(n), den(d) { reduce(); }
110
115 T numerator() const { return num; }
116
121 T denominator() const { return den; }
122
128 template <class U>
129 explicit operator U() const {
130 return U(num) / den;
131 }
132
140 friend BasicRational
141 operator+(const BasicRational &lhs, const BasicRational &rhs) {
142 return BasicRational(
143 lhs.num * rhs.den + rhs.num * lhs.den, lhs.den * rhs.den);
144 }
145
153 friend BasicRational
154 operator-(const BasicRational &lhs, const BasicRational &rhs) {
155 return BasicRational(
156 lhs.num * rhs.den - rhs.num * lhs.den, lhs.den * rhs.den);
157 }
158
166 friend BasicRational
167 operator*(const BasicRational &lhs, const BasicRational &rhs) {
168 return BasicRational(lhs.num * rhs.num, lhs.den * rhs.den);
169 }
170
179 friend BasicRational
180 operator/(const BasicRational &lhs, const BasicRational &rhs) {
181 if (rhs.num == 0) throw DomainError("Division by zero");
182 return BasicRational(lhs.num * rhs.den, lhs.den * rhs.num);
183 }
184
191 *this = *this + other;
192 return *this;
193 }
194
201 *this = *this - other;
202 return *this;
203 }
204
211 *this = *this * other;
212 return *this;
213 }
214
222 *this = *this / other;
223 return *this;
224 }
225
231
236 BasicRational operator+() const { return *this; }
237
244 friend bool
245 operator==(const BasicRational &lhs, const BasicRational &rhs) {
246 return lhs.num == rhs.num && lhs.den == rhs.den;
247 }
248
255 friend bool
256 operator!=(const BasicRational &lhs, const BasicRational &rhs) {
257 return !(lhs == rhs);
258 }
259
266 friend bool
267 operator<(const BasicRational &lhs, const BasicRational &rhs) {
268 return lhs.num * rhs.den < rhs.num * lhs.den;
269 }
270
277 friend bool
278 operator>(const BasicRational &lhs, const BasicRational &rhs) {
279 return rhs < lhs;
280 }
281
288 friend bool
289 operator<=(const BasicRational &lhs, const BasicRational &rhs) {
290 return !(lhs > rhs);
291 }
292
299 friend bool
300 operator>=(const BasicRational &lhs, const BasicRational &rhs) {
301 return !(lhs < rhs);
302 }
303
312 template <class CharT, class Traits>
313 friend std::basic_ostream<CharT, Traits> &operator<<(
314 std::basic_ostream<CharT, Traits> &os, const BasicRational &r) {
315 os << intmax_t(r.num);
316 if (r.den != 1) os << '/' << intmax_t(r.den);
317 return os;
318 }
319
327 template <class CharT, class Traits>
328 friend std::basic_istream<CharT, Traits> &
329 operator>>(std::basic_istream<CharT, Traits> &is, BasicRational &r) {
330 intmax_t n, d;
331 char slash;
332 is >> n;
333 if (is >> std::ws, is.peek() == '/') {
334 is >> slash >> d;
335 r = BasicRational(intmax_t(n), intmax_t(d));
336 } else
337 r = BasicRational(intmax_t(n));
338 return is;
339 }
340 };
341
347}
用于表示分数的基础模板类。
Definition rational.h:51
T numerator() const
取得分数的分子。
Definition rational.h:115
constexpr BasicRational()
默认构造函数,构造一个值为 0/1 的分数。
Definition rational.h:94
friend bool operator>=(const BasicRational &lhs, const BasicRational &rhs)
比较左操作数是否大于等于右操作数(ge)。
Definition rational.h:300
friend BasicRational operator*(const BasicRational &lhs, const BasicRational &rhs)
计算两个分数的积。
Definition rational.h:167
BasicRational operator-() const
返回相反数。
Definition rational.h:230
BasicRational operator+() const
返回自身。
Definition rational.h:236
friend std::basic_ostream< CharT, Traits > & operator<<(std::basic_ostream< CharT, Traits > &os, const BasicRational &r)
将一个分数打印到指定输出流。
Definition rational.h:313
friend bool operator<=(const BasicRational &lhs, const BasicRational &rhs)
Definition rational.h:289
T denominator() const
取得分数的分母。
Definition rational.h:121
intmax_t num
Definition rational.h:55
BasicRational & operator*=(const BasicRational &other)
就地版本,等价于 a = a * b。
Definition rational.h:210
friend bool operator!=(const BasicRational &lhs, const BasicRational &rhs)
比较两个分数是否不等(ne)。
Definition rational.h:256
BasicRational(T n, T d)
接受双参的构造函数,构造一个值为 n/d 的分数。
Definition rational.h:109
friend std::basic_istream< CharT, Traits > & operator>>(std::basic_istream< CharT, Traits > &is, BasicRational &r)
从指定输入流读取一个分数。
Definition rational.h:329
static T gcd(T a, T b)
求两个整数的最大公因数。
Definition rational.h:64
friend bool operator>(const BasicRational &lhs, const BasicRational &rhs)
比较左操作数是否大于右操作数(gt)。
Definition rational.h:278
BasicRational & operator+=(const BasicRational &other)
就地版本,等价于 a = a + b。
Definition rational.h:190
BasicRational & operator/=(const BasicRational &other)
就地版本,等价于 a = a / b。
Definition rational.h:221
friend BasicRational operator/(const BasicRational &lhs, const BasicRational &rhs)
计算两个分数的商。
Definition rational.h:180
friend BasicRational operator-(const BasicRational &lhs, const BasicRational &rhs)
计算两个分数的差。
Definition rational.h:154
intmax_t den
Definition rational.h:56
BasicRational & operator-=(const BasicRational &other)
就地版本,等价于 a = a - b。
Definition rational.h:200
friend bool operator<(const BasicRational &lhs, const BasicRational &rhs)
Definition rational.h:267
friend bool operator==(const BasicRational &lhs, const BasicRational &rhs)
比较两个分数是否相等(eq)。
Definition rational.h:245
void reduce()
辅助函数,用于约分一个分数。
Definition rational.h:79
constexpr BasicRational(T n)
接受单参的构造函数,构造一个值为 n/1 的分数。
Definition rational.h:100
friend BasicRational operator+(const BasicRational &lhs, const BasicRational &rhs)
计算两个分数的和。
Definition rational.h:141
DomainError(const std::string &msg)
构造 DomainError。
Definition csexc.h:167
定义 console 库使用的自定义异常类层次结构。
本库所有组件所在的顶层命名空间。
BasicRational< int8_t > Rational_8
以 int8_t 为基的分数。
Definition rational.h:343
@ U
Definition kb.h:100
@ T
Definition kb.h:99
BasicRational< int16_t > Rational_16
以 int16_t 为基的分数。
Definition rational.h:344
BasicRational< int32_t > Rational_32
以 int32_t 为基的分数。
Definition rational.h:345
BasicRational< int64_t > Rational_64
以 int64_t 为基的分数。
Definition rational.h:346
BasicRational< intmax_t > Rational
以 intmax_t 为基的分数。
Definition rational.h:342