numerical-collection-cpp 0.10.0
A collection of algorithms in numerical analysis implemented in C++
Loading...
Searching...
No Matches
fraction.h
Go to the documentation of this file.
1/*
2 * Copyright 2023 MusicScience37 (Kenta Kabashima)
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
20#pragma once
21
22#include <ostream>
23#include <type_traits> // IWYU pragma: keep
24
25#include <fmt/base.h>
26#include <fmt/ostream.h> // IWYU pragma: keep
27
34
35namespace num_collect::numbers {
36
42template <base::concepts::integral IntegerType>
43class fraction {
44public:
46 using integer_type = IntegerType;
47
57 "The denominator of a fraction must not be zero.");
58 normalize();
59 }
60
66 constexpr fraction( // NOLINT(google-explicit-constructor, hicpp-explicit-conversions)
67 integer_type integer) noexcept
68 : numerator_(integer), denominator_(static_cast<integer_type>(1)) {}
69
73 constexpr fraction() noexcept : fraction(static_cast<integer_type>(0)) {}
74
80 [[nodiscard]] constexpr auto numerator() const noexcept -> integer_type {
81 return numerator_;
82 }
83
89 [[nodiscard]] constexpr auto denominator() const noexcept -> integer_type {
90 return denominator_;
91 }
92
99 constexpr auto operator+=(const fraction& right) -> fraction& {
100 add(right);
101 return *this;
102 }
103
110 constexpr auto add(const fraction& right) -> fraction& {
111 if (denominator_ == right.denominator_) {
112 // TODO: Add safely.
113 numerator_ += right.numerator_;
114 } else {
115 const integer_type common_divisor =
116 util::greatest_common_divisor(denominator_, right.denominator_);
117 const integer_type right_coeff = denominator_ / common_divisor;
118 const integer_type my_coeff = right.denominator_ / common_divisor;
119
121
122 // TODO: Add safely.
124 util::multiply_safely(right.numerator_, right_coeff);
125 }
126 normalize();
127 return *this;
128 }
129
136 constexpr auto operator-=(const fraction& right) -> fraction& {
137 subtract(right);
138 return *this;
139 }
140
147 constexpr auto subtract(const fraction& right) -> fraction& {
148 if (denominator_ == right.denominator_) {
149 // TODO: Subtract safely.
150 numerator_ -= right.numerator_;
151 } else {
152 const integer_type common_divisor =
153 util::greatest_common_divisor(denominator_, right.denominator_);
154 const integer_type right_coeff = denominator_ / common_divisor;
155 const integer_type my_coeff = right.denominator_ / common_divisor;
156
158
159 // TODO: Subtract safely.
161 util::multiply_safely(right.numerator_, right_coeff);
162 }
163 normalize();
164 return *this;
165 }
166
173 constexpr auto operator*=(const fraction& right) -> fraction& {
174 multiply(right);
175 return *this;
176 }
177
184 constexpr auto multiply(const fraction& right) -> fraction& {
185 numerator_ = util::multiply_safely(numerator_, right.numerator_);
186 denominator_ = util::multiply_safely(denominator_, right.denominator_);
187 normalize();
188 return *this;
189 }
190
197 constexpr auto operator/=(const fraction& right) -> fraction& {
198 divide_by(right);
199 return *this;
200 }
201
208 constexpr auto divide_by(const fraction& right) -> fraction& {
209 multiply(right.inverse());
210 return *this;
211 }
212
218 [[nodiscard]] constexpr auto inverse() const -> fraction {
220 }
221
229 constexpr auto operator==(const fraction& right) const noexcept -> bool {
230 // This fraction is always normalized, so simple comparison is enough.
231 return denominator_ == right.denominator_ &&
232 numerator_ == right.numerator_;
233 }
234
242 constexpr auto operator!=(const fraction& right) const noexcept -> bool {
243 return !operator==(right);
244 }
245
246private:
250 constexpr void normalize() {
251 if constexpr (std::is_signed_v<integer_type>) {
252 if (denominator_ < static_cast<integer_type>(0)) {
255 }
256 }
257
258 if (numerator_ == static_cast<integer_type>(0)) {
259 denominator_ = static_cast<integer_type>(1);
260 return;
261 }
262
263 const auto common_divisor =
265 numerator_ /= common_divisor;
266 denominator_ /= common_divisor;
267 }
268
275 static constexpr auto int_abs(integer_type x) noexcept -> integer_type {
276 // TODO: move to utility or base.
277 if constexpr (std::is_unsigned_v<integer_type>) {
278 return x;
279 } else {
280 if (x < static_cast<integer_type>(0)) {
281 return -x;
282 }
283 return x;
284 }
285 }
286
289
292};
293
302template <num_collect::base::concepts::integral Integer>
303constexpr auto operator+(const fraction<Integer>& left,
304 const fraction<Integer>& right) -> fraction<Integer> {
305 return fraction<Integer>(left) += right;
306}
307
316template <num_collect::base::concepts::integral Integer>
317constexpr auto operator-(const fraction<Integer>& left,
318 const fraction<Integer>& right) -> fraction<Integer> {
319 return fraction<Integer>(left) -= right;
320}
321
330template <num_collect::base::concepts::integral Integer>
331constexpr auto operator*(const fraction<Integer>& left,
332 const fraction<Integer>& right) -> fraction<Integer> {
333 return fraction<Integer>(left) *= right;
334}
335
344template <num_collect::base::concepts::integral Integer>
345constexpr auto operator/(const fraction<Integer>& left,
346 const fraction<Integer>& right) -> fraction<Integer> {
347 return fraction<Integer>(left) /= right;
348}
349
350} // namespace num_collect::numbers
351
352namespace fmt {
353
359template <num_collect::base::concepts::integral Integer>
360struct formatter<num_collect::numbers::fraction<Integer>> {
361public:
368 constexpr auto parse(format_parse_context& context) // NOLINT
369 -> decltype(context.begin()) {
370 return context.end();
371 }
372
381 format_context& context) const {
382 return fmt::format_to(
383 context.out(), "{} / {}", val.numerator(), val.denominator());
384 }
385};
386
387} // namespace fmt
388
389namespace num_collect::numbers {
390
399template <num_collect::base::concepts::integral Integer>
400inline auto operator<<(std::ostream& stream, const fraction<Integer>& val)
401 -> std::ostream& {
402 fmt::print(stream, "{}", val);
403 return stream;
404}
405
406} // namespace num_collect::numbers
Class of fractions.
Definition fraction.h:43
constexpr auto operator/=(const fraction &right) -> fraction &
Divide this fraction by a fraction.
Definition fraction.h:197
static constexpr auto int_abs(integer_type x) noexcept -> integer_type
Get the absolute value of an integer.
Definition fraction.h:275
constexpr auto operator==(const fraction &right) const noexcept -> bool
Compare this fraction with another fraction.
Definition fraction.h:229
constexpr auto denominator() const noexcept -> integer_type
Get the denominator.
Definition fraction.h:89
constexpr auto operator!=(const fraction &right) const noexcept -> bool
Compare this fraction with another fraction.
Definition fraction.h:242
constexpr auto operator+=(const fraction &right) -> fraction &
Add a fraction to this fraction.
Definition fraction.h:99
constexpr auto add(const fraction &right) -> fraction &
Add a fraction to this fraction.
Definition fraction.h:110
constexpr fraction() noexcept
Constructor. (Initialize to zero.)
Definition fraction.h:73
constexpr auto divide_by(const fraction &right) -> fraction &
Divide this fraction by a fraction.
Definition fraction.h:208
constexpr auto subtract(const fraction &right) -> fraction &
Subtract a fraction from this fraction.
Definition fraction.h:147
constexpr fraction(integer_type integer) noexcept
Constructor. (Convert from an integer.)
Definition fraction.h:66
constexpr fraction(integer_type numerator, integer_type denominator)
Constructor.
Definition fraction.h:54
integer_type numerator_
Numerator.
Definition fraction.h:288
constexpr auto operator*=(const fraction &right) -> fraction &
Multiply a fraction to this fraction.
Definition fraction.h:173
constexpr void normalize()
Normalize this fraction.
Definition fraction.h:250
constexpr auto multiply(const fraction &right) -> fraction &
Multiply a fraction to this fraction.
Definition fraction.h:184
constexpr auto inverse() const -> fraction
Get the inverse of this fraction.
Definition fraction.h:218
constexpr auto numerator() const noexcept -> integer_type
Get the numerator.
Definition fraction.h:80
IntegerType integer_type
Type of integers.
Definition fraction.h:46
constexpr auto operator-=(const fraction &right) -> fraction &
Subtract a fraction from this fraction.
Definition fraction.h:136
integer_type denominator_
Denominator.
Definition fraction.h:291
Definition of exceptions.
Definition of greatest_common_divisor function.
Definition of integral concept.
Definition of macros for logging.
Definition of multiply_safely function.
Namespace of fmt library.
Definition log_level.h:114
Namespace of classes of numbers.
auto operator<<(std::ostream &stream, const fraction< Integer > &val) -> std::ostream &
Format a fraction.
Definition fraction.h:400
constexpr auto operator*(const fraction< Integer > &left, const fraction< Integer > &right) -> fraction< Integer >
Multiply two fractions.
Definition fraction.h:331
constexpr auto operator-(const fraction< Integer > &left, const fraction< Integer > &right) -> fraction< Integer >
Subtract a fraction from another fraction.
Definition fraction.h:317
constexpr auto operator/(const fraction< Integer > &left, const fraction< Integer > &right) -> fraction< Integer >
Divide a fraction by another fraction.
Definition fraction.h:345
constexpr auto operator+(const fraction< Integer > &left, const fraction< Integer > &right) -> fraction< Integer >
Add two fractions.
Definition fraction.h:303
constexpr auto multiply_safely(T a, T b) -> T
Multiply two integers with check of overflow.
constexpr auto greatest_common_divisor(T a, T b) -> T
Calculate the greatest common divisor.
Namespace of num_collect source codes.
Definition of NUM_COLLECT_PRECONDITION macro.
#define NUM_COLLECT_PRECONDITION(CONDITION,...)
Check whether a precondition is satisfied and throw an exception if not.
constexpr auto parse(format_parse_context &context) -> decltype(context.begin())
Parse format specifications.
Definition fraction.h:368
auto format(num_collect::numbers::fraction< Integer > val, format_context &context) const
Format a value.
Definition fraction.h:380