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
108
114 Fraction operator+(const Fraction& other) const {
115 return Fraction(
116 m_numerator * other.m_denominator + other.m_numerator * m_denominator,
117 m_denominator * other.m_denominator
118 );
119 }
120
126 Fraction operator-(const Fraction& other) const {
127 return Fraction(
128 m_numerator * other.m_denominator - other.m_numerator * m_denominator,
129 m_denominator * other.m_denominator
130 );
131 }
132
138 Fraction operator*(const Fraction& other) const {
139 return Fraction(
140 m_numerator * other.m_numerator,
141 m_denominator * other.m_denominator
142 );
143 }
144
151 Fraction operator/(const Fraction& other) const {
152 if (other.m_numerator == 0) {
153 throw std::invalid_argument("Cannot divide by zero fraction.");
154 }
155 return Fraction(
156 m_numerator * other.m_denominator,
157 m_denominator * other.m_numerator
158 );
159 }
160
166 Fraction& operator+=(const Fraction& other) {
167 *this = *this + other;
168 return *this;
169 }
170
176 Fraction& operator-=(const Fraction& other) {
177 *this = *this - other;
178 return *this;
179 }
180
186 Fraction& operator*=(const Fraction& other) {
187 *this = *this * other;
188 return *this;
189 }
190
197 Fraction& operator/=(const Fraction& other) {
198 *this = *this / other;
199 return *this;
200 }
201
207 bool operator==(const Fraction& other) const {
208 Fraction lhs = *this;
209 Fraction rhs = other;
210 lhs.reduce();
211 rhs.reduce();
212 return lhs.m_numerator == rhs.m_numerator && lhs.m_denominator == rhs.m_denominator;
213 }
214
220 bool operator!=(const Fraction& other) const {
221 return !(*this == other);
222 }
223
229 bool operator<(const Fraction& other) const {
230 double lhs = static_cast<double>(m_numerator) / m_denominator;
231 double rhs = static_cast<double>(other.m_numerator) / other.m_denominator;
232 return lhs < rhs;
233 }
234
240 bool operator<=(const Fraction& other) const {
241 return *this < other || *this == other;
242 }
243
249 bool operator>(const Fraction& other) const {
250 return !(*this <= other);
251 }
252
258 bool operator>=(const Fraction& other) const {
259 return !(*this < other);
260 }
261
266 explicit operator bool() const {
267 return m_numerator != 0;
268 }
269
276 friend std::ostream& operator<<(std::ostream& os, const Fraction& frac) {
277 os << frac.m_numerator;
278 if (frac.m_denominator != 1) {
279 os << "/" << frac.m_denominator;
280 }
281 return os;
282 }
283
291 friend std::istream& operator>>(std::istream& is, Fraction& frac) {
292 int num, den;
293 char sep;
294 is >> num >> sep >> den;
295 if (sep != '/' || den == 0) {
296 throw std::invalid_argument("Invalid fraction format or zero m_denominator.");
297 }
298 frac = Fraction(num, den);
299 return is;
300 }
301};
302
303} // namespace util
304} // 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:229
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:114
Fraction(int num=0, int den=1)
Constructs a Fraction object.
Definition Fraction.h:65
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:249
bool operator>=(const Fraction &other) const
Greater-than-or-equal-to comparison operator.
Definition Fraction.h:258
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:240
bool operator==(const Fraction &other) const
Equality comparison operator.
Definition Fraction.h:207
Fraction & operator+=(const Fraction &other)
Compound addition assignment operator.
Definition Fraction.h:166
Fraction operator*(const Fraction &other) const
Multiplies two fractions.
Definition Fraction.h:138
friend std::ostream & operator<<(std::ostream &os, const Fraction &frac)
Stream output operator.
Definition Fraction.h:276
friend std::istream & operator>>(std::istream &is, Fraction &frac)
Stream input operator.
Definition Fraction.h:291
Fraction & operator*=(const Fraction &other)
Compound multiplication assignment operator.
Definition Fraction.h:186
bool operator!=(const Fraction &other) const
Inequality comparison operator.
Definition Fraction.h:220
Fraction & operator-=(const Fraction &other)
Compound subtraction assignment operator.
Definition Fraction.h:176
Fraction operator-(const Fraction &other) const
Subtracts one fraction from another.
Definition Fraction.h:126
Fraction operator/(const Fraction &other) const
Divides one fraction by another.
Definition Fraction.h:151
Fraction & operator/=(const Fraction &other)
Compound division assignment operator.
Definition Fraction.h:197
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