knumber.cpp

00001 // -*- c-basic-offset: 2 -*-
00002 /* This file is part of the KDE libraries
00003    Copyright (c) 2005 Klaus Niederkrueger <kniederk@math.uni-koeln.de>
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public License
00016    along with this library; see the file COPYING.LIB.  If not, write to
00017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018    Boston, MA 02110-1301, USA.
00019 */
00020 
00021 #include <math.h>
00022 
00023 #include <config.h>
00024 
00025 #include <qregexp.h>
00026 #include <qstring.h>
00027 
00028 #include "knumber.h"
00029 
00030 KNumber const KNumber::Zero(0);
00031 KNumber const KNumber::One(1);
00032 KNumber const KNumber::MinusOne(-1);
00033 KNumber const KNumber::Pi("3.141592653589793238462643383279502884197169"
00034               "39937510582097494459230781640628620899862803"
00035               "4825342117068");
00036 KNumber const KNumber::Euler("2.718281828459045235360287471352662497757"
00037                  "24709369995957496696762772407663035354759"
00038                  "4571382178525166427");
00039 
00040 
00041 bool KNumber::_float_output = false;
00042 bool KNumber::_fraction_input = false;
00043 bool KNumber::_splitoffinteger_output = false;
00044 
00045 KNumber::KNumber(signed int num)
00046 {
00047   _num = new _knuminteger(num);
00048 }
00049 
00050 KNumber::KNumber(unsigned int num)
00051 {
00052   _num = new _knuminteger(num);
00053 }
00054 
00055 KNumber::KNumber(signed long int num)
00056 {
00057   _num = new _knuminteger(num);
00058 }
00059 
00060 KNumber::KNumber(unsigned long int num)
00061 {
00062   _num = new _knuminteger(num);
00063 }
00064 
00065 KNumber::KNumber(unsigned long long int num)
00066 {
00067   _num = new _knuminteger(num);
00068 }
00069 
00070 KNumber::KNumber(double num)
00071 {
00072   if ( isinf(num) ) _num = new _knumerror( _knumber::Infinity );
00073   else if ( isnan(num) ) _num = new _knumerror( _knumber::UndefinedNumber );
00074   else _num = new _knumfloat(num);      
00075 
00076 }
00077 
00078 KNumber::KNumber(KNumber const & num)
00079 {
00080   switch(num.type()) {
00081   case SpecialType:
00082     _num = new _knumerror(*(num._num));
00083     return;
00084   case IntegerType:
00085     _num = new _knuminteger(*(num._num));
00086     return;
00087   case  FractionType:
00088     _num = new _knumfraction(*(num._num));
00089     return;
00090   case FloatType:
00091     _num = new _knumfloat(*(num._num));
00092     return;
00093   };
00094 }
00095 
00096 
00097 KNumber::KNumber(QString const & num)
00098 {
00099   if (QRegExp("^(inf|-inf|nan)$").exactMatch(num))
00100     _num = new _knumerror(num);
00101   else if (QRegExp("^[+-]?\\d+$").exactMatch(num))
00102     _num = new _knuminteger(num);
00103   else if (QRegExp("^[+-]?\\d+/\\d+$").exactMatch(num)) {
00104     _num = new _knumfraction(num);
00105     simplifyRational();
00106   }
00107   else if (QRegExp("^[+-]?\\d+(\\.\\d*)?(e[+-]?\\d+)?$").exactMatch(num))
00108     if (_fraction_input == true) {
00109       _num = new _knumfraction(num);
00110       simplifyRational();
00111     } else
00112       _num = new _knumfloat(num);
00113 }
00114 
00115 KNumber::NumType KNumber::type(void) const
00116 {
00117   if(dynamic_cast<_knumerror *>(_num))
00118     return SpecialType;
00119   if(dynamic_cast<_knuminteger *>(_num))
00120     return IntegerType;
00121   if(dynamic_cast<_knumfraction *>(_num))
00122     return FractionType;
00123   if(dynamic_cast<_knumfloat *>(_num))
00124     return FloatType;
00125 
00126   return SpecialType;
00127 }
00128 
00129 // This method converts a fraction to an integer, whenever possible,
00130 // i.e. 5/1 --> 5
00131 // This method should be called, whenever such a inproper fraction can occur,
00132 // e.g. when adding 4/3 + 2/3....
00133 void KNumber::simplifyRational(void)
00134 {
00135   if (type() != FractionType)
00136     return;
00137   
00138   _knumfraction *tmp_num = dynamic_cast<_knumfraction *>(_num);
00139 
00140   if (tmp_num->isInteger()) {
00141     _knumber *tmp_num2 = tmp_num->intPart();
00142     delete tmp_num;
00143     _num = tmp_num2;
00144   }
00145 
00146 }
00147 
00148 
00149 KNumber const & KNumber::operator=(KNumber const & num)
00150 {
00151   if (this == & num) 
00152     return *this;
00153 
00154   delete _num;
00155 
00156   switch(num.type()) {
00157   case SpecialType:
00158     _num = new _knumerror();
00159     break;
00160   case IntegerType:
00161     _num = new _knuminteger();
00162     break;
00163   case FractionType:
00164     _num = new _knumfraction();
00165     break;
00166   case FloatType:
00167     _num = new _knumfloat();
00168     break;
00169   };
00170   
00171   _num->copy(*(num._num));
00172 
00173   return *this;
00174 }
00175 
00176 KNumber & KNumber::operator +=(KNumber const &arg)
00177 {
00178   KNumber tmp_num = *this + arg;
00179 
00180   delete _num;
00181 
00182   switch(tmp_num.type()) {
00183   case SpecialType:
00184     _num = new _knumerror();
00185     break;
00186   case IntegerType:
00187     _num = new _knuminteger();
00188     break;
00189   case FractionType:
00190     _num = new _knumfraction();
00191     break;
00192   case FloatType:
00193     _num = new _knumfloat();
00194     break;
00195   };
00196   
00197   _num->copy(*(tmp_num._num));
00198 
00199   return *this;
00200 }
00201 
00202 KNumber & KNumber::operator -=(KNumber const &arg)
00203 {
00204   KNumber tmp_num = *this - arg;
00205 
00206   delete _num;
00207 
00208   switch(tmp_num.type()) {
00209   case SpecialType:
00210     _num = new _knumerror();
00211     break;
00212   case IntegerType:
00213     _num = new _knuminteger();
00214     break;
00215   case FractionType:
00216     _num = new _knumfraction();
00217     break;
00218   case FloatType:
00219     _num = new _knumfloat();
00220     break;
00221   };
00222   
00223   _num->copy(*(tmp_num._num));
00224 
00225   return *this;
00226 }
00227 
00228 // increase the digit at 'position' by one
00229 static void _inc_by_one(QString &str, int position)
00230 {
00231   for (int i = position; i >= 0; i--)
00232     {
00233       char last_char = str[i].latin1();
00234       switch(last_char)
00235     {
00236     case '0':
00237       str[i] = '1';
00238       break;
00239     case '1':
00240       str[i] = '2';
00241       break;
00242     case '2':
00243       str[i] = '3';
00244       break;
00245     case '3':
00246       str[i] = '4';
00247       break;
00248     case '4':
00249       str[i] = '5';
00250       break;
00251     case '5':
00252       str[i] = '6';
00253       break;
00254     case '6':
00255       str[i] = '7';
00256       break;
00257     case '7':
00258       str[i] = '8';
00259       break;
00260     case '8':
00261       str[i] = '9';
00262       break;
00263     case '9':
00264       str[i] = '0';
00265       if (i == 0) str.prepend('1');
00266       continue;
00267     case '.':
00268       continue;
00269     }
00270       break;
00271     }
00272 }
00273 
00274 // Cut off if more digits in fractional part than 'precision'
00275 static void _round(QString &str, int precision)
00276 {
00277   int decimalSymbolPos = str.find('.');
00278 
00279   if (decimalSymbolPos == -1)
00280     if (precision == 0)  return;
00281     else if (precision > 0) // add dot if missing (and needed)
00282       {
00283     str.append('.');
00284     decimalSymbolPos = str.length() - 1;
00285       }
00286 
00287   // fill up with more than enough zeroes (in case fractional part too short)
00288   str.append(QString().fill('0', precision));
00289 
00290   // Now decide whether to round up or down
00291   char last_char = str[decimalSymbolPos + precision + 1].latin1();
00292   switch (last_char)
00293     {
00294     case '0':
00295     case '1':
00296     case '2':
00297     case '3':
00298     case '4':
00299       // nothing to do, rounding down
00300       break;
00301     case '5':
00302     case '6':
00303     case '7':
00304     case '8':
00305     case '9':
00306       // rounding up
00307       _inc_by_one(str, decimalSymbolPos + precision);
00308       break;
00309     default:
00310       break;
00311     }
00312 
00313   decimalSymbolPos = str.find('.');
00314   str.truncate(decimalSymbolPos + precision + 1);
00315 
00316   // if precision == 0 delete also '.'
00317   if (precision == 0) str = str.section('.', 0, 0);
00318 }
00319 
00320 static QString roundNumber(const QString &numStr, int precision)
00321 {
00322   QString tmpString = numStr;
00323   if (precision < 0  ||
00324       ! QRegExp("^[+-]?\\d+(\\.\\d+)*(e[+-]?\\d+)?$").exactMatch(tmpString))
00325     return numStr;
00326 
00327 
00328   // Skip the sign (for now)
00329   bool neg = (tmpString[0] == '-');
00330   if (neg  ||  tmpString[0] == '+') tmpString.remove(0, 1);
00331 
00332 
00333   // Split off exponential part (including 'e'-symbol)
00334   QString mantString = tmpString.section('e', 0, 0,
00335                      QString::SectionCaseInsensitiveSeps);
00336   QString expString = tmpString.section('e', 1, 1,
00337                     QString::SectionCaseInsensitiveSeps |
00338                     QString::SectionIncludeLeadingSep);
00339   if (expString.length() == 1) expString = QString();
00340 
00341 
00342   _round(mantString, precision);
00343 
00344   if(neg) mantString.prepend('-');
00345 
00346   return mantString +  expString;
00347 }
00348 
00349 
00350 QString const KNumber::toQString(int width, int prec) const
00351 {
00352   QString tmp_str;
00353 
00354   if (*this == Zero) // important to avoid infinite loops below
00355     return "0";
00356   switch (type()) {
00357   case IntegerType:
00358     if (width > 0) { //result needs to be cut-off
00359       bool tmp_bool = _fraction_input; // stupid work-around
00360       _fraction_input = false;
00361       tmp_str = (KNumber("1.0")*(*this)).toQString(width, -1);
00362       _fraction_input = tmp_bool;
00363     } else
00364       tmp_str = QString(_num->ascii());
00365     break;
00366   case FractionType:
00367     if (_float_output) {
00368       bool tmp_bool = _fraction_input; // stupid work-around
00369       _fraction_input = false;
00370       tmp_str = (KNumber("1.0")*(*this)).toQString(width, -1);
00371       _fraction_input = tmp_bool;
00372     } else { // _float_output == false
00373       if(_splitoffinteger_output) {
00374     // split off integer part
00375     KNumber int_part = this->integerPart();
00376     if (int_part == Zero)
00377       tmp_str = QString(_num->ascii());
00378     else if (int_part < Zero)
00379       tmp_str = int_part.toQString() + " " + (int_part - *this)._num->ascii();
00380     else
00381       tmp_str = int_part.toQString() + " " + (*this - int_part)._num->ascii();
00382       } else
00383     tmp_str = QString(_num->ascii());
00384 
00385       if (width > 0  &&  tmp_str.length() > width) {
00386     //result needs to be cut-off
00387     bool tmp_bool = _fraction_input; // stupid work-around
00388     _fraction_input = false;
00389     tmp_str = (KNumber("1.0")*(*this)).toQString(width, -1);
00390     _fraction_input = tmp_bool;
00391       }
00392     }
00393 
00394     break;
00395   case FloatType:
00396     if (width > 0)
00397       tmp_str = QString(_num->ascii(width));
00398     else
00399       // rough estimate for  maximal decimal precision (10^3 = 2^10)
00400       tmp_str = QString(_num->ascii(3*mpf_get_default_prec()/10));
00401     break;
00402   default:
00403     return QString(_num->ascii());
00404   }
00405   
00406   if (prec >= 0)
00407     return roundNumber(tmp_str, prec);
00408   else
00409     return tmp_str;
00410 }
00411 
00412 void KNumber::setDefaultFloatOutput(bool flag)
00413 {
00414   _float_output = flag;
00415 }
00416 
00417 void KNumber::setDefaultFractionalInput(bool flag)
00418 {
00419   _fraction_input = flag;
00420 }
00421 
00422 void KNumber::setSplitoffIntegerForFractionOutput(bool flag)
00423 {
00424   _splitoffinteger_output = flag;
00425 }
00426 
00427 void KNumber::setDefaultFloatPrecision(unsigned int prec)
00428 {
00429   // Need to transform decimal digits into binary digits
00430   unsigned long int bin_prec = static_cast<unsigned long int>
00431     (double(prec) * M_LN10 / M_LN2 + 1);
00432 
00433   mpf_set_default_prec(bin_prec);
00434 }
00435 
00436 KNumber const KNumber::abs(void) const
00437 {
00438   KNumber tmp_num;
00439   delete tmp_num._num;
00440 
00441   tmp_num._num = _num->abs();
00442 
00443   return tmp_num;
00444 }
00445 
00446 KNumber const KNumber::cbrt(void) const
00447 {
00448   KNumber tmp_num;
00449   delete tmp_num._num;
00450 
00451   tmp_num._num = _num->cbrt();
00452 
00453   return tmp_num;
00454 }
00455 
00456 KNumber const KNumber::sqrt(void) const
00457 {
00458   KNumber tmp_num;
00459   delete tmp_num._num;
00460 
00461   tmp_num._num = _num->sqrt();
00462 
00463   return tmp_num;
00464 }
00465 
00466 KNumber const KNumber::integerPart(void) const
00467 {
00468   KNumber tmp_num;
00469   delete tmp_num._num;
00470   tmp_num._num = _num->intPart();
00471 
00472   return tmp_num;
00473 }
00474 
00475 KNumber const KNumber::power(KNumber const &exp) const
00476 {
00477   if (*this == Zero) {
00478     if(exp == Zero)
00479       return KNumber("nan"); // 0^0 not defined
00480     else if (exp < Zero)
00481       return KNumber("inf");
00482     else
00483       return KNumber(0);
00484   }
00485 
00486   if (exp == Zero) {
00487     if (*this != Zero)
00488       return One;
00489     else
00490       return KNumber("nan");
00491   }
00492   else if (exp < Zero) {
00493     KNumber tmp_num;
00494     KNumber tmp_num2 = -exp;
00495     delete tmp_num._num;
00496     tmp_num._num = _num->power(*(tmp_num2._num));
00497 
00498     return One/tmp_num;
00499   }
00500   else {
00501     KNumber tmp_num;
00502     delete tmp_num._num;
00503     tmp_num._num = _num->power(*(exp._num));
00504 
00505     return tmp_num;
00506   }
00507 
00508 }
00509 
00510 KNumber const KNumber::operator-(void) const
00511 {
00512   KNumber tmp_num;
00513   delete tmp_num._num;
00514 
00515   tmp_num._num = _num->change_sign();
00516 
00517   return tmp_num;
00518 }
00519 
00520 KNumber const KNumber::operator+(KNumber const & arg2) const
00521 {
00522   KNumber tmp_num;
00523   delete tmp_num._num;
00524 
00525   tmp_num._num = _num->add(*arg2._num);
00526 
00527   tmp_num.simplifyRational();
00528 
00529   return tmp_num;
00530 }
00531 
00532 KNumber const KNumber::operator-(KNumber const & arg2) const
00533 {
00534   return *this + (-arg2);
00535 }
00536 
00537 KNumber const KNumber::operator*(KNumber const & arg2) const
00538 {
00539   KNumber tmp_num;
00540   delete tmp_num._num;
00541 
00542   tmp_num._num = _num->multiply(*arg2._num);
00543 
00544   tmp_num.simplifyRational();
00545 
00546   return tmp_num;
00547 }
00548 
00549 KNumber const KNumber::operator/(KNumber const & arg2) const
00550 {
00551   KNumber tmp_num;
00552   delete tmp_num._num;
00553 
00554   tmp_num._num = _num->divide(*arg2._num);
00555 
00556   tmp_num.simplifyRational();
00557 
00558   return tmp_num;
00559 }
00560 
00561 
00562 KNumber const KNumber::operator%(KNumber const & arg2) const
00563 {
00564   if (type() != IntegerType  ||  arg2.type() != IntegerType)
00565     return Zero;
00566 
00567   KNumber tmp_num;
00568   delete tmp_num._num;
00569 
00570   _knuminteger const *tmp_arg1 = dynamic_cast<_knuminteger const *>(_num);
00571   _knuminteger const *tmp_arg2 = dynamic_cast<_knuminteger const *>(arg2._num);
00572 
00573   tmp_num._num = tmp_arg1->mod(*tmp_arg2);
00574 
00575   return tmp_num;
00576 }
00577 
00578 KNumber const KNumber::operator&(KNumber const & arg2) const
00579 {
00580   if (type() != IntegerType  ||  arg2.type() != IntegerType)
00581     return Zero;
00582 
00583   KNumber tmp_num;
00584   delete tmp_num._num;
00585 
00586   _knuminteger const *tmp_arg1 = dynamic_cast<_knuminteger const *>(_num);
00587   _knuminteger const *tmp_arg2 = dynamic_cast<_knuminteger const *>(arg2._num);
00588 
00589   tmp_num._num = tmp_arg1->intAnd(*tmp_arg2);
00590 
00591   return tmp_num;
00592 
00593 }
00594 
00595 KNumber const KNumber::operator|(KNumber const & arg2) const
00596 {
00597   if (type() != IntegerType  ||  arg2.type() != IntegerType)
00598     return Zero;
00599 
00600   KNumber tmp_num;
00601   delete tmp_num._num;
00602 
00603   _knuminteger const *tmp_arg1 = dynamic_cast<_knuminteger const *>(_num);
00604   _knuminteger const *tmp_arg2 = dynamic_cast<_knuminteger const *>(arg2._num);
00605 
00606   tmp_num._num = tmp_arg1->intOr(*tmp_arg2);
00607 
00608   return tmp_num;
00609 }
00610 
00611 
00612 KNumber const KNumber::operator<<(KNumber const & arg2) const
00613 {
00614   if (type() != IntegerType  ||  arg2.type() != IntegerType)
00615     return KNumber("nan");
00616 
00617   _knuminteger const *tmp_arg1 = dynamic_cast<_knuminteger const *>(_num);
00618   _knuminteger const *tmp_arg2 = dynamic_cast<_knuminteger const *>(arg2._num);
00619 
00620   KNumber tmp_num;
00621   delete tmp_num._num;
00622   tmp_num._num = tmp_arg1->shift(*tmp_arg2);
00623 
00624   return tmp_num;
00625 }
00626 
00627 KNumber const KNumber::operator>>(KNumber const & arg2) const
00628 {
00629   if (type() != IntegerType  ||  arg2.type() != IntegerType)
00630     return KNumber("nan");
00631 
00632   KNumber tmp_num = -arg2;
00633 
00634   _knuminteger const *tmp_arg1 = dynamic_cast<_knuminteger const *>(_num);
00635   _knuminteger const *tmp_arg2 = dynamic_cast<_knuminteger const *>(tmp_num._num);
00636 
00637   KNumber tmp_num2;
00638   delete tmp_num2._num;
00639   tmp_num2._num = tmp_arg1->shift(*tmp_arg2);
00640 
00641   return tmp_num2;
00642 }
00643 
00644 
00645 
00646 KNumber::operator bool(void) const
00647 {
00648   if (*this == Zero)
00649     return false;
00650   return true;
00651 }
00652 
00653 KNumber::operator signed long int(void) const
00654 {
00655   return static_cast<signed long int>(*_num);
00656 }
00657 
00658 KNumber::operator unsigned long int(void) const
00659 {
00660   return static_cast<unsigned long int>(*_num);
00661 }
00662 
00663 KNumber::operator unsigned long long int(void) const
00664 {
00665 #if SIZEOF_LONG >= 8
00666   return static_cast<unsigned long int>(*this);
00667 #else
00668 
00669   KNumber tmp_num1 = this->abs().integerPart();
00670   unsigned long long int tmp_num2 =  static_cast<unsigned long int>(tmp_num1) +
00671     (static_cast<unsigned long long int>(
00672                      static_cast<unsigned long int>(tmp_num1 >> KNumber("32"))) << 32) ;
00673   
00674 #warning the cast operator from KNumber to unsigned long long int is probably buggy, when a sign is involved
00675   if (*this > KNumber(0))
00676     return tmp_num2;
00677   else
00678     return static_cast<unsigned long long int> (- static_cast<signed long long int>(tmp_num2));
00679 
00680 #endif  
00681 }
00682 
00683 KNumber::operator double(void) const
00684 {
00685   return static_cast<double>(*_num);
00686 }
00687 
00688 int const KNumber::compare(KNumber const & arg2) const
00689 {
00690   return _num->compare(*arg2._num);
00691 }
KDE Home | KDE Accessibility Home | Description of Access Keys