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

kcalc/knumber

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

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.9.4
This website is maintained by Timothy Pearson.