• Skip to content
  • Skip to link menu
KDE 4.0 API Reference
  • KDE API Reference
  • kdeutils
  • Sitemap
  • Contact Us
 

kcalc

knumber.cpp

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

kcalc

Skip menu "kcalc"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members

kdeutils

Skip menu "kdeutils"
  • ark
  • kcalc
  • kcharselect
  • kdelirc
  • kdessh
  • kdf
  • kfloppy
  • kgpg
  • kjots
  • klaptopdaemon
  • kmilo
  • ksim
  • ktimer
  • kwallet
  • superkaramba
Generated for kdeutils by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal