• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • kcalc/knumber
 

kcalc/knumber

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 <tqregexp.h>
00026 #include <tqstring.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 KNumber const KNumber::NotDefined("nan");
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(TQString const & num)
00098 {
00099   if (TQRegExp("^(inf|-inf|nan)$").exactMatch(num))
00100     _num = new _knumerror(num);
00101   else if (TQRegExp("^[+-]?\\d+$").exactMatch(num))
00102     _num = new _knuminteger(num);
00103   else if (TQRegExp("^[+-]?\\d+/\\d+$").exactMatch(num)) {
00104     _num = new _knumfraction(num);
00105     simplifyRational();
00106   }
00107   else if (TQRegExp("^[+-]?\\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   else
00114     _num = new _knumerror("nan");
00115 }
00116 
00117 KNumber::NumType KNumber::type(void) const
00118 {
00119   if(dynamic_cast<_knumerror *>(_num))
00120     return SpecialType;
00121   if(dynamic_cast<_knuminteger *>(_num))
00122     return IntegerType;
00123   if(dynamic_cast<_knumfraction *>(_num))
00124     return FractionType;
00125   if(dynamic_cast<_knumfloat *>(_num))
00126     return FloatType;
00127 
00128   return SpecialType;
00129 }
00130 
00131 // This method converts a fraction to an integer, whenever possible,
00132 // i.e. 5/1 --> 5
00133 // This method should be called, whenever such a inproper fraction can occur,
00134 // e.g. when adding 4/3 + 2/3....
00135 void KNumber::simplifyRational(void)
00136 {
00137   if (type() != FractionType)
00138     return;
00139   
00140   _knumfraction *tmp_num = dynamic_cast<_knumfraction *>(_num);
00141 
00142   if (tmp_num->isInteger()) {
00143     _knumber *tmp_num2 = tmp_num->intPart();
00144     delete tmp_num;
00145     _num = tmp_num2;
00146   }
00147 
00148 }
00149 
00150 
00151 KNumber const & KNumber::operator=(KNumber const & num)
00152 {
00153   if (this == & num) 
00154     return *this;
00155 
00156   delete _num;
00157 
00158   switch(num.type()) {
00159   case SpecialType:
00160     _num = new _knumerror();
00161     break;
00162   case IntegerType:
00163     _num = new _knuminteger();
00164     break;
00165   case FractionType:
00166     _num = new _knumfraction();
00167     break;
00168   case FloatType:
00169     _num = new _knumfloat();
00170     break;
00171   };
00172   
00173   _num->copy(*(num._num));
00174 
00175   return *this;
00176 }
00177 
00178 KNumber & KNumber::operator +=(KNumber const &arg)
00179 {
00180   KNumber tmp_num = *this + arg;
00181 
00182   delete _num;
00183 
00184   switch(tmp_num.type()) {
00185   case SpecialType:
00186     _num = new _knumerror();
00187     break;
00188   case IntegerType:
00189     _num = new _knuminteger();
00190     break;
00191   case FractionType:
00192     _num = new _knumfraction();
00193     break;
00194   case FloatType:
00195     _num = new _knumfloat();
00196     break;
00197   };
00198   
00199   _num->copy(*(tmp_num._num));
00200 
00201   return *this;
00202 }
00203 
00204 KNumber & KNumber::operator -=(KNumber const &arg)
00205 {
00206   KNumber tmp_num = *this - arg;
00207 
00208   delete _num;
00209 
00210   switch(tmp_num.type()) {
00211   case SpecialType:
00212     _num = new _knumerror();
00213     break;
00214   case IntegerType:
00215     _num = new _knuminteger();
00216     break;
00217   case FractionType:
00218     _num = new _knumfraction();
00219     break;
00220   case FloatType:
00221     _num = new _knumfloat();
00222     break;
00223   };
00224   
00225   _num->copy(*(tmp_num._num));
00226 
00227   return *this;
00228 }
00229 
00230 // increase the digit at 'position' by one
00231 static void _inc_by_one(TQString &str, int position)
00232 {
00233   for (int i = position; i >= 0; i--)
00234     {
00235       char last_char = str[i].latin1();
00236       switch(last_char)
00237     {
00238     case '0':
00239       str[i] = '1';
00240       break;
00241     case '1':
00242       str[i] = '2';
00243       break;
00244     case '2':
00245       str[i] = '3';
00246       break;
00247     case '3':
00248       str[i] = '4';
00249       break;
00250     case '4':
00251       str[i] = '5';
00252       break;
00253     case '5':
00254       str[i] = '6';
00255       break;
00256     case '6':
00257       str[i] = '7';
00258       break;
00259     case '7':
00260       str[i] = '8';
00261       break;
00262     case '8':
00263       str[i] = '9';
00264       break;
00265     case '9':
00266       str[i] = '0';
00267       if (i == 0) str.prepend('1');
00268       continue;
00269     case '.':
00270       continue;
00271     }
00272       break;
00273     }
00274 }
00275 
00276 // Cut off if more digits in fractional part than 'precision'
00277 static void _round(TQString &str, int precision)
00278 {
00279   int decimalSymbolPos = str.find('.');
00280 
00281   if (decimalSymbolPos == -1)
00282     if (precision == 0)  return;
00283     else if (precision > 0) // add dot if missing (and needed)
00284       {
00285     str.append('.');
00286     decimalSymbolPos = str.length() - 1;
00287       }
00288 
00289   // fill up with more than enough zeroes (in case fractional part too short)
00290   str.append(TQString().fill('0', precision));
00291 
00292   // Now decide whether to round up or down
00293   char last_char = str[decimalSymbolPos + precision + 1].latin1();
00294   switch (last_char)
00295     {
00296     case '0':
00297     case '1':
00298     case '2':
00299     case '3':
00300     case '4':
00301       // nothing to do, rounding down
00302       break;
00303     case '5':
00304     case '6':
00305     case '7':
00306     case '8':
00307     case '9':
00308       // rounding up
00309       _inc_by_one(str, decimalSymbolPos + precision);
00310       break;
00311     default:
00312       break;
00313     }
00314 
00315   decimalSymbolPos = str.find('.');
00316   str.truncate(decimalSymbolPos + precision + 1);
00317 
00318   // if precision == 0 delete also '.'
00319   if (precision == 0) str = str.section('.', 0, 0);
00320 }
00321 
00322 static TQString roundNumber(const TQString &numStr, int precision)
00323 {
00324   TQString tmpString = numStr;
00325   if (precision < 0  ||
00326       ! TQRegExp("^[+-]?\\d+(\\.\\d+)*(e[+-]?\\d+)?$").exactMatch(tmpString))
00327     return numStr;
00328 
00329 
00330   // Skip the sign (for now)
00331   bool neg = (tmpString[0] == '-');
00332   if (neg  ||  tmpString[0] == '+') tmpString.remove(0, 1);
00333 
00334 
00335   // Split off exponential part (including 'e'-symbol)
00336   TQString mantString = tmpString.section('e', 0, 0,
00337                      TQString::SectionCaseInsensitiveSeps);
00338   TQString expString = tmpString.section('e', 1, 1,
00339                     TQString::SectionCaseInsensitiveSeps |
00340                     TQString::SectionIncludeLeadingSep);
00341   if (expString.length() == 1) expString = TQString();
00342 
00343 
00344   _round(mantString, precision);
00345 
00346   if(neg) mantString.prepend('-');
00347 
00348   return mantString +  expString;
00349 }
00350 
00351 
00352 TQString const KNumber::toTQString(int width, int prec) const
00353 {
00354   TQString tmp_str;
00355 
00356   if (*this == Zero) // important to avoid infinite loops below
00357     return "0";
00358   switch (type()) {
00359   case IntegerType:
00360     if (width > 0) { //result needs to be cut-off
00361       bool tmp_bool = _fraction_input; // stupid work-around
00362       _fraction_input = false;
00363       tmp_str = (KNumber("1.0")*(*this)).toTQString(width, -1);
00364       _fraction_input = tmp_bool;
00365     } else
00366       tmp_str = TQString(_num->ascii());
00367     break;
00368   case FractionType:
00369     if (_float_output) {
00370       bool tmp_bool = _fraction_input; // stupid work-around
00371       _fraction_input = false;
00372       tmp_str = (KNumber("1.0")*(*this)).toTQString(width, -1);
00373       _fraction_input = tmp_bool;
00374     } else { // _float_output == false
00375       if(_splitoffinteger_output) {
00376     // split off integer part
00377     KNumber int_part = this->integerPart();
00378     if (int_part == Zero)
00379       tmp_str = TQString(_num->ascii());
00380     else if (int_part < Zero)
00381       tmp_str = int_part.toTQString() + " " + (int_part - *this)._num->ascii();
00382     else
00383       tmp_str = int_part.toTQString() + " " + (*this - int_part)._num->ascii();
00384       } else
00385     tmp_str = TQString(_num->ascii());
00386 
00387       if (width > 0  &&  tmp_str.length() > width) {
00388     //result needs to be cut-off
00389     bool tmp_bool = _fraction_input; // stupid work-around
00390     _fraction_input = false;
00391     tmp_str = (KNumber("1.0")*(*this)).toTQString(width, -1);
00392     _fraction_input = tmp_bool;
00393       }
00394     }
00395 
00396     break;
00397   case FloatType:
00398     if (width > 0)
00399       tmp_str = TQString(_num->ascii(width));
00400     else
00401       // rough estimate for  maximal decimal precision (10^3 = 2^10)
00402       tmp_str = TQString(_num->ascii(3*mpf_get_default_prec()/10));
00403     break;
00404   default:
00405     return TQString(_num->ascii());
00406   }
00407   
00408   if (prec >= 0)
00409     return roundNumber(tmp_str, prec);
00410   else
00411     return tmp_str;
00412 }
00413 
00414 void KNumber::setDefaultFloatOutput(bool flag)
00415 {
00416   _float_output = flag;
00417 }
00418 
00419 void KNumber::setDefaultFractionalInput(bool flag)
00420 {
00421   _fraction_input = flag;
00422 }
00423 
00424 void KNumber::setSplitoffIntegerForFractionOutput(bool flag)
00425 {
00426   _splitoffinteger_output = flag;
00427 }
00428 
00429 void KNumber::setDefaultFloatPrecision(unsigned int prec)
00430 {
00431   // Need to transform decimal digits into binary digits
00432   unsigned long int bin_prec = static_cast<unsigned long int>
00433     (double(prec) * M_LN10 / M_LN2 + 1);
00434 
00435   mpf_set_default_prec(bin_prec);
00436 }
00437 
00438 KNumber const KNumber::abs(void) const
00439 {
00440   KNumber tmp_num;
00441   delete tmp_num._num;
00442 
00443   tmp_num._num = _num->abs();
00444 
00445   return tmp_num;
00446 }
00447 
00448 KNumber const KNumber::cbrt(void) const
00449 {
00450   KNumber tmp_num;
00451   delete tmp_num._num;
00452 
00453   tmp_num._num = _num->cbrt();
00454 
00455   return tmp_num;
00456 }
00457 
00458 KNumber const KNumber::sqrt(void) const
00459 {
00460   KNumber tmp_num;
00461   delete tmp_num._num;
00462 
00463   tmp_num._num = _num->sqrt();
00464 
00465   return tmp_num;
00466 }
00467 
00468 KNumber const KNumber::integerPart(void) const
00469 {
00470   KNumber tmp_num;
00471   delete tmp_num._num;
00472   tmp_num._num = _num->intPart();
00473 
00474   return tmp_num;
00475 }
00476 
00477 KNumber const KNumber::power(KNumber const &exp) const
00478 {
00479   if (*this == Zero) {
00480     if(exp == Zero)
00481       return KNumber("nan"); // 0^0 not defined
00482     else if (exp < Zero)
00483       return KNumber("inf");
00484     else
00485       return KNumber(0);
00486   }
00487 
00488   if (exp == Zero) {
00489     if (*this != Zero)
00490       return One;
00491     else
00492       return KNumber("nan");
00493   }
00494   else if (exp < Zero) {
00495     KNumber tmp_num;
00496     KNumber tmp_num2 = -exp;
00497     delete tmp_num._num;
00498     tmp_num._num = _num->power(*(tmp_num2._num));
00499 
00500     return One/tmp_num;
00501   }
00502   else {
00503     KNumber tmp_num;
00504     delete tmp_num._num;
00505     tmp_num._num = _num->power(*(exp._num));
00506 
00507     return tmp_num;
00508   }
00509 
00510 }
00511 
00512 KNumber const KNumber::operator-(void) const
00513 {
00514   KNumber tmp_num;
00515   delete tmp_num._num;
00516 
00517   tmp_num._num = _num->change_sign();
00518 
00519   return tmp_num;
00520 }
00521 
00522 KNumber const KNumber::operator+(KNumber const & arg2) const
00523 {
00524   KNumber tmp_num;
00525   delete tmp_num._num;
00526 
00527   tmp_num._num = _num->add(*arg2._num);
00528 
00529   tmp_num.simplifyRational();
00530 
00531   return tmp_num;
00532 }
00533 
00534 KNumber const KNumber::operator-(KNumber const & arg2) const
00535 {
00536   return *this + (-arg2);
00537 }
00538 
00539 KNumber const KNumber::operator*(KNumber const & arg2) const
00540 {
00541   KNumber tmp_num;
00542   delete tmp_num._num;
00543 
00544   tmp_num._num = _num->multiply(*arg2._num);
00545 
00546   tmp_num.simplifyRational();
00547 
00548   return tmp_num;
00549 }
00550 
00551 KNumber const KNumber::operator/(KNumber const & arg2) const
00552 {
00553   KNumber tmp_num;
00554   delete tmp_num._num;
00555 
00556   tmp_num._num = _num->divide(*arg2._num);
00557 
00558   tmp_num.simplifyRational();
00559 
00560   return tmp_num;
00561 }
00562 
00563 
00564 KNumber const KNumber::operator%(KNumber const & arg2) const
00565 {
00566   if (type() != IntegerType  ||  arg2.type() != IntegerType)
00567     return Zero;
00568 
00569   KNumber tmp_num;
00570   delete tmp_num._num;
00571 
00572   _knuminteger const *tmp_arg1 = dynamic_cast<_knuminteger const *>(_num);
00573   _knuminteger const *tmp_arg2 = dynamic_cast<_knuminteger const *>(arg2._num);
00574 
00575   tmp_num._num = tmp_arg1->mod(*tmp_arg2);
00576 
00577   return tmp_num;
00578 }
00579 
00580 KNumber const KNumber::operator&(KNumber const & arg2) const
00581 {
00582   if (type() != IntegerType  ||  arg2.type() != IntegerType)
00583     return Zero;
00584 
00585   KNumber tmp_num;
00586   delete tmp_num._num;
00587 
00588   _knuminteger const *tmp_arg1 = dynamic_cast<_knuminteger const *>(_num);
00589   _knuminteger const *tmp_arg2 = dynamic_cast<_knuminteger const *>(arg2._num);
00590 
00591   tmp_num._num = tmp_arg1->intAnd(*tmp_arg2);
00592 
00593   return tmp_num;
00594 
00595 }
00596 
00597 KNumber const KNumber::operator|(KNumber const & arg2) const
00598 {
00599   if (type() != IntegerType  ||  arg2.type() != IntegerType)
00600     return Zero;
00601 
00602   KNumber tmp_num;
00603   delete tmp_num._num;
00604 
00605   _knuminteger const *tmp_arg1 = dynamic_cast<_knuminteger const *>(_num);
00606   _knuminteger const *tmp_arg2 = dynamic_cast<_knuminteger const *>(arg2._num);
00607 
00608   tmp_num._num = tmp_arg1->intOr(*tmp_arg2);
00609 
00610   return tmp_num;
00611 }
00612 
00613 
00614 KNumber const KNumber::operator<<(KNumber const & arg2) const
00615 {
00616   if (type() != IntegerType  ||  arg2.type() != IntegerType)
00617     return KNumber("nan");
00618 
00619   _knuminteger const *tmp_arg1 = dynamic_cast<_knuminteger const *>(_num);
00620   _knuminteger const *tmp_arg2 = dynamic_cast<_knuminteger const *>(arg2._num);
00621 
00622   KNumber tmp_num;
00623   delete tmp_num._num;
00624   tmp_num._num = tmp_arg1->shift(*tmp_arg2);
00625 
00626   return tmp_num;
00627 }
00628 
00629 KNumber const KNumber::operator>>(KNumber const & arg2) const
00630 {
00631   if (type() != IntegerType  ||  arg2.type() != IntegerType)
00632     return KNumber("nan");
00633 
00634   KNumber tmp_num = -arg2;
00635 
00636   _knuminteger const *tmp_arg1 = dynamic_cast<_knuminteger const *>(_num);
00637   _knuminteger const *tmp_arg2 = dynamic_cast<_knuminteger const *>(tmp_num._num);
00638 
00639   KNumber tmp_num2;
00640   delete tmp_num2._num;
00641   tmp_num2._num = tmp_arg1->shift(*tmp_arg2);
00642 
00643   return tmp_num2;
00644 }
00645 
00646 
00647 
00648 KNumber::operator bool(void) const
00649 {
00650   if (*this == Zero)
00651     return false;
00652   return true;
00653 }
00654 
00655 KNumber::operator signed long int(void) const
00656 {
00657   return static_cast<signed long int>(*_num);
00658 }
00659 
00660 KNumber::operator unsigned long int(void) const
00661 {
00662   return static_cast<unsigned long int>(*_num);
00663 }
00664 
00665 KNumber::operator unsigned long long int(void) const
00666 {
00667 #if SIZEOF_UNSIGNED_LONG == 8
00668   return static_cast<unsigned long int>(*this);
00669 #elif SIZEOF_UNSIGNED_LONG == 4
00670   KNumber tmp_num1 = this->abs().integerPart();
00671   unsigned long long int tmp_num2 =  static_cast<unsigned long int>(tmp_num1) +
00672     (static_cast<unsigned long long int>(
00673                      static_cast<unsigned long int>(tmp_num1 >> KNumber("32"))) << 32) ;
00674   
00675 #warning the cast operator from KNumber to unsigned long long int is probably buggy, when a sign is involved
00676   if (*this > KNumber(0))
00677     return tmp_num2;
00678   else
00679     return static_cast<unsigned long long int> (- static_cast<signed long long int>(tmp_num2));
00680 #else
00681 #error "SIZEOF_UNSIGNED_LONG is a unhandled case"
00682 #endif  
00683 }
00684 
00685 KNumber::operator double(void) const
00686 {
00687   return static_cast<double>(*_num);
00688 }
00689 
00690 int const KNumber::compare(KNumber const & arg2) const
00691 {
00692   return _num->compare(*arg2._num);
00693 }

kcalc/knumber

Skip menu "kcalc/knumber"
  • Main Page
  • Alphabetical List
  • Class List
  • File List
  • Class Members

kcalc/knumber

Skip menu "kcalc/knumber"
  • kcalc
  •   knumber
  • superkaramba
Generated for kcalc/knumber by doxygen 1.7.6.1
This website is maintained by Timothy Pearson.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. |