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

kcalc/knumber

  • kcalc
  • knumber
knumber.cpp
1 // -*- c-basic-offset: 2 -*-
2 /* This file is part of the KDE libraries
3  Copyright (c) 2005 Klaus Niederkrueger <kniederk@math.uni-koeln.de>
4 
5  This library is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Library General Public
7  License as published by the Free Software Foundation; either
8  version 2 of the License, or (at your option) any later version.
9 
10  This library is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Library General Public License for more details.
14 
15  You should have received a copy of the GNU Library General Public License
16  along with this library; see the file COPYING.LIB. If not, write to
17  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  Boston, MA 02110-1301, USA.
19 */
20 
21 #include <math.h>
22 
23 #include <config.h>
24 
25 #include <tqregexp.h>
26 #include <tqstring.h>
27 
28 #include "knumber.h"
29 
30 KNumber const KNumber::Zero(0);
31 KNumber const KNumber::One(1);
32 KNumber const KNumber::MinusOne(-1);
33 KNumber const KNumber::Pi("3.141592653589793238462643383279502884197169"
34  "39937510582097494459230781640628620899862803"
35  "4825342117068");
36 KNumber const KNumber::Euler("2.718281828459045235360287471352662497757"
37  "24709369995957496696762772407663035354759"
38  "4571382178525166427");
39 KNumber const KNumber::NotDefined("nan");
40 
41 bool KNumber::_float_output = false;
42 bool KNumber::_fraction_input = false;
43 bool KNumber::_splitoffinteger_output = false;
44 
45 KNumber::KNumber(signed int num)
46 {
47  _num = new _knuminteger(num);
48 }
49 
50 KNumber::KNumber(unsigned int num)
51 {
52  _num = new _knuminteger(num);
53 }
54 
55 KNumber::KNumber(signed long int num)
56 {
57  _num = new _knuminteger(num);
58 }
59 
60 KNumber::KNumber(unsigned long int num)
61 {
62  _num = new _knuminteger(num);
63 }
64 
65 KNumber::KNumber(unsigned long long int num)
66 {
67  _num = new _knuminteger(num);
68 }
69 
70 KNumber::KNumber(double num)
71 {
72  if ( isinf(num) ) _num = new _knumerror( _knumber::Infinity );
73  else if ( isnan(num) ) _num = new _knumerror( _knumber::UndefinedNumber );
74  else _num = new _knumfloat(num);
75 
76 }
77 
78 KNumber::KNumber(KNumber const & num)
79 {
80  switch(num.type()) {
81  case SpecialType:
82  _num = new _knumerror(*(num._num));
83  return;
84  case IntegerType:
85  _num = new _knuminteger(*(num._num));
86  return;
87  case FractionType:
88  _num = new _knumfraction(*(num._num));
89  return;
90  case FloatType:
91  _num = new _knumfloat(*(num._num));
92  return;
93  };
94 }
95 
96 
97 KNumber::KNumber(TQString const & num)
98 {
99  if (TQRegExp("^(inf|-inf|nan)$").exactMatch(num))
100  _num = new _knumerror(num);
101  else if (TQRegExp("^[+-]?\\d+$").exactMatch(num))
102  _num = new _knuminteger(num);
103  else if (TQRegExp("^[+-]?\\d+/\\d+$").exactMatch(num)) {
104  _num = new _knumfraction(num);
105  simplifyRational();
106  }
107  else if (TQRegExp("^[+-]?\\d+(\\.\\d*)?(e[+-]?\\d+)?$").exactMatch(num))
108  if (_fraction_input == true) {
109  _num = new _knumfraction(num);
110  simplifyRational();
111  } else
112  _num = new _knumfloat(num);
113  else
114  _num = new _knumerror("nan");
115 }
116 
117 KNumber::NumType KNumber::type(void) const
118 {
119  if(dynamic_cast<_knumerror *>(_num))
120  return SpecialType;
121  if(dynamic_cast<_knuminteger *>(_num))
122  return IntegerType;
123  if(dynamic_cast<_knumfraction *>(_num))
124  return FractionType;
125  if(dynamic_cast<_knumfloat *>(_num))
126  return FloatType;
127 
128  return SpecialType;
129 }
130 
131 // This method converts a fraction to an integer, whenever possible,
132 // i.e. 5/1 --> 5
133 // This method should be called, whenever such a inproper fraction can occur,
134 // e.g. when adding 4/3 + 2/3....
135 void KNumber::simplifyRational(void)
136 {
137  if (type() != FractionType)
138  return;
139 
140  _knumfraction *tmp_num = dynamic_cast<_knumfraction *>(_num);
141 
142  if (tmp_num->isInteger()) {
143  _knumber *tmp_num2 = tmp_num->intPart();
144  delete tmp_num;
145  _num = tmp_num2;
146  }
147 
148 }
149 
150 
151 KNumber const & KNumber::operator=(KNumber const & num)
152 {
153  if (this == & num)
154  return *this;
155 
156  delete _num;
157 
158  switch(num.type()) {
159  case SpecialType:
160  _num = new _knumerror();
161  break;
162  case IntegerType:
163  _num = new _knuminteger();
164  break;
165  case FractionType:
166  _num = new _knumfraction();
167  break;
168  case FloatType:
169  _num = new _knumfloat();
170  break;
171  };
172 
173  _num->copy(*(num._num));
174 
175  return *this;
176 }
177 
178 KNumber & KNumber::operator +=(KNumber const &arg)
179 {
180  KNumber tmp_num = *this + arg;
181 
182  delete _num;
183 
184  switch(tmp_num.type()) {
185  case SpecialType:
186  _num = new _knumerror();
187  break;
188  case IntegerType:
189  _num = new _knuminteger();
190  break;
191  case FractionType:
192  _num = new _knumfraction();
193  break;
194  case FloatType:
195  _num = new _knumfloat();
196  break;
197  };
198 
199  _num->copy(*(tmp_num._num));
200 
201  return *this;
202 }
203 
204 KNumber & KNumber::operator -=(KNumber const &arg)
205 {
206  KNumber tmp_num = *this - arg;
207 
208  delete _num;
209 
210  switch(tmp_num.type()) {
211  case SpecialType:
212  _num = new _knumerror();
213  break;
214  case IntegerType:
215  _num = new _knuminteger();
216  break;
217  case FractionType:
218  _num = new _knumfraction();
219  break;
220  case FloatType:
221  _num = new _knumfloat();
222  break;
223  };
224 
225  _num->copy(*(tmp_num._num));
226 
227  return *this;
228 }
229 
230 // increase the digit at 'position' by one
231 static void _inc_by_one(TQString &str, int position)
232 {
233  for (int i = position; i >= 0; i--)
234  {
235  char last_char = str[i].latin1();
236  switch(last_char)
237  {
238  case '0':
239  str[i] = '1';
240  break;
241  case '1':
242  str[i] = '2';
243  break;
244  case '2':
245  str[i] = '3';
246  break;
247  case '3':
248  str[i] = '4';
249  break;
250  case '4':
251  str[i] = '5';
252  break;
253  case '5':
254  str[i] = '6';
255  break;
256  case '6':
257  str[i] = '7';
258  break;
259  case '7':
260  str[i] = '8';
261  break;
262  case '8':
263  str[i] = '9';
264  break;
265  case '9':
266  str[i] = '0';
267  if (i == 0) str.prepend('1');
268  continue;
269  case '.':
270  continue;
271  }
272  break;
273  }
274 }
275 
276 // Cut off if more digits in fractional part than 'precision'
277 static void _round(TQString &str, int precision)
278 {
279  int decimalSymbolPos = str.find('.');
280 
281  if (decimalSymbolPos == -1)
282  if (precision == 0) return;
283  else if (precision > 0) // add dot if missing (and needed)
284  {
285  str.append('.');
286  decimalSymbolPos = str.length() - 1;
287  }
288 
289  // fill up with more than enough zeroes (in case fractional part too short)
290  str.append(TQString().fill('0', precision));
291 
292  // Now decide whether to round up or down
293  char last_char = str[decimalSymbolPos + precision + 1].latin1();
294  switch (last_char)
295  {
296  case '0':
297  case '1':
298  case '2':
299  case '3':
300  case '4':
301  // nothing to do, rounding down
302  break;
303  case '5':
304  case '6':
305  case '7':
306  case '8':
307  case '9':
308  // rounding up
309  _inc_by_one(str, decimalSymbolPos + precision);
310  break;
311  default:
312  break;
313  }
314 
315  decimalSymbolPos = str.find('.');
316  str.truncate(decimalSymbolPos + precision + 1);
317 
318  // if precision == 0 delete also '.'
319  if (precision == 0) str = str.section('.', 0, 0);
320 }
321 
322 static TQString roundNumber(const TQString &numStr, int precision)
323 {
324  TQString tmpString = numStr;
325  if (precision < 0 ||
326  ! TQRegExp("^[+-]?\\d+(\\.\\d+)*(e[+-]?\\d+)?$").exactMatch(tmpString))
327  return numStr;
328 
329 
330  // Skip the sign (for now)
331  bool neg = (tmpString[0] == '-');
332  if (neg || tmpString[0] == '+') tmpString.remove(0, 1);
333 
334 
335  // Split off exponential part (including 'e'-symbol)
336  TQString mantString = tmpString.section('e', 0, 0,
337  TQString::SectionCaseInsensitiveSeps);
338  TQString expString = tmpString.section('e', 1, 1,
339  TQString::SectionCaseInsensitiveSeps |
340  TQString::SectionIncludeLeadingSep);
341  if (expString.length() == 1) expString = TQString();
342 
343 
344  _round(mantString, precision);
345 
346  if(neg) mantString.prepend('-');
347 
348  return mantString + expString;
349 }
350 
351 
352 TQString const KNumber::toTQString(int width, int prec) const
353 {
354  TQString tmp_str;
355 
356  if (*this == Zero) // important to avoid infinite loops below
357  return "0";
358  switch (type()) {
359  case IntegerType:
360  if (width > 0) { //result needs to be cut-off
361  bool tmp_bool = _fraction_input; // stupid work-around
362  _fraction_input = false;
363  tmp_str = (KNumber("1.0")*(*this)).toTQString(width, -1);
364  _fraction_input = tmp_bool;
365  } else
366  tmp_str = TQString(_num->ascii());
367  break;
368  case FractionType:
369  if (_float_output) {
370  bool tmp_bool = _fraction_input; // stupid work-around
371  _fraction_input = false;
372  tmp_str = (KNumber("1.0")*(*this)).toTQString(width, -1);
373  _fraction_input = tmp_bool;
374  } else { // _float_output == false
375  if(_splitoffinteger_output) {
376  // split off integer part
377  KNumber int_part = this->integerPart();
378  if (int_part == Zero)
379  tmp_str = TQString(_num->ascii());
380  else if (int_part < Zero)
381  tmp_str = int_part.toTQString() + " " + (int_part - *this)._num->ascii();
382  else
383  tmp_str = int_part.toTQString() + " " + (*this - int_part)._num->ascii();
384  } else
385  tmp_str = TQString(_num->ascii());
386 
387  if (width > 0 && tmp_str.length() > width) {
388  //result needs to be cut-off
389  bool tmp_bool = _fraction_input; // stupid work-around
390  _fraction_input = false;
391  tmp_str = (KNumber("1.0")*(*this)).toTQString(width, -1);
392  _fraction_input = tmp_bool;
393  }
394  }
395 
396  break;
397  case FloatType:
398  if (width > 0)
399  tmp_str = TQString(_num->ascii(width));
400  else
401  // rough estimate for maximal decimal precision (10^3 = 2^10)
402  tmp_str = TQString(_num->ascii(3*mpf_get_default_prec()/10));
403  break;
404  default:
405  return TQString(_num->ascii());
406  }
407 
408  if (prec >= 0)
409  return roundNumber(tmp_str, prec);
410  else
411  return tmp_str;
412 }
413 
414 void KNumber::setDefaultFloatOutput(bool flag)
415 {
416  _float_output = flag;
417 }
418 
419 void KNumber::setDefaultFractionalInput(bool flag)
420 {
421  _fraction_input = flag;
422 }
423 
424 void KNumber::setSplitoffIntegerForFractionOutput(bool flag)
425 {
426  _splitoffinteger_output = flag;
427 }
428 
429 void KNumber::setDefaultFloatPrecision(unsigned int prec)
430 {
431  // Need to transform decimal digits into binary digits
432  unsigned long int bin_prec = static_cast<unsigned long int>
433  (double(prec) * M_LN10 / M_LN2 + 1);
434 
435  mpf_set_default_prec(bin_prec);
436 }
437 
438 KNumber const KNumber::abs(void) const
439 {
440  KNumber tmp_num;
441  delete tmp_num._num;
442 
443  tmp_num._num = _num->abs();
444 
445  return tmp_num;
446 }
447 
448 KNumber const KNumber::cbrt(void) const
449 {
450  KNumber tmp_num;
451  delete tmp_num._num;
452 
453  tmp_num._num = _num->cbrt();
454 
455  return tmp_num;
456 }
457 
458 KNumber const KNumber::sqrt(void) const
459 {
460  KNumber tmp_num;
461  delete tmp_num._num;
462 
463  tmp_num._num = _num->sqrt();
464 
465  return tmp_num;
466 }
467 
468 KNumber const KNumber::integerPart(void) const
469 {
470  KNumber tmp_num;
471  delete tmp_num._num;
472  tmp_num._num = _num->intPart();
473 
474  return tmp_num;
475 }
476 
477 KNumber const KNumber::power(KNumber const &exp) const
478 {
479  if (*this == Zero) {
480  if(exp == Zero)
481  return KNumber("nan"); // 0^0 not defined
482  else if (exp < Zero)
483  return KNumber("inf");
484  else
485  return KNumber(0);
486  }
487 
488  if (exp == Zero) {
489  if (*this != Zero)
490  return One;
491  else
492  return KNumber("nan");
493  }
494  else if (exp < Zero) {
495  KNumber tmp_num;
496  KNumber tmp_num2 = -exp;
497  delete tmp_num._num;
498  tmp_num._num = _num->power(*(tmp_num2._num));
499 
500  return One/tmp_num;
501  }
502  else {
503  KNumber tmp_num;
504  delete tmp_num._num;
505  tmp_num._num = _num->power(*(exp._num));
506 
507  return tmp_num;
508  }
509 
510 }
511 
512 KNumber const KNumber::operator-(void) const
513 {
514  KNumber tmp_num;
515  delete tmp_num._num;
516 
517  tmp_num._num = _num->change_sign();
518 
519  return tmp_num;
520 }
521 
522 KNumber const KNumber::operator+(KNumber const & arg2) const
523 {
524  KNumber tmp_num;
525  delete tmp_num._num;
526 
527  tmp_num._num = _num->add(*arg2._num);
528 
529  tmp_num.simplifyRational();
530 
531  return tmp_num;
532 }
533 
534 KNumber const KNumber::operator-(KNumber const & arg2) const
535 {
536  return *this + (-arg2);
537 }
538 
539 KNumber const KNumber::operator*(KNumber const & arg2) const
540 {
541  KNumber tmp_num;
542  delete tmp_num._num;
543 
544  tmp_num._num = _num->multiply(*arg2._num);
545 
546  tmp_num.simplifyRational();
547 
548  return tmp_num;
549 }
550 
551 KNumber const KNumber::operator/(KNumber const & arg2) const
552 {
553  KNumber tmp_num;
554  delete tmp_num._num;
555 
556  tmp_num._num = _num->divide(*arg2._num);
557 
558  tmp_num.simplifyRational();
559 
560  return tmp_num;
561 }
562 
563 
564 KNumber const KNumber::operator%(KNumber const & arg2) const
565 {
566  if (type() != IntegerType || arg2.type() != IntegerType)
567  return Zero;
568 
569  KNumber tmp_num;
570  delete tmp_num._num;
571 
572  _knuminteger const *tmp_arg1 = dynamic_cast<_knuminteger const *>(_num);
573  _knuminteger const *tmp_arg2 = dynamic_cast<_knuminteger const *>(arg2._num);
574 
575  tmp_num._num = tmp_arg1->mod(*tmp_arg2);
576 
577  return tmp_num;
578 }
579 
580 KNumber const KNumber::operator&(KNumber const & arg2) const
581 {
582  if (type() != IntegerType || arg2.type() != IntegerType)
583  return Zero;
584 
585  KNumber tmp_num;
586  delete tmp_num._num;
587 
588  _knuminteger const *tmp_arg1 = dynamic_cast<_knuminteger const *>(_num);
589  _knuminteger const *tmp_arg2 = dynamic_cast<_knuminteger const *>(arg2._num);
590 
591  tmp_num._num = tmp_arg1->intAnd(*tmp_arg2);
592 
593  return tmp_num;
594 
595 }
596 
597 KNumber const KNumber::operator|(KNumber const & arg2) const
598 {
599  if (type() != IntegerType || arg2.type() != IntegerType)
600  return Zero;
601 
602  KNumber tmp_num;
603  delete tmp_num._num;
604 
605  _knuminteger const *tmp_arg1 = dynamic_cast<_knuminteger const *>(_num);
606  _knuminteger const *tmp_arg2 = dynamic_cast<_knuminteger const *>(arg2._num);
607 
608  tmp_num._num = tmp_arg1->intOr(*tmp_arg2);
609 
610  return tmp_num;
611 }
612 
613 
614 KNumber const KNumber::operator<<(KNumber const & arg2) const
615 {
616  if (type() != IntegerType || arg2.type() != IntegerType)
617  return KNumber("nan");
618 
619  _knuminteger const *tmp_arg1 = dynamic_cast<_knuminteger const *>(_num);
620  _knuminteger const *tmp_arg2 = dynamic_cast<_knuminteger const *>(arg2._num);
621 
622  KNumber tmp_num;
623  delete tmp_num._num;
624  tmp_num._num = tmp_arg1->shift(*tmp_arg2);
625 
626  return tmp_num;
627 }
628 
629 KNumber const KNumber::operator>>(KNumber const & arg2) const
630 {
631  if (type() != IntegerType || arg2.type() != IntegerType)
632  return KNumber("nan");
633 
634  KNumber tmp_num = -arg2;
635 
636  _knuminteger const *tmp_arg1 = dynamic_cast<_knuminteger const *>(_num);
637  _knuminteger const *tmp_arg2 = dynamic_cast<_knuminteger const *>(tmp_num._num);
638 
639  KNumber tmp_num2;
640  delete tmp_num2._num;
641  tmp_num2._num = tmp_arg1->shift(*tmp_arg2);
642 
643  return tmp_num2;
644 }
645 
646 
647 
648 KNumber::operator bool(void) const
649 {
650  if (*this == Zero)
651  return false;
652  return true;
653 }
654 
655 KNumber::operator signed long int(void) const
656 {
657  return static_cast<signed long int>(*_num);
658 }
659 
660 KNumber::operator unsigned long int(void) const
661 {
662  return static_cast<unsigned long int>(*_num);
663 }
664 
665 KNumber::operator unsigned long long int(void) const
666 {
667 #if SIZEOF_UNSIGNED_LONG == 8
668  return static_cast<unsigned long int>(*this);
669 #elif SIZEOF_UNSIGNED_LONG == 4
670  KNumber tmp_num1 = this->abs().integerPart();
671  unsigned long long int tmp_num2 = static_cast<unsigned long int>(tmp_num1) +
672  (static_cast<unsigned long long int>(
673  static_cast<unsigned long int>(tmp_num1 >> KNumber("32"))) << 32) ;
674 
675 #warning the cast operator from KNumber to unsigned long long int is probably buggy, when a sign is involved
676  if (*this > KNumber(0))
677  return tmp_num2;
678  else
679  return static_cast<unsigned long long int> (- static_cast<signed long long int>(tmp_num2));
680 #else
681 #error "SIZEOF_UNSIGNED_LONG is a unhandled case"
682 #endif
683 }
684 
685 KNumber::operator double(void) const
686 {
687  return static_cast<double>(*_num);
688 }
689 
690 int const KNumber::compare(KNumber const & arg2) const
691 {
692  return _num->compare(*arg2._num);
693 }

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.8.1.2
This website is maintained by Timothy Pearson.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. |