MUSX Document Model
Loading...
Searching...
No Matches
Fraction.h
1/*
2 * Copyright (C) 2025, Robert Patterson
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 */
22#pragma once
23
24#include <iostream>
25#include <numeric>
26#include <stdexcept>
27
28#include "musx/dom/Fundamentals.h"
29
30namespace musx {
31namespace util {
32
37class Fraction {
38private:
39 int m_numerator;
40 int m_denominator;
41
46 void reduce() {
47 int gcd = std::gcd(m_numerator, m_denominator);
48 m_numerator /= gcd;
49 m_denominator /= gcd;
50
51 // Ensure the m_denominator is always positive
52 if (m_denominator < 0) {
53 m_numerator = -m_numerator;
54 m_denominator = -m_denominator;
55 }
56 }
57
58public:
65 Fraction(int num = 0, int den = 1) : m_numerator(num), m_denominator(den) {
66 if (m_denominator == 0) {
67 throw std::invalid_argument("Denominator cannot be zero.");
68 }
69 reduce();
70 }
71
74 static Fraction fromEdu(int edu);
75
80 int numerator() const { return m_numerator; }
81
86 int denominator() const { return m_denominator; }
87
92 int quotient() const {
93 return m_numerator / m_denominator;
94 }
95
101 return Fraction(m_numerator % m_denominator, m_denominator);
102 }
103
107 return Fraction(m_denominator, m_numerator);
108 }
109
114
120 Fraction operator+(const Fraction& other) const {
121 return Fraction(
122 m_numerator * other.m_denominator + other.m_numerator * m_denominator,
123 m_denominator * other.m_denominator
124 );
125 }
126
132 Fraction operator-(const Fraction& other) const {
133 return Fraction(
134 m_numerator * other.m_denominator - other.m_numerator * m_denominator,
135 m_denominator * other.m_denominator
136 );
137 }
138
144 Fraction operator*(const Fraction& other) const {
145 return Fraction(
146 m_numerator * other.m_numerator,
147 m_denominator * other.m_denominator
148 );
149 }
150
157 Fraction operator/(const Fraction& other) const {
158 if (other.m_numerator == 0) {
159 throw std::invalid_argument("Cannot divide by zero fraction.");
160 }
161 return Fraction(
162 m_numerator * other.m_denominator,
163 m_denominator * other.m_numerator
164 );
165 }
166
172 Fraction& operator+=(const Fraction& other) {
173 *this = *this + other;
174 return *this;
175 }
176
182 Fraction& operator-=(const Fraction& other) {
183 *this = *this - other;
184 return *this;
185 }
186
192 Fraction& operator*=(const Fraction& other) {
193 *this = *this * other;
194 return *this;
195 }
196
203 Fraction& operator/=(const Fraction& other) {
204 *this = *this / other;
205 return *this;
206 }
207
213 bool operator==(const Fraction& other) const {
214 Fraction lhs = *this;
215 Fraction rhs = other;
216 lhs.reduce();
217 rhs.reduce();
218 return lhs.m_numerator == rhs.m_numerator && lhs.m_denominator == rhs.m_denominator;
219 }
220
226 bool operator!=(const Fraction& other) const {
227 return !(*this == other);
228 }
229
235 bool operator<(const Fraction& other) const {
236 double lhs = static_cast<double>(m_numerator) / m_denominator;
237 double rhs = static_cast<double>(other.m_numerator) / other.m_denominator;
238 return lhs < rhs;
239 }
240
246 bool operator<=(const Fraction& other) const {
247 return *this < other || *this == other;
248 }
249
255 bool operator>(const Fraction& other) const {
256 return !(*this <= other);
257 }
258
264 bool operator>=(const Fraction& other) const {
265 return !(*this < other);
266 }
267
272 explicit operator bool() const {
273 return m_numerator != 0;
274 }
275
282 friend std::ostream& operator<<(std::ostream& os, const Fraction& frac) {
283 os << frac.m_numerator;
284 if (frac.m_denominator != 1) {
285 os << "/" << frac.m_denominator;
286 }
287 return os;
288 }
289
297 friend std::istream& operator>>(std::istream& is, Fraction& frac) {
298 int num, den;
299 char sep;
300 is >> num >> sep >> den;
301 if (sep != '/' || den == 0) {
302 throw std::invalid_argument("Invalid fraction format or zero m_denominator.");
303 }
304 frac = Fraction(num, den);
305 return is;
306 }
307};
308
309} // namespace util
310} // namespace musx
A class to represent fractions with integer m_numerator and m_denominator, automatically reduced to s...
Definition Fraction.h:37
bool operator<(const Fraction &other) const
Less-than comparison operator.
Definition Fraction.h:235
Fraction remainder() const
Returns the fractional part of the fraction.
Definition Fraction.h:100
int numerator() const
Gets the m_numerator of the fraction.
Definition Fraction.h:80
int quotient() const
Returns the integer (whole number) part of the fraction.
Definition Fraction.h:92
Fraction operator+(const Fraction &other) const
Adds two fractions.
Definition Fraction.h:120
Fraction(int num=0, int den=1)
Constructs a Fraction object.
Definition Fraction.h:65
Fraction reciprocal() const
Returns the reciprocal fraction.
Definition Fraction.h:106
static Fraction fromEdu(int edu)
Constructs a Fraction from edu.
Definition Fraction.cpp:31
bool operator>(const Fraction &other) const
Greater-than comparison operator.
Definition Fraction.h:255
bool operator>=(const Fraction &other) const
Greater-than-or-equal-to comparison operator.
Definition Fraction.h:264
dom::Edu calcEduDuration() const
Calculates duration as a fraction of a whole note.
Definition Fraction.cpp:36
bool operator<=(const Fraction &other) const
Less-than-or-equal-to comparison operator.
Definition Fraction.h:246
bool operator==(const Fraction &other) const
Equality comparison operator.
Definition Fraction.h:213
Fraction & operator+=(const Fraction &other)
Compound addition assignment operator.
Definition Fraction.h:172
Fraction operator*(const Fraction &other) const
Multiplies two fractions.
Definition Fraction.h:144
friend std::ostream & operator<<(std::ostream &os, const Fraction &frac)
Stream output operator.
Definition Fraction.h:282
friend std::istream & operator>>(std::istream &is, Fraction &frac)
Stream input operator.
Definition Fraction.h:297
Fraction & operator*=(const Fraction &other)
Compound multiplication assignment operator.
Definition Fraction.h:192
bool operator!=(const Fraction &other) const
Inequality comparison operator.
Definition Fraction.h:226
Fraction & operator-=(const Fraction &other)
Compound subtraction assignment operator.
Definition Fraction.h:182
Fraction operator-(const Fraction &other) const
Subtracts one fraction from another.
Definition Fraction.h:132
Fraction operator/(const Fraction &other) const
Divides one fraction by another.
Definition Fraction.h:157
Fraction & operator/=(const Fraction &other)
Compound division assignment operator.
Definition Fraction.h:203
int denominator() const
Gets the m_denominator of the fraction.
Definition Fraction.h:86
int32_t Edu
"Enigma Durational Units" value (1024 per quarter note)
Definition Fundamentals.h:61
object model for musx file (enigmaxml)
Definition BaseClasses.h:32