2012-05-26 14:26:10 +02:00
|
|
|
//=============================================================================
|
2013-04-02 20:46:07 +02:00
|
|
|
// MuseScore
|
|
|
|
// Music Composition & Notation
|
2012-05-26 14:26:10 +02:00
|
|
|
//
|
2019-02-19 11:29:37 +01:00
|
|
|
// Copyright (C) 2019 Werner Schweer
|
2012-05-26 14:26:10 +02:00
|
|
|
//
|
|
|
|
// This program is free software; you can redistribute it and/or modify
|
2013-04-02 20:46:07 +02:00
|
|
|
// it under the terms of the GNU General Public License version 2
|
|
|
|
// as published by the Free Software Foundation and appearing in
|
|
|
|
// the file LICENCE.GPL
|
2012-05-26 14:26:10 +02:00
|
|
|
//=============================================================================
|
|
|
|
|
2019-02-19 11:29:37 +01:00
|
|
|
// everything contained in .h file for performance reasons
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
#ifndef __FRACTION_H__
|
|
|
|
#define __FRACTION_H__
|
|
|
|
|
2012-07-18 14:54:44 +02:00
|
|
|
#include "config.h"
|
2019-02-19 11:29:37 +01:00
|
|
|
#include "mscore.h"
|
2012-07-18 14:54:44 +02:00
|
|
|
|
2013-05-13 18:49:17 +02:00
|
|
|
namespace Ms {
|
|
|
|
|
2019-02-19 11:29:37 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// gcd
|
|
|
|
// greatest common divisor. always returns a positive val
|
|
|
|
// however, since int / uint = uint by C++ rules,
|
|
|
|
// return int to avoid accidental implicit unsigned cast
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
static int_least64_t gcd(int_least64_t a, int_least64_t b)
|
|
|
|
{
|
|
|
|
int bp;
|
|
|
|
if (b > a) { bp = b; b = a; a = bp; } // Saves one % if true
|
|
|
|
while (b != 0) {
|
|
|
|
bp = b; b = a % b; a = bp;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (a >= 0 ? a : -a);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// Fraction
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
class Fraction {
|
2019-02-19 11:29:37 +01:00
|
|
|
|
|
|
|
// ensure 64 bit to avoid overflows in comparisons
|
|
|
|
int_least64_t _numerator { 0 };
|
|
|
|
int_least64_t _denominator { 1 };
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
public:
|
2019-01-30 15:13:54 +01:00
|
|
|
|
|
|
|
#if 0
|
|
|
|
// implicit conversion from int to Fraction: this is convenient but may hide some potential bugs
|
|
|
|
constexpr Fraction(int z=0, int n=1) : _numerator(z), _denominator(n) {}
|
|
|
|
#else
|
|
|
|
// no implicit conversion from int to Fraction:
|
|
|
|
constexpr Fraction() {}
|
2019-02-19 11:29:37 +01:00
|
|
|
constexpr Fraction(int z, int n) : _numerator { n < 0 ? -z : z }, _denominator { n < 0 ? -n : n } { }
|
2019-01-30 15:13:54 +01:00
|
|
|
#endif
|
2012-05-26 14:26:10 +02:00
|
|
|
int numerator() const { return _numerator; }
|
|
|
|
int denominator() const { return _denominator; }
|
2019-02-19 11:29:37 +01:00
|
|
|
int_least64_t& rnumerator() { return _numerator; }
|
|
|
|
int_least64_t& rdenominator() { return _denominator; }
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
void setNumerator(int v) { _numerator = v; }
|
2019-02-19 11:29:37 +01:00
|
|
|
void setDenominator(int v) {
|
|
|
|
if (v < 0) { _numerator = -_numerator; _denominator = -v; }
|
|
|
|
else _denominator = v;
|
|
|
|
}
|
|
|
|
void set(int z, int n) {
|
|
|
|
if (n < 0) { _numerator = -z; _denominator = -n; }
|
|
|
|
else { _numerator = z; _denominator = n; }
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
bool isZero() const { return _numerator == 0; }
|
2019-01-30 15:13:54 +01:00
|
|
|
bool isNotZero() const { return _numerator != 0; }
|
2013-05-24 13:47:16 +02:00
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
bool isValid() const { return _denominator != 0; }
|
|
|
|
|
|
|
|
// check if two fractions are identical (numerator & denominator)
|
|
|
|
// == operator checks for equal value:
|
|
|
|
bool identical(const Fraction& v) const {
|
2019-02-19 11:29:37 +01:00
|
|
|
return (_numerator == v._numerator) &&
|
|
|
|
(_denominator == v._denominator);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
2019-02-19 11:29:37 +01:00
|
|
|
Fraction absValue() const {
|
|
|
|
return Fraction(qAbs(_numerator), _denominator); }
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
|
2019-02-19 11:29:37 +01:00
|
|
|
// --- reduction --- //
|
2012-05-26 14:26:10 +02:00
|
|
|
|
2019-02-19 11:29:37 +01:00
|
|
|
void reduce()
|
|
|
|
{
|
|
|
|
const int g = gcd(_numerator, _denominator);
|
|
|
|
_numerator /= g; _denominator /= g;
|
|
|
|
}
|
|
|
|
|
|
|
|
Fraction reduced() const
|
|
|
|
{
|
|
|
|
const int g = gcd(_numerator, _denominator);
|
|
|
|
return Fraction(_numerator / g, _denominator / g);
|
|
|
|
}
|
|
|
|
|
|
|
|
// --- comparison --- //
|
|
|
|
|
|
|
|
bool operator<(const Fraction& val) const
|
|
|
|
{
|
|
|
|
return _numerator * val._denominator < val._numerator * _denominator;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator<=(const Fraction& val) const
|
|
|
|
{
|
|
|
|
return _numerator * val._denominator <= val._numerator * _denominator;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator>=(const Fraction& val) const
|
|
|
|
{
|
|
|
|
return _numerator * val._denominator >= val._numerator * _denominator;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator>(const Fraction& val) const
|
|
|
|
{
|
|
|
|
return _numerator * val._denominator > val._numerator * _denominator;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator==(const Fraction& val) const
|
|
|
|
{
|
|
|
|
return _numerator * val._denominator == val._numerator * _denominator;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator!=(const Fraction& val) const
|
|
|
|
{
|
|
|
|
return _numerator * val._denominator != val._numerator * _denominator;
|
|
|
|
}
|
|
|
|
|
|
|
|
// --- arithmetic --- //
|
|
|
|
|
|
|
|
Fraction& operator+=(const Fraction& val)
|
|
|
|
{
|
|
|
|
if (_denominator == val._denominator)
|
|
|
|
_numerator += val._numerator; // Common enough use case to be handled separately for efficiency
|
|
|
|
else {
|
|
|
|
const int g = gcd(_denominator, val._denominator);
|
|
|
|
const int m1 = val._denominator / g; // This saves one division over straight lcm
|
|
|
|
_numerator = _numerator * m1 + val._numerator * (_denominator / g);
|
|
|
|
_denominator = m1 * _denominator;
|
|
|
|
}
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
Fraction& operator-=(const Fraction& val)
|
|
|
|
{
|
|
|
|
if (_denominator == val._denominator)
|
|
|
|
_numerator -= val._numerator; // Common enough use case to be handled separately for efficiency
|
|
|
|
else {
|
|
|
|
const int g = gcd(_denominator, val._denominator);
|
|
|
|
const int m1 = val._denominator / g; // This saves one division over straight lcm
|
|
|
|
_numerator = _numerator * m1 - val._numerator * (_denominator / g);
|
|
|
|
_denominator = m1 * _denominator;
|
|
|
|
}
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
Fraction& operator*=(const Fraction& val)
|
|
|
|
{
|
|
|
|
_numerator *= val._numerator;
|
|
|
|
_denominator *= val._denominator;
|
|
|
|
if (val._denominator != 1) reduce(); // We should be free to fully reduce here
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
Fraction& operator*=(int val)
|
|
|
|
{
|
|
|
|
_numerator *= val;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
Fraction& operator/=(const Fraction& val)
|
|
|
|
{
|
|
|
|
const int sign = (val._numerator >= 0 ? 1 : -1);
|
|
|
|
_numerator *= (sign*val._denominator);
|
|
|
|
_denominator *= (sign*val._numerator);
|
|
|
|
if (val._numerator != sign) reduce();
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
Fraction& operator/=(int val)
|
|
|
|
{
|
|
|
|
_denominator *= val;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
#endif
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
Fraction operator+(const Fraction& v) const { return Fraction(*this) += v; }
|
|
|
|
Fraction operator-(const Fraction& v) const { return Fraction(*this) -= v; }
|
2019-01-30 15:13:54 +01:00
|
|
|
Fraction operator-() const { return Fraction(-_numerator, _denominator); }
|
2012-05-26 14:26:10 +02:00
|
|
|
Fraction operator*(const Fraction& v) const { return Fraction(*this) *= v; }
|
|
|
|
Fraction operator/(const Fraction& v) const { return Fraction(*this) /= v; }
|
2019-02-19 11:29:37 +01:00
|
|
|
// Fraction operator/(int v) const { return Fraction(*this) /= v; }
|
|
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// fromTicks
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
static Fraction fromTicks(int ticks)
|
|
|
|
{
|
|
|
|
if (ticks == -1)
|
|
|
|
return Fraction(-1,1); // HACK
|
|
|
|
return Fraction(ticks, MScore::division * 4).reduced();
|
|
|
|
}
|
|
|
|
|
2019-03-26 10:49:58 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// eps
|
|
|
|
/// A very small fraction, corresponds to 1 MIDI tick
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
static Fraction eps() { return Fraction(1, MScore::division * 4); }
|
|
|
|
|
2019-02-19 11:29:37 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// ticks
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
int ticks() const
|
|
|
|
{
|
|
|
|
if (_numerator == -1 && _denominator == 1) // HACK
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
// MScore::division - ticks per quarter note
|
|
|
|
// MScore::division * 4 - ticks per whole note
|
|
|
|
// result: rounded (MScore::division * 4 * _numerator * 1.0 / _denominator) value
|
|
|
|
const auto result = (static_cast<int_least64_t>(_numerator) * MScore::division * 4 + (_denominator/2)) / _denominator;
|
|
|
|
return static_cast<int>(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
|
2019-01-30 15:13:54 +01:00
|
|
|
QString print() const { return QString("%1/%2").arg(_numerator).arg(_denominator); }
|
|
|
|
QString toString() const { return print(); }
|
2019-03-12 11:55:00 +01:00
|
|
|
static Fraction fromString(const QString& str) {
|
|
|
|
const int i = str.indexOf('/');
|
|
|
|
return (i == -1) ? Fraction(str.toInt(), 1) : Fraction(str.leftRef(i).toInt(), str.midRef(i+1).toInt());
|
|
|
|
}
|
2016-07-07 16:20:16 +02:00
|
|
|
operator QVariant() const { return QVariant::fromValue(*this); }
|
2012-05-26 14:26:10 +02:00
|
|
|
};
|
|
|
|
|
2019-01-31 11:17:59 +01:00
|
|
|
inline Fraction operator*(const Fraction& f, int v) { return Fraction(f) *= v; }
|
|
|
|
inline Fraction operator*(int v, const Fraction& f) { return Fraction(f) *= v; }
|
2019-01-10 12:58:19 +01:00
|
|
|
|
2013-05-13 18:49:17 +02:00
|
|
|
} // namespace Ms
|
2012-05-26 14:26:10 +02:00
|
|
|
|
2014-05-12 12:28:07 +02:00
|
|
|
Q_DECLARE_METATYPE(Ms::Fraction);
|
2015-05-07 11:36:27 +02:00
|
|
|
|
|
|
|
#endif
|