00001 // 00002 // Copyright (c) 2006 by Rafael Ostertag 00003 // 00004 // This program is free software; you can redistribute it and/or modify 00005 // it under the terms of the GNU General Public License as published by 00006 // the Free Software Foundation; either version 2 of the License, or 00007 // (at your option) any later version. 00008 // 00009 // This program is distributed in the hope that it will be useful, 00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 // GNU General Public License for more details. 00013 // 00014 // You should have received a copy of the GNU General Public License 00015 // along with this program; if not, write to the Free Software 00016 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00017 // 00018 // 00019 // $Id: fraction.cc,v 1.11 2006/12/31 00:49:39 rafi Exp $ 00020 // 00021 00030 #include <string> 00031 #include <iostream> 00032 #include <cstring> 00033 00034 #ifdef DEBUG 00035 #include <cassert> 00036 #endif 00037 00038 #include "casobject.h" 00039 #include "casexception.h" 00040 #include "fraction.h" 00041 #include "longint.h" 00042 00050 // Private methods 00051 // ---------------------------------------------------------------------------- 00052 00053 // ---------------------------------------------------------------------------- 00054 00055 00056 // Protected methods 00057 // ---------------------------------------------------------------------------- 00058 00059 // ---------------------------------------------------------------------------- 00060 00061 00062 // Constructors & Destructor 00063 // ---------------------------------------------------------------------------- 00068 Fraction::Fraction() { 00069 #ifdef SHOWCONSTRUCTOR 00070 std::cerr << "# Fraction::Fraction()" << std::endl; 00071 #endif 00072 00073 LongInt tmp ( 1L ); 00074 numerator = tmp.Clone(); 00075 denominator = tmp.Clone(); 00076 } 00077 00085 Fraction::Fraction ( const CASObject* num, const CASObject* denom ) { 00086 #ifdef SHOWCONSTRUCTOR 00087 std::cerr << "# Fraction::Fraction(const CASObject* num, const CASObject* denom)" << std::endl; 00088 #endif 00089 00090 checkptr ( num ); 00091 checkptr ( denom ); 00092 00093 if ( denom->IsZero() ) { 00094 throw EDivByZero(); 00095 } 00096 00097 numerator = num->Clone(); 00098 denominator = denom->Clone(); 00099 } 00100 00108 Fraction::Fraction ( const CASObject* denom ) { 00109 #ifdef SHOWCONSTRUCTOR 00110 std::cerr << "# Fraction::Fraction(const CASObject* denom)" << std::endl; 00111 #endif 00112 00113 checkptr ( denom ); 00114 00115 if ( denom->IsZero() ) { 00116 throw EDivByZero(); 00117 } 00118 00119 LongInt t ( 1L ); 00120 numerator = t.Clone(); 00121 denominator = denominator->Clone(); 00122 } 00123 00129 Fraction::Fraction ( const Fraction &f ) { 00130 #ifdef SHOWCONSTRUCTOR 00131 std::cerr << "# Fraction::Fraction(const Fraction &f)" << std::endl; 00132 #endif 00133 00134 numerator = f.numerator->Clone(); 00135 denominator = f.denominator->Clone(); 00136 meta = f.meta; 00137 } 00138 00143 Fraction::~Fraction() { 00144 #ifdef SHOWCONSTRUCTOR 00145 std::cerr << "# Fraction::~Fraction()" << std::endl; 00146 #endif 00147 #ifdef DEBUG 00148 assert ( numerator != 0 ); 00149 assert ( denominator != 0 ); 00150 #endif 00151 delete numerator; 00152 delete denominator; 00153 } 00154 // ---------------------------------------------------------------------------- 00155 00156 00157 // Public Methods 00158 // ---------------------------------------------------------------------------- 00167 CASObject* 00168 Fraction::Clone() const { 00169 Fraction *ret_val = new Fraction; 00170 #ifdef DEBUG 00171 assert ( ret_val->numerator != 0 ); 00172 assert ( ret_val->denominator != 0 ); 00173 #endif 00174 00175 CASObject::Garbage->Put ( ret_val->numerator ); 00176 CASObject::Garbage->Put ( ret_val->denominator ); 00177 00178 ret_val->numerator = numerator->Clone(); 00179 ret_val->denominator = denominator->Clone(); 00180 00181 ret_val->meta = meta; 00182 00183 return ret_val; 00184 } 00185 00195 void 00196 Fraction::Get ( std::string &s ) const { 00197 if ( IsOne() ) { 00198 s = "1"; 00199 return; 00200 } 00201 00202 if ( IsZero() ) { 00203 s = "0"; 00204 return; 00205 } 00206 00207 s = "("; 00208 00209 std::string tmp; 00210 numerator->Get ( tmp ); 00211 s += tmp; 00212 00213 s += "/"; 00214 00215 denominator->Get ( tmp ); 00216 s += tmp; 00217 00218 s += ")"; 00219 00220 } 00221 00235 void 00236 Fraction::Get ( char *s, unsigned long size ) const { 00237 checkptr ( s ); 00238 00239 if ( size < ( Length() + 1 ) ) { 00240 throw EBufTooSmall(); 00241 } 00242 00243 memset ( s, '\0', size ); 00244 00245 00246 std::string tmp; 00247 Get ( tmp ); 00248 00249 strncpy ( s, tmp.c_str(), size ); 00250 } 00251 00257 void 00258 Fraction::Print() const { 00259 std::string tmp; 00260 Get ( tmp ); 00261 std::cout << tmp; 00262 } 00263 00273 unsigned long 00274 Fraction::Length() const { 00275 if ( IsZero() || IsOne() ) { 00276 return 1; 00277 } 00278 00279 unsigned long len = 0; 00280 len += numerator->Length(); 00281 len += denominator->Length(); 00282 // Because the string representation puts the fraction in (X/X), we add 3, 00283 // one for '(', one for '/', and one for ')' 00284 len += 3; 00285 return len; 00286 } 00287 00294 bool 00295 Fraction::IsZero() const { 00296 return numerator->IsZero(); 00297 } 00298 00305 bool 00306 Fraction::IsOne() const { 00307 return numerator->IsEqual ( denominator ); 00308 } 00309 00320 CASObject* 00321 Fraction::Absolute() const { 00322 Fraction res; 00323 res = *this; 00324 res.numerator->AbsoluteIP(); 00325 res.denominator->AbsoluteIP(); 00326 00327 return res.Clone(); 00328 } 00329 00336 void 00337 Fraction::AbsoluteIP() { 00338 numerator->AbsoluteIP(); 00339 denominator->AbsoluteIP(); 00340 } 00341 00354 CASObject* 00355 Fraction::Invert() const { 00356 #ifdef WARNINGS 00357 #warning "Not Implemented: Fraction::Invert() const" 00358 #endif 00359 throw ENotImplemented(); 00360 } 00361 00371 void 00372 Fraction::InvertIP() { 00373 #ifdef WARNINGS 00374 #warning "Not Implemented: Fraction::InvertIP()" 00375 #endif 00376 throw ENotImplemented(); 00377 } 00378 00396 CASObject* 00397 Fraction::Add ( const CASObject* addend ) const { 00398 checkptr ( addend ); 00399 00400 // Prepare the resulting fraction 00401 Fraction *result = new Fraction; 00402 CASObject::Garbage->Put ( result->numerator ); 00403 CASObject::Garbage->Put ( result->denominator ); 00404 00405 if ( GetType() == addend->GetType() ) { 00406 const Fraction *fr_ptr = dynamic_cast<const Fraction*> ( addend ); 00407 #ifdef DEBUG 00408 assert ( fr_ptr != 0 ); 00409 #endif 00410 00411 result->denominator = denominator->Multiply ( fr_ptr->denominator ); 00412 00413 CASObject* num1 = numerator->Multiply ( fr_ptr->denominator ); 00414 CASObject* num2 = fr_ptr->numerator->Multiply ( denominator ); 00415 result->numerator = num1->Add ( num2 ); 00416 00417 CASObject::Garbage->Put ( num1 ); 00418 CASObject::Garbage->Put ( num2 ); 00419 00420 return result; 00421 } 00422 00423 CASObject* num = denominator->Multiply ( addend ); 00424 result->numerator = numerator->Add ( num ); 00425 result->denominator = denominator->Clone(); 00426 00427 return result; 00428 00429 } 00430 00448 CASObject* 00449 Fraction::Subtract ( const CASObject* subtrahend ) const { 00450 checkptr ( subtrahend ); 00451 00452 // Prepare the resulting fraction 00453 Fraction *result = new Fraction; 00454 00455 CASObject::Garbage->Put ( result->numerator ); 00456 CASObject::Garbage->Put ( result->denominator ); 00457 00458 if ( GetType() == subtrahend->GetType() ) { 00459 const Fraction *fr_ptr = dynamic_cast<const Fraction*> ( subtrahend ); 00460 #ifdef DEBUG 00461 assert ( fr_ptr != 0 ); 00462 #endif 00463 00464 result->denominator = denominator->Multiply ( fr_ptr->denominator ); 00465 00466 CASObject* num1 = numerator->Multiply ( fr_ptr->denominator ); 00467 CASObject* num2 = fr_ptr->numerator->Multiply ( denominator ); 00468 result->numerator = num1->Subtract ( num2 ); 00469 00470 CASObject::Garbage->Put ( num1 ); 00471 CASObject::Garbage->Put ( num2 ); 00472 00473 return result; 00474 } 00475 00476 CASObject* num = denominator->Multiply ( subtrahend ); 00477 result->numerator = numerator->Subtract ( num ); 00478 result->denominator = denominator->Clone(); 00479 00480 return result; 00481 } 00482 00498 CASObject* 00499 Fraction::Multiply ( const CASObject* factor ) const { 00500 checkptr ( factor ); 00501 00502 // Prepare the resulting fraction 00503 Fraction *result = new Fraction; 00504 00505 CASObject::Garbage->Put ( result->numerator ); 00506 CASObject::Garbage->Put ( result->denominator ); 00507 00508 if ( GetType() == factor->GetType() ) { 00509 const Fraction *fr_ptr = dynamic_cast<const Fraction*> ( factor ); 00510 #ifdef DEBUG 00511 00512 assert ( fr_ptr != 0 ); 00513 #endif 00514 00515 result->denominator = denominator->Multiply ( fr_ptr->denominator ); 00516 result->numerator = numerator->Multiply ( fr_ptr->numerator ); 00517 00518 return result; 00519 } 00520 00521 00522 result->numerator = numerator->Multiply ( factor ); 00523 result->denominator = denominator->Clone(); 00524 00525 return result; 00526 } 00527 00538 CASObject* 00539 Fraction::Divide ( const CASObject* divisor ) const { 00540 checkptr ( divisor ); 00541 00542 // Prepare the resulting fraction 00543 Fraction *result = new Fraction; 00544 00545 CASObject::Garbage->Put ( result->numerator ); 00546 CASObject::Garbage->Put ( result->denominator ); 00547 00548 if ( GetType() == divisor->GetType() ) { 00549 const Fraction *fr_ptr = dynamic_cast<const Fraction*> ( divisor ); 00550 #ifdef DEBUG 00551 00552 assert ( fr_ptr != 0 ); 00553 #endif 00554 00555 result->denominator = denominator->Multiply ( fr_ptr->numerator ); 00556 result->numerator = numerator->Multiply ( fr_ptr->denominator ); 00557 00558 return result; 00559 } 00560 00561 00562 result->numerator = numerator->Clone(); 00563 result->denominator = denominator->Multiply ( divisor ); 00564 00565 return result; 00566 00567 } 00568 00582 CASObject* 00583 Fraction::Power ( const CASObject* exp ) const { 00584 checkptr ( exp ); 00585 00586 Fraction *result = new Fraction; 00587 00588 CASObject::Garbage->Put ( result->numerator ); 00589 CASObject::Garbage->Put ( result->denominator ); 00590 00591 result->numerator = numerator->Power ( exp ); 00592 result->denominator = denominator->Power ( exp ); 00593 00594 return result; 00595 00596 } 00597 00612 CASObject* 00613 Fraction::Modulo ( const CASObject* divisor ) const { 00614 #ifdef WARNINGS 00615 #warning "Not fully implemented: Fraction::Modulo(const CASObject*) const " 00616 #endif 00617 LongInt *result = new LongInt ( 0L ); 00618 return result; 00619 } 00620 00634 CASObject* 00635 Fraction::GCD ( const CASObject* o ) const { 00636 #ifdef WARNINGS 00637 #warning "Not fully implemented: Fraction::GCD(const CASObject*) const" 00638 #endif 00639 LongInt *result = new LongInt ( 1L ); 00640 return result; 00641 } 00642 00658 bool 00659 Fraction::IsEqual ( const CASObject* o ) const { 00660 #ifdef WARNINGS 00661 #warning "Not fully implemented: Fraction::IsEqual(const CASObject*) const" 00662 #endif 00663 checkptr ( o ); 00664 00665 if ( GetType() == o->GetType() ) { 00666 const Fraction *fr_ptr = dynamic_cast<const Fraction*> ( o ); 00667 #ifdef DEBUG 00668 00669 assert ( fr_ptr != 0 ); 00670 #endif 00671 00672 return ( *this ) == ( *fr_ptr ); 00673 } 00674 else { 00675 return false; 00676 } 00677 } 00678 00689 bool 00690 Fraction::IsLT ( const CASObject* o ) const { 00691 checkptr ( o ); 00692 00693 if ( GetType() < o->GetType() ) { 00694 return true; 00695 } 00696 00697 if ( GetType() > o->GetType() ) { 00698 return false; 00699 } 00700 00701 const Fraction *f = dynamic_cast<const Fraction*> ( o ); 00702 #ifdef DEBUG 00703 assert ( o != 0 ); 00704 #endif 00705 00706 if ( denominator->IsLT ( f->denominator ) ) { 00707 return false; 00708 } 00709 00710 if ( denominator->IsGT ( f->denominator ) ) { 00711 return true; 00712 } 00713 00714 return numerator->IsLT ( f->numerator ); 00715 } 00716 00727 bool 00728 Fraction::IsGT ( const CASObject* o ) const { 00729 checkptr ( o ); 00730 if ( IsEqual ( o ) ) { 00731 return false; 00732 } 00733 00734 return !IsLT ( o ); 00735 } 00736 00752 bool 00753 Fraction::IsSimilar ( const CASObject *o ) const { 00754 checkptr ( o ); 00755 00756 if ( GetType() != o->GetType() ) { 00757 return false; 00758 } 00759 00760 const Fraction *fr = dynamic_cast<const Fraction*> ( o ); 00761 #ifdef DEBUG 00762 assert ( fr != 0 ); 00763 #endif 00764 00765 return ( fr->numerator->IsSimilar ( numerator ) && 00766 fr->denominator->IsSimilar ( denominator ) ); 00767 } 00768 00777 CASObject* 00778 Fraction::SortWeight() const { 00779 CASObject* weightnumerator = numerator->SortWeight(); 00780 CASObject* weightdenominator = denominator->SortWeight(); 00781 CASObject* weight = weightnumerator->Divide ( weightdenominator ); 00782 CASObject::Garbage->Put ( weightnumerator ); 00783 CASObject::Garbage->Put ( weightdenominator ); 00784 00785 return weight; 00786 } 00787 00793 void 00794 Fraction::Sort() { 00795 if ( meta.IsSorted() ) { 00796 return; 00797 } 00798 checkptr ( numerator ); 00799 checkptr ( denominator ); 00800 numerator->Sort(); 00801 denominator->Sort(); 00802 meta.SetSorted(); 00803 } 00804 00818 CASObject* 00819 Fraction::Evaluate() const { 00820 if ( meta.IsEvaluated() ) { 00821 return Clone(); 00822 } 00823 Fraction *ret_val = dynamic_cast<Fraction*> ( Clone() ); 00824 #ifdef DEBUG 00825 00826 assert ( ret_val != 0 ); 00827 #endif 00828 00829 CASObject* denom = ret_val->denominator; 00830 CASObject* num = ret_val->numerator; 00831 00832 ret_val->denominator = ret_val->denominator->Evaluate(); 00833 ret_val->numerator = ret_val->numerator->Evaluate(); 00834 00835 CASObject::Garbage->Put ( denom ); 00836 CASObject::Garbage->Put ( num ); 00837 00838 ret_val->meta.SetEvaluated(); 00839 ret_val->Sort(); 00840 00841 return ret_val; 00842 } 00843 00851 inline bool Fraction::IsPureNumerical() const { 00852 return numerator->IsPureNumerical() && denominator->IsPureNumerical(); 00853 } 00854 00855 // ---------------------------------------------------------------------------- 00856 00857 // Operators 00858 // ---------------------------------------------------------------------------- 00864 const Fraction& 00865 Fraction::operator= ( const Fraction &f ) { 00866 #ifdef SHOWCONSTRUCTOR 00867 std::cerr << "# Fraction::operator=(const Fraction &f)" << std::endl; 00868 #endif 00869 00870 if ( this == &f ) { 00871 return *this; 00872 } 00873 00874 #ifdef DEBUG 00875 assert ( numerator != 0 ); 00876 assert ( denominator != 0 ); 00877 #endif 00878 00879 CASObject::Garbage->Put ( numerator ); 00880 CASObject::Garbage->Put ( denominator ); 00881 00882 numerator = f.numerator->Clone(); 00883 denominator = f.denominator->Clone(); 00884 meta = f.meta; 00885 00886 return *this; 00887 } 00888 00899 const bool 00900 Fraction::operator== ( const Fraction &f ) const { 00901 #ifdef WARNINGS 00902 #warning "Not fully implemented: Fraction::operator==(const Fraction &f)" 00903 #endif 00904 #ifdef DEBUG 00905 assert ( numerator != 0 ); 00906 assert ( denominator != 0 ); 00907 #endif 00908 00909 return numerator->IsEqual ( f.numerator ) && denominator->IsEqual ( f.denominator ); 00910 } 00911 // ---------------------------------------------------------------------------- 00912
1.4.7