/* $Id$ */ /* * Copyright (C) 2005-2006 Richard Braun * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include "mtx.h" #include "mtxmatrix.h" #include "mtxinteger.h" #include "mtxrational.h" #include "mtxexception.h" #include "mtxdivbyzeroexception.h" using namespace std; unsigned int MtxRational::precision = MTX_DEFAULT_PRECISION; MtxRational::MtxRational() { setNumerator(0); setDenominator(1); } MtxRational::MtxRational(int integer) { setNumerator(integer); setDenominator(1); } /* * Return 10^power. I hate such duplications, but I also hate ugly macros. */ static double pot(unsigned int power) { unsigned int i; double result; result = 1; for (i = 0; i < power; i++) result *= 10; return result; } static MtxInteger mtx_pot(unsigned int power) { MtxInteger result; unsigned int i; result = 1; for (i = 0; i < power; i++) result *= 10; return result; } MtxRational::MtxRational(double rational) { unsigned int base, power; double power_of_ten; char *tmp; int size; power = 0; while (fabs(rational - trunc(rational)) > 0) { rational *= 10; power++; } base = MtxInteger::getBase(); MtxInteger::setBase(10); size = snprintf(NULL, 0, "%.0f", rational) + 1; tmp = new char[size]; snprintf(tmp, size, "%.0f", rational); setNumerator(tmp); delete[] tmp; power_of_ten = pot(power); size = snprintf(NULL, 0, "%.0f", power_of_ten) + 1; tmp = new char[size]; snprintf(tmp, size, "%.0f", power_of_ten); setDenominator(tmp); delete[] tmp; normalize(); MtxInteger::setBase(base); } MtxRational::MtxRational(const char *rational) { char *tmp, *ptr; size_t length; length = strlen(rational); tmp = new char[length + 1]; strcpy(tmp, rational); ptr = strchr(tmp, '.'); if (ptr == NULL) { setNumerator(tmp); setDenominator(1); } else { MtxInteger power_of_ten; unsigned int power; size_t index; index = ptr - tmp; power = length - (index + 1); power_of_ten = mtx_pot(power); strcpy(ptr, rational + index + 1); setNumerator(tmp); setDenominator(power_of_ten); } delete[] tmp; normalize(); } MtxRational::MtxRational(const MtxInteger &numerator, const MtxInteger &denominator) { setNumerator(numerator); setDenominator(denominator); normalize(); } MtxRational::~MtxRational() { } MtxInteger MtxRational::getNumerator() const { return numerator; } MtxInteger MtxRational::getDenominator() const { return denominator; } void MtxRational::setNumerator(const MtxInteger &numerator) { this->numerator = numerator; } void MtxRational::setDenominator(const MtxInteger &denominator) { if (denominator == 0) throw MtxDivByZeroException(); this->denominator = denominator; } MtxRational MtxRational::operator+() const { return MtxRational(*this); } MtxRational MtxRational::operator-() const { MtxRational new_rational(*this); new_rational.setNumerator(-new_rational.numerator); return new_rational.normalize(); } bool MtxRational::operator==(const MtxRational &rational) const { if (numerator * rational.denominator == denominator * rational.numerator) return true; else return false; } bool MtxRational::operator!=(const MtxRational &rational) const { return !(*this == rational); } bool MtxRational::operator>(const MtxRational &rational) const { MtxInteger a, b; a = this->numerator * rational.denominator; b = rational.numerator * this->denominator; return a > b; } bool MtxRational::operator>=(const MtxRational &rational) const { return (*this > rational || *this == rational); } bool MtxRational::operator<(const MtxRational &rational) const { return rational > *this; } bool MtxRational::operator<=(const MtxRational &rational) const { return (*this < rational || *this == rational); } MtxRational MtxRational::operator+(const MtxRational &rational) const { return MtxRational((numerator * rational.denominator + rational.numerator * denominator), denominator * rational.denominator); } MtxMatrix MtxRational::operator+(const MtxMatrix &matrix) const { return matrix + *this; } MtxRational & MtxRational::operator++() { *this = *this + 1; return *this; } MtxRational & MtxRational::operator++(int a) { *this = *this + 1; return *this; } MtxRational & MtxRational::operator+=(const MtxRational &rational) { *this = *this + rational; return *this; } MtxRational MtxRational::operator-(const MtxRational &rational) const { return MtxRational((numerator * rational.denominator - rational.numerator * denominator), denominator * rational.denominator); } MtxMatrix MtxRational::operator-(const MtxMatrix &matrix) const { size_t i, j, rows, columns; MtxMatrix new_matrix; new_matrix = matrix; rows = matrix.getRows(); columns = matrix.getColumns(); for (i = 0; i < rows; i++) for (j = 0; j < columns; j++) new_matrix[i][j] = *this - matrix[i][j]; return new_matrix; } MtxRational & MtxRational::operator--() { *this = *this - 1; return *this; } MtxRational & MtxRational::operator--(int a) { *this = *this - 1; return *this; } MtxRational & MtxRational::operator-=(const MtxRational &rational) { *this = *this - rational; return *this; } MtxRational MtxRational::operator*(const MtxRational &rational) const { return MtxRational(numerator * rational.numerator, denominator * rational.denominator); } MtxMatrix MtxRational::operator*(const MtxMatrix &matrix) const { return matrix * *this; } MtxRational & MtxRational::operator*=(const MtxRational &rational) { *this = *this * rational; return *this; } MtxRational MtxRational::operator/(const MtxRational &rational) const { return MtxRational(numerator * rational.denominator, denominator * rational.numerator); } MtxMatrix MtxRational::operator/(const MtxMatrix &matrix) const { throw MtxException("division by matrix not allowed"); } MtxRational & MtxRational::operator/=(const MtxRational &rational) { *this = *this / rational; return *this; } ostream & operator<<(ostream &cout, const MtxRational &rational) { cout << rational.toString(); return cout; } void MtxRational::simplify() { if (denominator.abs() != 1) { MtxInteger gcd; gcd = MtxInteger::gcd(numerator, denominator); numerator /= gcd; denominator /= gcd; } } MtxRational & MtxRational::normalize() { if (numerator == 0) setDenominator(1); else { if ((numerator < 0 && denominator < 0) || (numerator > 0 && denominator < 0)) { setNumerator(-numerator); setDenominator(-denominator); } simplify(); } return *this; } string MtxRational::toString() const { if (numerator == 0) return "0"; else if (denominator == 1) return numerator.toString(); else return numerator.toString() + "/" + denominator.toString(); } string MtxRational::toFloatString() const { MtxInteger divisor, result, remainder; string str; if (numerator == 0) return "0"; divisor = denominator.abs(); result = (numerator / divisor).abs(); remainder = (numerator % divisor).abs(); if ((numerator < 0) != (denominator < 0)) str = '-'; str += result.toString(); if (remainder != 0) { unsigned int base, digits_count; str += '.'; base = MtxInteger::getBase(); digits_count = 0; do { remainder *= base; result = remainder / divisor; remainder %= divisor; str += result.toString(); digits_count++; } while (remainder != 0 && digits_count < precision); } return str; } MTXVALUE_CLONE_METHOD(MtxRational); #define ADD_SUBTRACT_MULTIPLY_DIVIDE(name, op) \ MtxValue * \ MtxRational::name(const MtxValue *value) const \ { \ const MtxRational *rational; \ rational = dynamic_cast(value); \ if (rational == NULL) \ { \ const MtxInteger *integer; \ integer = dynamic_cast(value); \ if (integer == NULL) \ { \ const MtxMatrix *matrix; \ matrix = dynamic_cast(value); \ if (matrix == NULL) \ throw MtxException("internal error: unable to retreive variable " \ "type"); \ return (*this op *matrix).clone(); \ } \ else \ return (*this op *integer).clone(); \ } \ else \ return (*this op *rational).clone(); \ } ADD_SUBTRACT_MULTIPLY_DIVIDE(add, +) ADD_SUBTRACT_MULTIPLY_DIVIDE(subtract, -) ADD_SUBTRACT_MULTIPLY_DIVIDE(multiply, *) ADD_SUBTRACT_MULTIPLY_DIVIDE(divide, /) MtxValue * MtxRational::opposite() const { return (-*this).clone(); } MtxRational MtxRational::reciprocal() const { MtxRational new_rational; new_rational.numerator = denominator; new_rational.denominator = numerator; return new_rational.normalize(); } void MtxRational::setPrecision(unsigned int new_precision) { precision = new_precision; } unsigned int MtxRational::getPrecision() { return precision; }