File indexing completed on 2024-05-12 17:22:41
0001 // This file is part of the SpeedCrunch project 0002 // Copyright (C) 2015 Pol Welter <polwelter@gmail.com> 0003 // 0004 // This program is free software; you can redistribute it and/or 0005 // modify it under the terms of the GNU General Public License 0006 // as published by the Free Software Foundation; either version 2 0007 // of the License, or (at your option) any later version. 0008 // 0009 // This program is distributed in the hope that it will be useful, 0010 // but WITHOUT ANY WARRANTY; without even the implied warranty of 0011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0012 // GNU General Public License for more details. 0013 // 0014 // You should have received a copy of the GNU General Public License 0015 // along with this program; see the file COPYING. If not, write to 0016 // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0017 // Boston, MA 02110-1301, USA. 0018 0019 #include "rational.h" 0020 #include "hmath.h" 0021 #include "numberformatter.h" 0022 0023 #include <cmath> 0024 #include <QString> 0025 #include <QStringList> 0026 #include <limits.h> 0027 0028 0029 void Rational::normalize() 0030 { 0031 if(m_denom==0) { 0032 m_valid = false; 0033 return; 0034 } 0035 if(m_num==0) { 0036 m_denom=1; 0037 return; 0038 } 0039 int g = gcd(abs(m_num), abs(m_denom)); 0040 m_num /= g; 0041 m_denom /= g; 0042 if(m_denom<0) { 0043 m_num = -m_num; 0044 m_denom = -m_denom; 0045 } 0046 } 0047 0048 int Rational::compare(const Rational &other) const 0049 { 0050 return m_num*other.m_denom - m_denom*other.m_num; 0051 } 0052 0053 0054 /* 0055 * Find a rational approximation to num using a continued fraction scheme. 0056 * Code adapted from the 'Fraction' module for the PYTHON programming language, 0057 * authored by Sjoerd Mullender and Jeffrey Yasskin. 0058 */ 0059 Rational::Rational(const HNumber &num) : 0060 m_num(1), m_denom(1), m_valid(1) 0061 { 0062 if(num.isZero()) { 0063 m_num = 0; 0064 return; 0065 } 0066 if(HMath::abs(num)>HNumber(INT_MAX) || HMath::abs(num)<HNumber(1)/HNumber(INT_MAX)) { 0067 m_valid = false; 0068 return; 0069 } 0070 if(num.isInteger()) { 0071 m_num = num.toInt(); 0072 return; 0073 } 0074 const unsigned long long MAXD = INT_MAX/2; // maximal denominator 0075 unsigned long long p0=0, q0=1, p1=1, q1=0; 0076 HNumber val(HMath::abs(num)); 0077 while(true) { 0078 long a = HMath::floor(val).toInt(); 0079 unsigned long long q2 = q0 + a*q1; 0080 if(q2>MAXD) 0081 break; 0082 unsigned long long temp1=p0, temp2=p1, temp3=q1; 0083 p0 = temp2; 0084 q0 = temp3; 0085 p1 = temp1 + a*temp2; 0086 q1 = q2; 0087 if(HMath::frac(val).isZero()) break; 0088 val = HNumber(1)/HMath::frac(val); 0089 if(val>HNumber(MAXD)) break; 0090 } 0091 0092 Rational bound(p1, q1); 0093 if(num<0) { 0094 bound.m_num *= -1; 0095 } 0096 *this = bound; 0097 0098 } 0099 0100 Rational::Rational(const double &num): 0101 m_num(1), m_denom(1), m_valid(1) 0102 { 0103 if (num==0) { 0104 m_num = 0; 0105 return; 0106 } 0107 if (std::abs(num)>INT_MAX || std::abs(1./num)>INT_MAX) { 0108 m_valid = false; 0109 return; 0110 } 0111 const long long MAXD = INT_MAX/2; // maximal denominator 0112 long long p0=0, q0=1, p1=1, q1=0; 0113 0114 double val = fabs(num); 0115 while(true) { 0116 unsigned long long a = static_cast<unsigned long long>(floor(val)); 0117 unsigned long long q2 = q0 + a*q1; 0118 if(q2>MAXD) 0119 break; 0120 unsigned long long temp1=p0, temp2=p1, temp3=q1; 0121 p0 = temp2; 0122 q0 = temp3; 0123 p1 = temp1 + a*temp2; 0124 q1 = q2; 0125 if(val==a) break; 0126 val = 1/(val-a); 0127 } 0128 0129 Rational bound(p1, q1); 0130 if(num<0) 0131 bound.m_num *= -1; 0132 0133 *this = bound; 0134 } 0135 0136 Rational::Rational(const QString &str) : m_num(0), m_denom(1), m_valid(true) 0137 { 0138 if(str=="") { 0139 m_valid=false; 0140 return; 0141 } 0142 QStringList l = str.split("/"); 0143 if(l.size()==1) { 0144 bool ok; 0145 m_num = l.at(0).toInt(&ok); 0146 if(!ok) { 0147 m_valid=false; 0148 return; 0149 } 0150 } else if(l.size()==2) { 0151 bool ok; 0152 m_num = l.at(0).toInt(&ok); 0153 if(!ok) { 0154 m_valid=false; 0155 return; 0156 } 0157 m_denom = l.at(1).toInt(&ok); 0158 if(!ok) { 0159 m_valid=false; 0160 return; 0161 } 0162 } 0163 } 0164 0165 Rational Rational::operator*(const Rational &other) const 0166 { 0167 return Rational(this->m_num * other.m_num, this->m_denom * other.m_denom); 0168 } 0169 0170 Rational Rational::operator/(const Rational &other) const 0171 { 0172 if(other.isZero()) return Rational(1,0); // Rational(1,0) will set m_valid=false 0173 return Rational(this->m_num / other.m_num, this->m_denom / other.m_denom); 0174 } 0175 0176 Rational Rational::operator+(const Rational &other) const 0177 { 0178 return Rational(this->m_num*other.m_denom + this->m_denom*other.m_num, this->m_denom*other.m_denom); 0179 } 0180 0181 Rational Rational::operator-(const Rational &other) const 0182 { 0183 return Rational(this->m_num*other.m_denom - this->m_denom*other.m_num, this->m_denom*other.m_denom); 0184 } 0185 0186 Rational &Rational::operator=(const Rational &other) 0187 { 0188 m_num = other.m_num; 0189 m_denom = other.m_denom; 0190 m_valid = other.m_valid; 0191 return *this; 0192 } 0193 0194 Rational &Rational::operator+=(const Rational &other) 0195 { 0196 return operator=(*this + other); 0197 } 0198 0199 Rational &Rational::operator-=(const Rational &other) 0200 { 0201 return operator=(*this - other); 0202 } 0203 0204 Rational &Rational::operator*=(const Rational &other) 0205 { 0206 return operator=(*this * other); 0207 } 0208 0209 Rational &Rational::operator/=(const Rational &other) 0210 { 0211 return operator=(*this / other); 0212 } 0213 0214 bool Rational::operator<(const Rational &other) const 0215 { 0216 return compare(other)<0; 0217 } 0218 0219 bool Rational::operator==(const Rational &other) const 0220 { 0221 return compare(other) == 0; 0222 } 0223 0224 bool Rational::operator>(const Rational &other) const 0225 { 0226 return compare(other)>0; 0227 } 0228 0229 bool Rational::isZero() const 0230 { 0231 return m_num==0; 0232 } 0233 0234 bool Rational::isValid() const 0235 { 0236 return m_valid; 0237 } 0238 0239 QString Rational::toString() const 0240 { 0241 if(m_denom==1) 0242 return QString::fromLatin1("%1").arg(m_num); 0243 return QString::fromLatin1("%1/%2").arg(m_num).arg(m_denom); 0244 } 0245 0246 HNumber Rational::toHNumber() const 0247 { 0248 HNumber num(m_num); 0249 HNumber denom(m_denom); 0250 return num/denom; 0251 0252 } 0253 0254 double Rational::toDouble() const 0255 { 0256 return double(m_num)/m_denom; 0257 }