summaryrefslogtreecommitdiffstats
path: root/kcalc/knumber
diff options
context:
space:
mode:
Diffstat (limited to 'kcalc/knumber')
-rw-r--r--kcalc/knumber/Makefile.am16
-rw-r--r--kcalc/knumber/configure.in.in73
-rw-r--r--kcalc/knumber/knumber.cpp693
-rw-r--r--kcalc/knumber/knumber.h289
-rw-r--r--kcalc/knumber/knumber_priv.cpp1083
-rw-r--r--kcalc/knumber/knumber_priv.h313
-rw-r--r--kcalc/knumber/tests/Makefile.am32
-rw-r--r--kcalc/knumber/tests/knumbertest.cpp582
-rw-r--r--kcalc/knumber/tests/knumbertest.h9
9 files changed, 3090 insertions, 0 deletions
diff --git a/kcalc/knumber/Makefile.am b/kcalc/knumber/Makefile.am
new file mode 100644
index 0000000..6e5673b
--- /dev/null
+++ b/kcalc/knumber/Makefile.am
@@ -0,0 +1,16 @@
+AM_CPPFLAGS=-D_GNU_SOURCE -D_ISOC99_SOURCE $(all_includes)
+
+SUBDIRS = tests
+
+bin_PROGRAMS =
+lib_LTLIBRARIES =
+noinst_LTLIBRARIES = libknumber.la
+
+libknumber_la_SOURCES = knumber.cpp knumber_priv.cpp
+libknumber_la_LIBADD = $(LIBGMP) -lm
+
+METASOURCES = AUTO
+
+noinst_HEADERS = knumber.h knumber_priv.h
+
+include ../../admin/Doxyfile.am
diff --git a/kcalc/knumber/configure.in.in b/kcalc/knumber/configure.in.in
new file mode 100644
index 0000000..8ef670b
--- /dev/null
+++ b/kcalc/knumber/configure.in.in
@@ -0,0 +1,73 @@
+AC_DEFUN([KDE_C_LONG_DOUBLE],
+[
+ AC_CACHE_CHECK(for long double, ac_cv_c_long_double,
+ [
+ ac_save_LIBS="$LIBS"
+ LIBS="-lm $LIBS"
+ AC_TRY_RUN(
+ [
+#define _ISOC99_SOURCE 1
+#define _GNU_SOURCE 1
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+int main() {
+/* The Stardent Vistra knows sizeof(long double), but does not support it. */
+long double foo = 1.0;
+char buffer[10];
+/* On Ultrix 4.3 cc, long double is 4 and double is 8. */
+int result = (sizeof(long double) <= sizeof(double));
+/* the following is needed for a broken printf in glibc2 */
+if (!result) {
+ foo = foo * 3;
+ sprintf(buffer,"%0.0Lf",foo);
+ result = strcmp(buffer, "3");
+/* and now something mean ;-) */
+ foo = powl(fabsl(foo), 1);
+}
+exit(result); }
+ ],
+ ac_cv_c_long_double=yes, ac_cv_c_long_double=no,
+ ac_cv_c_long_double=no
+ )
+ LIBS="$ac_save_LIBS"
+ ])
+ if test $ac_cv_c_long_double = yes; then
+ AC_DEFINE(HAVE_LONG_DOUBLE, 1, [Define if you have support for long double in printf])
+ fi
+])
+KDE_C_LONG_DOUBLE
+
+have_l_funcs=yes
+AC_CHECK_LIB(m, sqrtl,,have_l_funcs=no)
+
+if test "xyes" = "x$have_l_funcs" ; then
+ AC_DEFINE(HAVE_L_FUNCS,1,[Define if you have *l math functions (absl, ...)])
+fi
+
+LIBGMP=
+KDE_CHECK_HEADER([gmp.h], [
+ AC_LANG_SAVE
+ AC_LANG_CPLUSPLUS
+
+ kde_save_LIBS=$LIBS
+ LIBS="$all_libraries -lgmp"
+ AC_TRY_LINK(dnl
+ [
+ #include <gmp.h>
+ ],
+ [
+ mpz_t _mpz;
+ mpz_init_set_si(_mpz, 0);
+ ],
+ [LIBGMP="-lgmp"],
+ [
+ DO_NOT_COMPILE="$DO_NOT_COMPILE kcalc"
+ ])
+ LIBS=$kde_save_LIBS
+ AC_LANG_RESTORE
+
+])
+AC_SUBST(LIBGMP)
diff --git a/kcalc/knumber/knumber.cpp b/kcalc/knumber/knumber.cpp
new file mode 100644
index 0000000..d282b26
--- /dev/null
+++ b/kcalc/knumber/knumber.cpp
@@ -0,0 +1,693 @@
+// -*- c-basic-offset: 2 -*-
+/* This file is part of the KDE libraries
+ Copyright (c) 2005 Klaus Niederkrueger <kniederk@math.uni-koeln.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <math.h>
+
+#include <config.h>
+
+#include <qregexp.h>
+#include <qstring.h>
+
+#include "knumber.h"
+
+KNumber const KNumber::Zero(0);
+KNumber const KNumber::One(1);
+KNumber const KNumber::MinusOne(-1);
+KNumber const KNumber::Pi("3.141592653589793238462643383279502884197169"
+ "39937510582097494459230781640628620899862803"
+ "4825342117068");
+KNumber const KNumber::Euler("2.718281828459045235360287471352662497757"
+ "24709369995957496696762772407663035354759"
+ "4571382178525166427");
+KNumber const KNumber::NotDefined("nan");
+
+bool KNumber::_float_output = false;
+bool KNumber::_fraction_input = false;
+bool KNumber::_splitoffinteger_output = false;
+
+KNumber::KNumber(signed int num)
+{
+ _num = new _knuminteger(num);
+}
+
+KNumber::KNumber(unsigned int num)
+{
+ _num = new _knuminteger(num);
+}
+
+KNumber::KNumber(signed long int num)
+{
+ _num = new _knuminteger(num);
+}
+
+KNumber::KNumber(unsigned long int num)
+{
+ _num = new _knuminteger(num);
+}
+
+KNumber::KNumber(unsigned long long int num)
+{
+ _num = new _knuminteger(num);
+}
+
+KNumber::KNumber(double num)
+{
+ if ( isinf(num) ) _num = new _knumerror( _knumber::Infinity );
+ else if ( isnan(num) ) _num = new _knumerror( _knumber::UndefinedNumber );
+ else _num = new _knumfloat(num);
+
+}
+
+KNumber::KNumber(KNumber const & num)
+{
+ switch(num.type()) {
+ case SpecialType:
+ _num = new _knumerror(*(num._num));
+ return;
+ case IntegerType:
+ _num = new _knuminteger(*(num._num));
+ return;
+ case FractionType:
+ _num = new _knumfraction(*(num._num));
+ return;
+ case FloatType:
+ _num = new _knumfloat(*(num._num));
+ return;
+ };
+}
+
+
+KNumber::KNumber(QString const & num)
+{
+ if (QRegExp("^(inf|-inf|nan)$").exactMatch(num))
+ _num = new _knumerror(num);
+ else if (QRegExp("^[+-]?\\d+$").exactMatch(num))
+ _num = new _knuminteger(num);
+ else if (QRegExp("^[+-]?\\d+/\\d+$").exactMatch(num)) {
+ _num = new _knumfraction(num);
+ simplifyRational();
+ }
+ else if (QRegExp("^[+-]?\\d+(\\.\\d*)?(e[+-]?\\d+)?$").exactMatch(num))
+ if (_fraction_input == true) {
+ _num = new _knumfraction(num);
+ simplifyRational();
+ } else
+ _num = new _knumfloat(num);
+ else
+ _num = new _knumerror("nan");
+}
+
+KNumber::NumType KNumber::type(void) const
+{
+ if(dynamic_cast<_knumerror *>(_num))
+ return SpecialType;
+ if(dynamic_cast<_knuminteger *>(_num))
+ return IntegerType;
+ if(dynamic_cast<_knumfraction *>(_num))
+ return FractionType;
+ if(dynamic_cast<_knumfloat *>(_num))
+ return FloatType;
+
+ return SpecialType;
+}
+
+// This method converts a fraction to an integer, whenever possible,
+// i.e. 5/1 --> 5
+// This method should be called, whenever such a inproper fraction can occur,
+// e.g. when adding 4/3 + 2/3....
+void KNumber::simplifyRational(void)
+{
+ if (type() != FractionType)
+ return;
+
+ _knumfraction *tmp_num = dynamic_cast<_knumfraction *>(_num);
+
+ if (tmp_num->isInteger()) {
+ _knumber *tmp_num2 = tmp_num->intPart();
+ delete tmp_num;
+ _num = tmp_num2;
+ }
+
+}
+
+
+KNumber const & KNumber::operator=(KNumber const & num)
+{
+ if (this == & num)
+ return *this;
+
+ delete _num;
+
+ switch(num.type()) {
+ case SpecialType:
+ _num = new _knumerror();
+ break;
+ case IntegerType:
+ _num = new _knuminteger();
+ break;
+ case FractionType:
+ _num = new _knumfraction();
+ break;
+ case FloatType:
+ _num = new _knumfloat();
+ break;
+ };
+
+ _num->copy(*(num._num));
+
+ return *this;
+}
+
+KNumber & KNumber::operator +=(KNumber const &arg)
+{
+ KNumber tmp_num = *this + arg;
+
+ delete _num;
+
+ switch(tmp_num.type()) {
+ case SpecialType:
+ _num = new _knumerror();
+ break;
+ case IntegerType:
+ _num = new _knuminteger();
+ break;
+ case FractionType:
+ _num = new _knumfraction();
+ break;
+ case FloatType:
+ _num = new _knumfloat();
+ break;
+ };
+
+ _num->copy(*(tmp_num._num));
+
+ return *this;
+}
+
+KNumber & KNumber::operator -=(KNumber const &arg)
+{
+ KNumber tmp_num = *this - arg;
+
+ delete _num;
+
+ switch(tmp_num.type()) {
+ case SpecialType:
+ _num = new _knumerror();
+ break;
+ case IntegerType:
+ _num = new _knuminteger();
+ break;
+ case FractionType:
+ _num = new _knumfraction();
+ break;
+ case FloatType:
+ _num = new _knumfloat();
+ break;
+ };
+
+ _num->copy(*(tmp_num._num));
+
+ return *this;
+}
+
+// increase the digit at 'position' by one
+static void _inc_by_one(QString &str, int position)
+{
+ for (int i = position; i >= 0; i--)
+ {
+ char last_char = str[i].latin1();
+ switch(last_char)
+ {
+ case '0':
+ str[i] = '1';
+ break;
+ case '1':
+ str[i] = '2';
+ break;
+ case '2':
+ str[i] = '3';
+ break;
+ case '3':
+ str[i] = '4';
+ break;
+ case '4':
+ str[i] = '5';
+ break;
+ case '5':
+ str[i] = '6';
+ break;
+ case '6':
+ str[i] = '7';
+ break;
+ case '7':
+ str[i] = '8';
+ break;
+ case '8':
+ str[i] = '9';
+ break;
+ case '9':
+ str[i] = '0';
+ if (i == 0) str.prepend('1');
+ continue;
+ case '.':
+ continue;
+ }
+ break;
+ }
+}
+
+// Cut off if more digits in fractional part than 'precision'
+static void _round(QString &str, int precision)
+{
+ int decimalSymbolPos = str.find('.');
+
+ if (decimalSymbolPos == -1)
+ if (precision == 0) return;
+ else if (precision > 0) // add dot if missing (and needed)
+ {
+ str.append('.');
+ decimalSymbolPos = str.length() - 1;
+ }
+
+ // fill up with more than enough zeroes (in case fractional part too short)
+ str.append(QString().fill('0', precision));
+
+ // Now decide whether to round up or down
+ char last_char = str[decimalSymbolPos + precision + 1].latin1();
+ switch (last_char)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ // nothing to do, rounding down
+ break;
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ // rounding up
+ _inc_by_one(str, decimalSymbolPos + precision);
+ break;
+ default:
+ break;
+ }
+
+ decimalSymbolPos = str.find('.');
+ str.truncate(decimalSymbolPos + precision + 1);
+
+ // if precision == 0 delete also '.'
+ if (precision == 0) str = str.section('.', 0, 0);
+}
+
+static QString roundNumber(const QString &numStr, int precision)
+{
+ QString tmpString = numStr;
+ if (precision < 0 ||
+ ! QRegExp("^[+-]?\\d+(\\.\\d+)*(e[+-]?\\d+)?$").exactMatch(tmpString))
+ return numStr;
+
+
+ // Skip the sign (for now)
+ bool neg = (tmpString[0] == '-');
+ if (neg || tmpString[0] == '+') tmpString.remove(0, 1);
+
+
+ // Split off exponential part (including 'e'-symbol)
+ QString mantString = tmpString.section('e', 0, 0,
+ QString::SectionCaseInsensitiveSeps);
+ QString expString = tmpString.section('e', 1, 1,
+ QString::SectionCaseInsensitiveSeps |
+ QString::SectionIncludeLeadingSep);
+ if (expString.length() == 1) expString = QString();
+
+
+ _round(mantString, precision);
+
+ if(neg) mantString.prepend('-');
+
+ return mantString + expString;
+}
+
+
+QString const KNumber::toQString(int width, int prec) const
+{
+ QString tmp_str;
+
+ if (*this == Zero) // important to avoid infinite loops below
+ return "0";
+ switch (type()) {
+ case IntegerType:
+ if (width > 0) { //result needs to be cut-off
+ bool tmp_bool = _fraction_input; // stupid work-around
+ _fraction_input = false;
+ tmp_str = (KNumber("1.0")*(*this)).toQString(width, -1);
+ _fraction_input = tmp_bool;
+ } else
+ tmp_str = QString(_num->ascii());
+ break;
+ case FractionType:
+ if (_float_output) {
+ bool tmp_bool = _fraction_input; // stupid work-around
+ _fraction_input = false;
+ tmp_str = (KNumber("1.0")*(*this)).toQString(width, -1);
+ _fraction_input = tmp_bool;
+ } else { // _float_output == false
+ if(_splitoffinteger_output) {
+ // split off integer part
+ KNumber int_part = this->integerPart();
+ if (int_part == Zero)
+ tmp_str = QString(_num->ascii());
+ else if (int_part < Zero)
+ tmp_str = int_part.toQString() + " " + (int_part - *this)._num->ascii();
+ else
+ tmp_str = int_part.toQString() + " " + (*this - int_part)._num->ascii();
+ } else
+ tmp_str = QString(_num->ascii());
+
+ if (width > 0 && tmp_str.length() > width) {
+ //result needs to be cut-off
+ bool tmp_bool = _fraction_input; // stupid work-around
+ _fraction_input = false;
+ tmp_str = (KNumber("1.0")*(*this)).toQString(width, -1);
+ _fraction_input = tmp_bool;
+ }
+ }
+
+ break;
+ case FloatType:
+ if (width > 0)
+ tmp_str = QString(_num->ascii(width));
+ else
+ // rough estimate for maximal decimal precision (10^3 = 2^10)
+ tmp_str = QString(_num->ascii(3*mpf_get_default_prec()/10));
+ break;
+ default:
+ return QString(_num->ascii());
+ }
+
+ if (prec >= 0)
+ return roundNumber(tmp_str, prec);
+ else
+ return tmp_str;
+}
+
+void KNumber::setDefaultFloatOutput(bool flag)
+{
+ _float_output = flag;
+}
+
+void KNumber::setDefaultFractionalInput(bool flag)
+{
+ _fraction_input = flag;
+}
+
+void KNumber::setSplitoffIntegerForFractionOutput(bool flag)
+{
+ _splitoffinteger_output = flag;
+}
+
+void KNumber::setDefaultFloatPrecision(unsigned int prec)
+{
+ // Need to transform decimal digits into binary digits
+ unsigned long int bin_prec = static_cast<unsigned long int>
+ (double(prec) * M_LN10 / M_LN2 + 1);
+
+ mpf_set_default_prec(bin_prec);
+}
+
+KNumber const KNumber::abs(void) const
+{
+ KNumber tmp_num;
+ delete tmp_num._num;
+
+ tmp_num._num = _num->abs();
+
+ return tmp_num;
+}
+
+KNumber const KNumber::cbrt(void) const
+{
+ KNumber tmp_num;
+ delete tmp_num._num;
+
+ tmp_num._num = _num->cbrt();
+
+ return tmp_num;
+}
+
+KNumber const KNumber::sqrt(void) const
+{
+ KNumber tmp_num;
+ delete tmp_num._num;
+
+ tmp_num._num = _num->sqrt();
+
+ return tmp_num;
+}
+
+KNumber const KNumber::integerPart(void) const
+{
+ KNumber tmp_num;
+ delete tmp_num._num;
+ tmp_num._num = _num->intPart();
+
+ return tmp_num;
+}
+
+KNumber const KNumber::power(KNumber const &exp) const
+{
+ if (*this == Zero) {
+ if(exp == Zero)
+ return KNumber("nan"); // 0^0 not defined
+ else if (exp < Zero)
+ return KNumber("inf");
+ else
+ return KNumber(0);
+ }
+
+ if (exp == Zero) {
+ if (*this != Zero)
+ return One;
+ else
+ return KNumber("nan");
+ }
+ else if (exp < Zero) {
+ KNumber tmp_num;
+ KNumber tmp_num2 = -exp;
+ delete tmp_num._num;
+ tmp_num._num = _num->power(*(tmp_num2._num));
+
+ return One/tmp_num;
+ }
+ else {
+ KNumber tmp_num;
+ delete tmp_num._num;
+ tmp_num._num = _num->power(*(exp._num));
+
+ return tmp_num;
+ }
+
+}
+
+KNumber const KNumber::operator-(void) const
+{
+ KNumber tmp_num;
+ delete tmp_num._num;
+
+ tmp_num._num = _num->change_sign();
+
+ return tmp_num;
+}
+
+KNumber const KNumber::operator+(KNumber const & arg2) const
+{
+ KNumber tmp_num;
+ delete tmp_num._num;
+
+ tmp_num._num = _num->add(*arg2._num);
+
+ tmp_num.simplifyRational();
+
+ return tmp_num;
+}
+
+KNumber const KNumber::operator-(KNumber const & arg2) const
+{
+ return *this + (-arg2);
+}
+
+KNumber const KNumber::operator*(KNumber const & arg2) const
+{
+ KNumber tmp_num;
+ delete tmp_num._num;
+
+ tmp_num._num = _num->multiply(*arg2._num);
+
+ tmp_num.simplifyRational();
+
+ return tmp_num;
+}
+
+KNumber const KNumber::operator/(KNumber const & arg2) const
+{
+ KNumber tmp_num;
+ delete tmp_num._num;
+
+ tmp_num._num = _num->divide(*arg2._num);
+
+ tmp_num.simplifyRational();
+
+ return tmp_num;
+}
+
+
+KNumber const KNumber::operator%(KNumber const & arg2) const
+{
+ if (type() != IntegerType || arg2.type() != IntegerType)
+ return Zero;
+
+ KNumber tmp_num;
+ delete tmp_num._num;
+
+ _knuminteger const *tmp_arg1 = dynamic_cast<_knuminteger const *>(_num);
+ _knuminteger const *tmp_arg2 = dynamic_cast<_knuminteger const *>(arg2._num);
+
+ tmp_num._num = tmp_arg1->mod(*tmp_arg2);
+
+ return tmp_num;
+}
+
+KNumber const KNumber::operator&(KNumber const & arg2) const
+{
+ if (type() != IntegerType || arg2.type() != IntegerType)
+ return Zero;
+
+ KNumber tmp_num;
+ delete tmp_num._num;
+
+ _knuminteger const *tmp_arg1 = dynamic_cast<_knuminteger const *>(_num);
+ _knuminteger const *tmp_arg2 = dynamic_cast<_knuminteger const *>(arg2._num);
+
+ tmp_num._num = tmp_arg1->intAnd(*tmp_arg2);
+
+ return tmp_num;
+
+}
+
+KNumber const KNumber::operator|(KNumber const & arg2) const
+{
+ if (type() != IntegerType || arg2.type() != IntegerType)
+ return Zero;
+
+ KNumber tmp_num;
+ delete tmp_num._num;
+
+ _knuminteger const *tmp_arg1 = dynamic_cast<_knuminteger const *>(_num);
+ _knuminteger const *tmp_arg2 = dynamic_cast<_knuminteger const *>(arg2._num);
+
+ tmp_num._num = tmp_arg1->intOr(*tmp_arg2);
+
+ return tmp_num;
+}
+
+
+KNumber const KNumber::operator<<(KNumber const & arg2) const
+{
+ if (type() != IntegerType || arg2.type() != IntegerType)
+ return KNumber("nan");
+
+ _knuminteger const *tmp_arg1 = dynamic_cast<_knuminteger const *>(_num);
+ _knuminteger const *tmp_arg2 = dynamic_cast<_knuminteger const *>(arg2._num);
+
+ KNumber tmp_num;
+ delete tmp_num._num;
+ tmp_num._num = tmp_arg1->shift(*tmp_arg2);
+
+ return tmp_num;
+}
+
+KNumber const KNumber::operator>>(KNumber const & arg2) const
+{
+ if (type() != IntegerType || arg2.type() != IntegerType)
+ return KNumber("nan");
+
+ KNumber tmp_num = -arg2;
+
+ _knuminteger const *tmp_arg1 = dynamic_cast<_knuminteger const *>(_num);
+ _knuminteger const *tmp_arg2 = dynamic_cast<_knuminteger const *>(tmp_num._num);
+
+ KNumber tmp_num2;
+ delete tmp_num2._num;
+ tmp_num2._num = tmp_arg1->shift(*tmp_arg2);
+
+ return tmp_num2;
+}
+
+
+
+KNumber::operator bool(void) const
+{
+ if (*this == Zero)
+ return false;
+ return true;
+}
+
+KNumber::operator signed long int(void) const
+{
+ return static_cast<signed long int>(*_num);
+}
+
+KNumber::operator unsigned long int(void) const
+{
+ return static_cast<unsigned long int>(*_num);
+}
+
+KNumber::operator unsigned long long int(void) const
+{
+#if SIZEOF_UNSIGNED_LONG == 8
+ return static_cast<unsigned long int>(*this);
+#elif SIZEOF_UNSIGNED_LONG == 4
+ KNumber tmp_num1 = this->abs().integerPart();
+ unsigned long long int tmp_num2 = static_cast<unsigned long int>(tmp_num1) +
+ (static_cast<unsigned long long int>(
+ static_cast<unsigned long int>(tmp_num1 >> KNumber("32"))) << 32) ;
+
+#warning the cast operator from KNumber to unsigned long long int is probably buggy, when a sign is involved
+ if (*this > KNumber(0))
+ return tmp_num2;
+ else
+ return static_cast<unsigned long long int> (- static_cast<signed long long int>(tmp_num2));
+#else
+#error "SIZEOF_UNSIGNED_LONG is a unhandled case"
+#endif
+}
+
+KNumber::operator double(void) const
+{
+ return static_cast<double>(*_num);
+}
+
+int const KNumber::compare(KNumber const & arg2) const
+{
+ return _num->compare(*arg2._num);
+}
diff --git a/kcalc/knumber/knumber.h b/kcalc/knumber/knumber.h
new file mode 100644
index 0000000..489a579
--- /dev/null
+++ b/kcalc/knumber/knumber.h
@@ -0,0 +1,289 @@
+// -*- c-basic-offset: 2 -*-
+/* This file is part of the KDE libraries
+ Copyright (C) 2005 Klaus Niederkrueger <kniederk@math.uni-koeln.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#ifndef _KNUMBER_H
+#define _KNUMBER_H
+
+#include <kdelibs_export.h>
+
+#include "knumber_priv.h"
+
+class QString;
+
+/**
+ *
+ * @short Class that provides arbitrary precision numbers
+ *
+ * KNumber provides access to arbitrary precision numbers from within
+ * KDE.
+ *
+ * KNumber is based on the GMP (GNU Multiprecision) library and
+ * provides transparent support to integer, fractional and floating
+ * point number. It contains rudimentary error handling, and also
+ * includes methods for converting the numbers to QStrings for
+ * output, and to read QStrings to obtain a KNumber.
+ *
+ * The different types of numbers that can be represented by objects
+ * of this class will be described below:
+ *
+ * @li @p NumType::SpecialType - This type represents an error that
+ * has occurred, e.g. trying to divide 1 by 0 gives an object that
+ * represents infinity.
+ *
+ * @li @p NumType::IntegerType - The number is an integer. It can be
+ * arbitrarily large (restricted by the memory of the system).
+ *
+ * @li @p NumType::FractionType - A fraction is a number of the form
+ * denominator divided by nominator, where both denominator and
+ * nominator are integers of arbitrary size.
+ *
+ * @li @p NumType::FloatType - The number is of floating point
+ * type. These numbers are usually rounded, so that they do not
+ * represent precise values.
+ *
+ *
+ * @author Klaus Niederkrueger <kniederk@math.uni-koeln.de>
+ */
+class KDE_EXPORT KNumber
+{
+ public:
+ static KNumber const Zero;
+ static KNumber const One;
+ static KNumber const MinusOne;
+ static KNumber const Pi;
+ static KNumber const Euler;
+ static KNumber const NotDefined;
+
+ /**
+ * KNumber tries to provide transparent access to the following type
+ * of numbers:
+ *
+ * @li @p NumType::SpecialType - Some type of error has occurred,
+ * further inspection with @p KNumber::ErrorType
+ *
+ * @li @p NumType::IntegerType - the number is an integer
+ *
+ * @li @p NumType::FractionType - the number is a fraction
+ *
+ * @li @p NumType::FloatType - the number is of floating point type
+ *
+ */
+ enum NumType {SpecialType, IntegerType, FractionType, FloatType};
+
+ /**
+ * A KNumber that represents an error, i.e. that is of type @p
+ * NumType::SpecialType can further distinguished:
+ *
+ * @li @p ErrorType::UndefinedNumber - This is e.g. the result of
+ * taking the square root of a negative number or computing
+ * \f$ \infty - \infty \f$.
+ *
+ * @li @p ErrorType::Infinity - Such a number can be e.g. obtained
+ * by dividing 1 by 0. Some further calculations are still allowed,
+ * e.g. \f$ \infty + 5 \f$ still gives \f$\infty\f$.
+ *
+ * @li @p ErrorType::MinusInfinity - MinusInfinity behaves similarly
+ * to infinity above. It can be obtained by changing the sign of
+ * infinity.
+ *
+ */
+ enum ErrorType {UndefinedNumber, Infinity, MinusInfinity};
+
+ KNumber(signed int num = 0);
+ KNumber(unsigned int num);
+ KNumber(signed long int num);
+ KNumber(unsigned long int num);
+ KNumber(unsigned long long int num);
+
+ KNumber(double num);
+
+ KNumber(KNumber const & num);
+
+ KNumber(QString const & num);
+
+ ~KNumber()
+ {
+ delete _num;
+ }
+
+ KNumber const & operator=(KNumber const & num);
+
+ /**
+ * Returns the type of the number, as explained in @p KNumber::NumType.
+ */
+ NumType type(void) const;
+
+ /**
+ * Set whether the output of numbers (with KNumber::toQString)
+ * should happen as floating point numbers or not. This method has
+ * in fact only an effect on numbers of type @p
+ * NumType::FractionType, which can be either displayed as fractions
+ * or in decimal notation.
+ *
+ * The default behavior is not to display fractions in floating
+ * point notation.
+ */
+ static void setDefaultFloatOutput(bool flag);
+
+ /**
+ * Set whether a number constructed from a QString should be
+ * initialized as a fraction or as a float, e.g. "1.01" would be
+ * treated as 101/100, if this flag is set to true.
+ *
+ * The default setting is false.
+ */
+ static void setDefaultFractionalInput(bool flag);
+
+ /**
+ * Set the default precision to be *at least* @p prec (decimal)
+ * digits. All subsequent initialized floats will use at least this
+ * precision, but previously initialized variables are unaffected.
+ */
+ static void setDefaultFloatPrecision(unsigned int prec);
+
+ /**
+ * What a terrible method name!! When displaying a fraction, the
+ * default mode gives @p "nomin/denom". With this method one can
+ * choose to display a fraction as @p "integer nomin/denom".
+ *
+ * Examples: Default representation mode is 47/17, but if @p flag is
+ * @p true, then the result is 2 13/17.
+ */
+ static void setSplitoffIntegerForFractionOutput(bool flag);
+
+ /**
+ * Return a QString representing the KNumber.
+ *
+ * @param width This number specifies the maximal length of the
+ * output, before the method switches to exponential notation and
+ * does rounding. For negative numbers, this option is ignored.
+ *
+ * @param prec This parameter controls the number of digits
+ * following the decimal point. For negative numbers, this option
+ * is ignored.
+ *
+ */
+ QString const toQString(int width = -1, int prec = -1) const;
+
+ /**
+ * Compute the absolute value, i.e. @p x.abs() returns the value
+ *
+ * \f[ \left\{\begin{array}{cl} x, & x \ge 0 \\ -x, & x <
+ * 0\end{array}\right.\f]
+ * This method works for \f$ x = \infty \f$ and \f$ x = -\infty \f$.
+ */
+ KNumber const abs(void) const;
+
+ /**
+ * Compute the square root. If \f$ x < 0 \f$ (including \f$
+ * x=-\infty \f$), then @p x.sqrt() returns @p
+ * ErrorType::UndefinedNumber.
+ *
+ * If @p x is an integer or a fraction, then @p x.sqrt() tries to
+ * compute the exact square root. If the square root is not a
+ * fraction, then a float with the default precision is returned.
+ *
+ * This method works for \f$ x = \infty \f$ giving \f$ \infty \f$.
+ */
+ KNumber const sqrt(void) const;
+
+ /**
+ * Compute the cube root.
+ *
+ * If @p x is an integer or a fraction, then @p x.cbrt() tries to
+ * compute the exact cube root. If the cube root is not a fraction,
+ * then a float is returned, but
+ *
+ * WARNING: A float cube root is computed as a standard @p double
+ * that is later transformed back into a @p KNumber.
+ *
+ * This method works for \f$ x = \infty \f$ giving \f$ \infty \f$,
+ * and for \f$ x = -\infty \f$ giving \f$ -\infty \f$.
+ */
+ KNumber const cbrt(void) const;
+
+ /**
+ * Truncates a @p KNumber to its integer type returning a number of
+ * type @p NumType::IntegerType.
+ *
+ * If \f$ x = \pm\infty \f$, integerPart leaves the value unchanged,
+ * i.e. it returns \f$ \pm\infty \f$.
+ */
+ KNumber const integerPart(void) const;
+
+ KNumber const power(KNumber const &exp) const;
+
+ KNumber const operator+(KNumber const & arg2) const;
+ KNumber const operator -(void) const;
+ KNumber const operator-(KNumber const & arg2) const;
+ KNumber const operator*(KNumber const & arg2) const;
+ KNumber const operator/(KNumber const & arg2) const;
+ KNumber const operator%(KNumber const & arg2) const;
+
+ KNumber const operator&(KNumber const & arg2) const;
+ KNumber const operator|(KNumber const & arg2) const;
+ KNumber const operator<<(KNumber const & arg2) const;
+ KNumber const operator>>(KNumber const & arg2) const;
+
+ operator bool(void) const;
+ operator signed long int(void) const;
+ operator unsigned long int(void) const;
+ operator unsigned long long int(void) const;
+ operator double(void) const;
+
+ bool const operator==(KNumber const & arg2) const
+ { return (compare(arg2) == 0); }
+
+ bool const operator!=(KNumber const & arg2) const
+ { return (compare(arg2) != 0); }
+
+ bool const operator>(KNumber const & arg2) const
+ { return (compare(arg2) > 0); }
+
+ bool const operator<(KNumber const & arg2) const
+ { return (compare(arg2) < 0); }
+
+ bool const operator>=(KNumber const & arg2) const
+ { return (compare(arg2) >= 0); }
+
+ bool const operator<=(KNumber const & arg2) const
+ { return (compare(arg2) <= 0); }
+
+ KNumber & operator +=(KNumber const &arg);
+ KNumber & operator -=(KNumber const &arg);
+
+
+ //KNumber const toFloat(void) const;
+
+
+
+
+ private:
+ void simplifyRational(void);
+ int const compare(KNumber const & arg2) const;
+
+ _knumber *_num;
+ static bool _float_output;
+ static bool _fraction_input;
+ static bool _splitoffinteger_output;
+};
+
+
+
+#endif // _KNUMBER_H
diff --git a/kcalc/knumber/knumber_priv.cpp b/kcalc/knumber/knumber_priv.cpp
new file mode 100644
index 0000000..1326d44
--- /dev/null
+++ b/kcalc/knumber/knumber_priv.cpp
@@ -0,0 +1,1083 @@
+/* This file is part of the KDE libraries
+ Copyright (c) 2005 Klaus Niederkrueger <kniederk@math.uni-koeln.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <math.h>
+#include <config.h>
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <qregexp.h>
+#include <qstring.h>
+
+#include "knumber_priv.h"
+
+_knumerror::_knumerror(_knumber const & num)
+{
+ switch(num.type()) {
+ case SpecialType:
+ _error = dynamic_cast<_knumerror const &>(num)._error;
+ break;
+ case IntegerType:
+ case FractionType:
+ case FloatType:
+ // What should I do here?
+ break;
+ }
+}
+
+
+
+_knuminteger::_knuminteger(unsigned long long int num)
+{
+ mpz_init(_mpz);
+#if SIZEOF_UNSIGNED_LONG == 8
+ mpz_init_set_ui(_mpz, static_cast<unsigned long int>(num));
+#elif SIZEOF_UNSIGNED_LONG == 4
+ mpz_set_ui(_mpz, static_cast<unsigned long int>(num >> 32));
+ mpz_mul_2exp(_mpz, _mpz, 32);
+ mpz_add_ui(_mpz, _mpz, static_cast<unsigned long int>(num));
+#else
+#error "SIZEOF_UNSIGNED_LONG is a unhandled case"
+#endif
+}
+
+
+_knuminteger::_knuminteger(_knumber const & num)
+{
+ mpz_init(_mpz);
+
+ switch(num.type()) {
+ case IntegerType:
+ mpz_set(_mpz, dynamic_cast<_knuminteger const &>(num)._mpz);
+ break;
+ case FractionType:
+ case FloatType:
+ case SpecialType:
+ // What should I do here?
+ break;
+ }
+}
+
+_knumfraction::_knumfraction(_knumber const & num)
+{
+ mpq_init(_mpq);
+
+ switch(num.type()) {
+ case IntegerType:
+ mpq_set_z(_mpq, dynamic_cast<_knuminteger const &>(num)._mpz);
+ break;
+ case FractionType:
+ mpq_set(_mpq, dynamic_cast<_knumfraction const &>(num)._mpq);
+ break;
+ case FloatType:
+ case SpecialType:
+ // What should I do here?
+ break;
+ }
+}
+
+_knumfloat::_knumfloat(_knumber const & num)
+{
+ mpf_init(_mpf);
+
+ switch(num.type()) {
+ case IntegerType:
+ mpf_set_z(_mpf, dynamic_cast<_knuminteger const &>(num)._mpz);
+ break;
+ case FractionType:
+ mpf_set_q(_mpf, dynamic_cast<_knumfraction const &>(num)._mpq);
+ break;
+ case FloatType:
+ mpf_set(_mpf, dynamic_cast<_knumfloat const &>(num)._mpf);
+ break;
+ case SpecialType:
+ // What should I do here?
+ break;
+ }
+}
+
+
+
+_knumerror::_knumerror(QString const & num)
+{
+ if (num == "nan")
+ _error = UndefinedNumber;
+ else if (num == "inf")
+ _error = Infinity;
+ else if (num == "-inf")
+ _error = MinusInfinity;
+}
+
+_knuminteger::_knuminteger(QString const & num)
+{
+ mpz_init(_mpz);
+ mpz_set_str(_mpz, num.ascii(), 10);
+}
+
+_knumfraction::_knumfraction(QString const & num)
+{
+ mpq_init(_mpq);
+ if (QRegExp("^[+-]?\\d+(\\.\\d*)?(e[+-]?\\d+)?$").exactMatch(num)) {
+ // my hand-made conversion is terrible
+ // first me convert the mantissa
+ unsigned long int digits_after_dot = ((num.section( '.', 1, 1)).section('e', 0, 0)).length();
+ QString tmp_num = num.section('e', 0, 0).remove('.');
+ mpq_set_str(_mpq, tmp_num.ascii(), 10);
+ mpz_t tmp_int;
+ mpz_init(tmp_int);
+ mpz_ui_pow_ui (tmp_int, 10, digits_after_dot);
+ mpz_mul(mpq_denref(_mpq), mpq_denref(_mpq), tmp_int);
+ // now we take care of the exponent
+ if (! (tmp_num = num.section('e', 1, 1)).isEmpty()) {
+ long int tmp_exp = tmp_num.toLong();
+ if (tmp_exp > 0) {
+ mpz_ui_pow_ui (tmp_int, 10,
+ static_cast<unsigned long int>(tmp_exp));
+ mpz_mul(mpq_numref(_mpq), mpq_numref(_mpq), tmp_int);
+ } else {
+ mpz_ui_pow_ui (tmp_int, 10,
+ static_cast<unsigned long int>(-tmp_exp));
+ mpz_mul(mpq_denref(_mpq), mpq_denref(_mpq), tmp_int);
+ }
+ }
+ mpz_clear(tmp_int);
+ } else
+ mpq_set_str(_mpq, num.ascii(), 10);
+ mpq_canonicalize(_mpq);
+}
+
+_knumfloat::_knumfloat(QString const & num)
+{
+ mpf_init(_mpf);
+ mpf_set_str(_mpf, num.ascii(), 10);
+}
+
+_knuminteger const & _knuminteger::operator = (_knuminteger const & num)
+{
+ if (this == &num)
+ return *this;
+
+ mpz_set(_mpz, num._mpz);
+ return *this;
+}
+
+QString const _knumerror::ascii(int prec) const
+{
+ static_cast<void>(prec);
+
+ switch(_error) {
+ case UndefinedNumber:
+ return QString("nan");
+ case Infinity:
+ return QString("inf");
+ case MinusInfinity:
+ return QString("-inf");
+ default:
+ return QString::null;
+ }
+}
+
+QString const _knuminteger::ascii(int prec) const
+{
+ static_cast<void>(prec);
+ char *tmp_ptr;
+
+ gmp_asprintf(&tmp_ptr, "%Zd", _mpz);
+ QString ret_str = tmp_ptr;
+
+ free(tmp_ptr);
+ return ret_str;
+}
+
+QString const _knumfraction::ascii(int prec) const
+{
+ static_cast<void>(prec);
+ char *tmp_ptr = mpq_get_str(0, 10, _mpq);
+ QString ret_str = tmp_ptr;
+
+ free(tmp_ptr);
+
+ return ret_str;
+}
+
+QString const _knumfloat::ascii(int prec) const
+{
+ QString ret_str;
+ char *tmp_ptr;
+ if (prec > 0)
+ gmp_asprintf(&tmp_ptr, ("%." + QString().setNum(prec) + "Fg").ascii(), _mpf);
+ else
+ gmp_asprintf(&tmp_ptr, "%Fg", _mpf);
+
+ ret_str = tmp_ptr;
+
+ free(tmp_ptr);
+
+ return ret_str;
+}
+
+
+bool _knumfraction::isInteger(void) const
+{
+ if (mpz_cmp_ui(mpq_denref(_mpq), 1) == 0)
+ return true;
+ else
+ return false;
+}
+
+
+_knumber * _knumerror::abs(void) const
+{
+ _knumerror * tmp_num = new _knumerror(*this);
+
+ if(_error == MinusInfinity) tmp_num->_error = Infinity;
+
+ return tmp_num;
+}
+
+_knumber * _knuminteger::abs(void) const
+{
+ _knuminteger * tmp_num = new _knuminteger();
+
+ mpz_abs(tmp_num->_mpz, _mpz);
+
+ return tmp_num;
+}
+
+_knumber * _knumfraction::abs(void) const
+{
+ _knumfraction * tmp_num = new _knumfraction();
+
+ mpq_abs(tmp_num->_mpq, _mpq);
+
+ return tmp_num;
+}
+
+_knumber * _knumfloat::abs(void) const
+{
+ _knumfloat * tmp_num = new _knumfloat();
+
+ mpf_abs(tmp_num->_mpf, _mpf);
+
+ return tmp_num;
+}
+
+
+
+_knumber * _knumerror::intPart(void) const
+{
+ return new _knumerror(*this);
+}
+
+_knumber * _knuminteger::intPart(void) const
+{
+ _knuminteger *tmp_num = new _knuminteger();
+ mpz_set(tmp_num->_mpz, _mpz);
+ return tmp_num;
+}
+
+_knumber * _knumfraction::intPart(void) const
+{
+ _knuminteger *tmp_num = new _knuminteger();
+
+ mpz_set_q(tmp_num->_mpz, _mpq);
+
+ return tmp_num;
+}
+
+_knumber * _knumfloat::intPart(void) const
+{
+ _knuminteger *tmp_num = new _knuminteger();
+
+ mpz_set_f(tmp_num->_mpz, _mpf);
+
+ return tmp_num;
+}
+
+
+
+
+int _knumerror::sign(void) const
+{
+ switch(_error) {
+ case Infinity:
+ return 1;
+ case MinusInfinity:
+ return -1;
+ default:
+ return 0;
+ }
+}
+
+int _knuminteger::sign(void) const
+{
+ return mpz_sgn(_mpz);
+}
+
+int _knumfraction::sign(void) const
+{
+ return mpq_sgn(_mpq);
+}
+
+int _knumfloat::sign(void) const
+{
+ return mpf_sgn(_mpf);
+}
+
+
+
+#warning _cbrt for now this is a stupid work around
+static void _cbrt(mpf_t &num)
+{
+ double tmp_num = cbrt(mpf_get_d(num));
+ mpf_init_set_d(num, tmp_num);
+}
+
+
+_knumber * _knumerror::cbrt(void) const
+{
+ // infty ^3 = infty; -infty^3 = -infty
+ _knumerror *tmp_num = new _knumerror(*this);
+
+ return tmp_num;
+}
+
+_knumber * _knuminteger::cbrt(void) const
+{
+ _knuminteger * tmp_num = new _knuminteger();
+
+ if(mpz_root(tmp_num->_mpz, _mpz, 3))
+ return tmp_num; // root is perfect
+
+ delete tmp_num; // root was not perfect, result will be float
+
+ _knumfloat * tmp_num2 = new _knumfloat();
+ mpf_set_z(tmp_num2->_mpf, _mpz);
+
+ _cbrt(tmp_num2->_mpf);
+
+ return tmp_num2;
+}
+
+_knumber * _knumfraction::cbrt(void) const
+{
+ _knumfraction * tmp_num = new _knumfraction();
+ if (mpz_root(mpq_numref(tmp_num->_mpq), mpq_numref(_mpq), 3)
+ && mpz_root(mpq_denref(tmp_num->_mpq), mpq_denref(_mpq), 3))
+ return tmp_num; // root is perfect
+
+ delete tmp_num; // root was not perfect, result will be float
+
+ _knumfloat * tmp_num2 = new _knumfloat();
+ mpf_set_q(tmp_num2->_mpf, _mpq);
+
+ _cbrt(tmp_num2->_mpf);
+
+ return tmp_num2;
+}
+
+_knumber * _knumfloat::cbrt(void) const
+{
+ _knumfloat * tmp_num = new _knumfloat(*this);
+
+ _cbrt(tmp_num->_mpf);
+
+ return tmp_num;
+}
+
+
+
+
+_knumber * _knumerror::sqrt(void) const
+{
+ _knumerror *tmp_num = new _knumerror(*this);
+
+ if(_error == MinusInfinity) tmp_num->_error = UndefinedNumber;
+
+ return tmp_num;
+}
+
+_knumber * _knuminteger::sqrt(void) const
+{
+ if (mpz_sgn(_mpz) < 0) {
+ _knumerror *tmp_num = new _knumerror(UndefinedNumber);
+ return tmp_num;
+ }
+ if (mpz_perfect_square_p(_mpz)) {
+ _knuminteger * tmp_num = new _knuminteger();
+
+ mpz_sqrt(tmp_num->_mpz, _mpz);
+
+ return tmp_num;
+ } else {
+ _knumfloat * tmp_num = new _knumfloat();
+ mpf_set_z(tmp_num->_mpf, _mpz);
+ mpf_sqrt(tmp_num->_mpf, tmp_num->_mpf);
+
+ return tmp_num;
+ }
+}
+
+_knumber * _knumfraction::sqrt(void) const
+{
+ if (mpq_sgn(_mpq) < 0) {
+ _knumerror *tmp_num = new _knumerror(UndefinedNumber);
+ return tmp_num;
+ }
+ if (mpz_perfect_square_p(mpq_numref(_mpq))
+ && mpz_perfect_square_p(mpq_denref(_mpq))) {
+ _knumfraction * tmp_num = new _knumfraction();
+ mpq_set(tmp_num->_mpq, _mpq);
+ mpz_sqrt(mpq_numref(tmp_num->_mpq), mpq_numref(tmp_num->_mpq));
+ mpz_sqrt(mpq_denref(tmp_num->_mpq), mpq_denref(tmp_num->_mpq));
+
+ return tmp_num;
+ } else {
+ _knumfloat * tmp_num = new _knumfloat();
+ mpf_set_q(tmp_num->_mpf, _mpq);
+ mpf_sqrt(tmp_num->_mpf, tmp_num->_mpf);
+
+ return tmp_num;
+ }
+
+ _knumfraction * tmp_num = new _knumfraction();
+
+ return tmp_num;
+}
+
+_knumber * _knumfloat::sqrt(void) const
+{
+ if (mpf_sgn(_mpf) < 0) {
+ _knumerror *tmp_num = new _knumerror(UndefinedNumber);
+ return tmp_num;
+ }
+ _knumfloat * tmp_num = new _knumfloat();
+
+ mpf_sqrt(tmp_num->_mpf, _mpf);
+
+ return tmp_num;
+}
+
+
+
+_knumber * _knumerror::change_sign(void) const
+{
+ _knumerror * tmp_num = new _knumerror();
+
+ if(_error == Infinity) tmp_num->_error = MinusInfinity;
+ if(_error == MinusInfinity) tmp_num->_error = Infinity;
+
+ return tmp_num;
+}
+
+_knumber * _knuminteger::change_sign(void) const
+{
+ _knuminteger * tmp_num = new _knuminteger();
+
+ mpz_neg(tmp_num->_mpz, _mpz);
+
+ return tmp_num;
+}
+
+_knumber * _knumfraction::change_sign(void) const
+{
+ _knumfraction * tmp_num = new _knumfraction();
+
+ mpq_neg(tmp_num->_mpq, _mpq);
+
+ return tmp_num;
+}
+
+_knumber *_knumfloat::change_sign(void) const
+{
+ _knumfloat * tmp_num = new _knumfloat();
+
+ mpf_neg(tmp_num->_mpf, _mpf);
+
+ return tmp_num;
+}
+
+
+_knumber * _knumerror::reciprocal(void) const
+{
+ switch(_error) {
+ case Infinity:
+ case MinusInfinity:
+ return new _knuminteger(0);
+ case UndefinedNumber:
+ default:
+ return new _knumerror(UndefinedNumber);
+ }
+}
+
+_knumber * _knuminteger::reciprocal(void) const
+{
+ if(mpz_cmp_si(_mpz, 0) == 0) return new _knumerror(Infinity);
+
+ _knumfraction * tmp_num = new _knumfraction(*this);
+
+ mpq_inv(tmp_num->_mpq, tmp_num->_mpq);
+
+ return tmp_num;
+}
+
+_knumber * _knumfraction::reciprocal() const
+{
+ if(mpq_cmp_si(_mpq, 0, 1) == 0) return new _knumerror(Infinity);
+
+ _knumfraction * tmp_num = new _knumfraction();
+
+ mpq_inv(tmp_num->_mpq, _mpq);
+
+ return tmp_num;
+}
+
+_knumber *_knumfloat::reciprocal(void) const
+{
+ if(mpf_cmp_si(_mpf, 0) == 0) return new _knumerror(Infinity);
+
+ _knumfloat * tmp_num = new _knumfloat();
+
+ mpf_div(tmp_num->_mpf, _knumfloat("1.0")._mpf, _mpf);
+
+ return tmp_num;
+}
+
+
+
+_knumber * _knumerror::add(_knumber const & arg2) const
+{
+ if (arg2.type() != SpecialType)
+ return new _knumerror(_error);
+
+ _knumerror const & tmp_arg2 = dynamic_cast<_knumerror const &>(arg2);
+
+ if (_error == UndefinedNumber
+ || tmp_arg2._error == UndefinedNumber
+ || (_error == Infinity && tmp_arg2._error == MinusInfinity)
+ || (_error == MinusInfinity && tmp_arg2._error == Infinity)
+ )
+ return new _knumerror(UndefinedNumber);
+
+ return new _knumerror(_error);
+}
+
+_knumber * _knuminteger::add(_knumber const & arg2) const
+{
+ if (arg2.type() != IntegerType)
+ return arg2.add(*this);
+
+ _knuminteger * tmp_num = new _knuminteger();
+
+ mpz_add(tmp_num->_mpz, _mpz,
+ dynamic_cast<_knuminteger const &>(arg2)._mpz);
+
+ return tmp_num;
+}
+
+_knumber * _knumfraction::add(_knumber const & arg2) const
+{
+ if (arg2.type() == IntegerType) {
+ // need to cast arg2 to fraction
+ _knumfraction tmp_num(arg2);
+ return tmp_num.add(*this);
+ }
+
+
+ if (arg2.type() == FloatType || arg2.type() == SpecialType)
+ return arg2.add(*this);
+
+ _knumfraction * tmp_num = new _knumfraction();
+
+ mpq_add(tmp_num->_mpq, _mpq,
+ dynamic_cast<_knumfraction const &>(arg2)._mpq);
+
+ return tmp_num;
+}
+
+_knumber *_knumfloat::add(_knumber const & arg2) const
+{
+ if (arg2.type() == SpecialType)
+ return arg2.add(*this);
+
+ if (arg2.type() != FloatType) {
+ // need to cast arg2 to float
+ _knumfloat tmp_num(arg2);
+ return tmp_num.add(*this);
+ }
+
+ _knumfloat * tmp_num = new _knumfloat();
+
+ mpf_add(tmp_num->_mpf, _mpf,
+ dynamic_cast<_knumfloat const &>(arg2)._mpf);
+
+ return tmp_num;
+}
+
+
+_knumber * _knumerror::multiply(_knumber const & arg2) const
+{
+ //improve this
+ switch(arg2.type()) {
+ case SpecialType:
+ {
+ _knumerror const & tmp_arg2 = dynamic_cast<_knumerror const &>(arg2);
+ if (_error == UndefinedNumber || tmp_arg2._error == UndefinedNumber)
+ return new _knumerror(UndefinedNumber);
+ if ( this->sign() * arg2.sign() > 0)
+ return new _knumerror(Infinity);
+ else
+ return new _knumerror(MinusInfinity);
+ }
+ case IntegerType:
+ case FractionType:
+ case FloatType:
+ {
+ int sign_arg2 = arg2.sign();
+ if (_error == UndefinedNumber || sign_arg2 == 0)
+ return new _knumerror(UndefinedNumber);
+ if ( (_error == Infinity && sign_arg2 > 0) ||
+ (_error == MinusInfinity && sign_arg2 < 0) )
+ return new _knumerror(Infinity);
+
+ return new _knumerror(MinusInfinity);
+ }
+ }
+
+ return new _knumerror(_error);
+}
+
+
+_knumber * _knuminteger::multiply(_knumber const & arg2) const
+{
+ if (arg2.type() != IntegerType)
+ return arg2.multiply(*this);
+
+ _knuminteger * tmp_num = new _knuminteger();
+
+ mpz_mul(tmp_num->_mpz, _mpz,
+ dynamic_cast<_knuminteger const &>(arg2)._mpz);
+
+ return tmp_num;
+}
+
+_knumber * _knumfraction::multiply(_knumber const & arg2) const
+{
+ if (arg2.type() == IntegerType) {
+ // need to cast arg2 to fraction
+ _knumfraction tmp_num(arg2);
+ return tmp_num.multiply(*this);
+ }
+
+
+ if (arg2.type() == FloatType || arg2.type() == SpecialType)
+ return arg2.multiply(*this);
+
+ _knumfraction * tmp_num = new _knumfraction();
+
+ mpq_mul(tmp_num->_mpq, _mpq,
+ dynamic_cast<_knumfraction const &>(arg2)._mpq);
+
+ return tmp_num;
+}
+
+_knumber *_knumfloat::multiply(_knumber const & arg2) const
+{
+ if (arg2.type() == SpecialType)
+ return arg2.multiply(*this);
+ if (arg2.type() == IntegerType &&
+ mpz_cmp_si(dynamic_cast<_knuminteger const &>(arg2)._mpz,0) == 0)
+ // if arg2 == 0 return integer 0!!
+ return new _knuminteger(0);
+
+ if (arg2.type() != FloatType) {
+ // need to cast arg2 to float
+ _knumfloat tmp_num(arg2);
+ return tmp_num.multiply(*this);
+ }
+
+ _knumfloat * tmp_num = new _knumfloat();
+
+ mpf_mul(tmp_num->_mpf, _mpf,
+ dynamic_cast<_knumfloat const &>(arg2)._mpf);
+
+ return tmp_num;
+}
+
+
+
+
+
+_knumber * _knumber::divide(_knumber const & arg2) const
+{
+ _knumber * tmp_num = arg2.reciprocal();
+ _knumber * rslt_num = this->multiply(*tmp_num);
+
+ delete tmp_num;
+
+ return rslt_num;
+}
+
+_knumber *_knumfloat::divide(_knumber const & arg2) const
+{
+ if(mpf_cmp_si(_mpf, 0) == 0) return new _knumerror(Infinity);
+
+ // automatically casts arg2 to float
+ _knumfloat * tmp_num = new _knumfloat(arg2);
+
+ mpf_div(tmp_num->_mpf, _mpf, tmp_num->_mpf);
+
+ return tmp_num;
+}
+
+
+
+
+_knumber * _knumerror::power(_knumber const & exponent) const
+{
+ static_cast<void>(exponent);
+ return new _knumerror(UndefinedNumber);
+}
+
+_knumber * _knuminteger::power(_knumber const & exponent) const
+{
+ if (exponent.type() == IntegerType) {
+
+ mpz_t tmp_mpz;
+ mpz_init_set(tmp_mpz,
+ dynamic_cast<_knuminteger const &>(exponent)._mpz);
+
+ if (! mpz_fits_ulong_p(tmp_mpz)) { // conversion wouldn't work, so
+ // use floats
+ mpz_clear(tmp_mpz);
+ // need to cast everything to float
+ _knumfloat tmp_num1(*this), tmp_num2(exponent);
+ return tmp_num1.power(tmp_num2);
+ }
+
+ unsigned long int tmp_int = mpz_get_ui(tmp_mpz);
+ mpz_clear(tmp_mpz);
+
+ _knuminteger * tmp_num = new _knuminteger();
+ mpz_pow_ui(tmp_num->_mpz, _mpz, tmp_int);
+ return tmp_num;
+ }
+ if (exponent.type() == FractionType) {
+ if (mpz_sgn(_mpz) < 0)
+ return new _knumerror(UndefinedNumber);
+ // GMP only supports few root functions, so we need to convert
+ // into signed long int
+ mpz_t tmp_mpz;
+ mpz_init_set(tmp_mpz,
+ mpq_denref(dynamic_cast<_knumfraction const &>(exponent)._mpq));
+
+ if (! mpz_fits_ulong_p(tmp_mpz)) { // conversion wouldn't work, so
+ // use floats
+ mpz_clear(tmp_mpz);
+ // need to cast everything to float
+ _knumfloat tmp_num1(*this), tmp_num2(exponent);
+ return tmp_num1.power(tmp_num2);
+ }
+
+ unsigned long int tmp_int = mpz_get_ui(tmp_mpz);
+ mpz_clear(tmp_mpz);
+
+ // first check if result will be an integer
+ _knuminteger * tmp_num = new _knuminteger();
+ int flag = mpz_root(tmp_num->_mpz, _mpz, tmp_int);
+ if (flag == 0) { // result is not exact
+ delete tmp_num;
+ // need to cast everything to float
+ _knumfloat tmp_num1(*this), tmp_num2(exponent);
+ return tmp_num1.power(tmp_num2);
+ }
+
+ // result is exact
+
+ mpz_init_set(tmp_mpz,
+ mpq_numref(dynamic_cast<_knumfraction const &>(exponent)._mpq));
+
+ if (! mpz_fits_ulong_p(tmp_mpz)) { // conversion wouldn't work, so
+ // use floats
+ mpz_clear(tmp_mpz);
+ // need to cast everything to float
+ _knumfloat tmp_num1(*this), tmp_num2(exponent);
+ return tmp_num1.power(tmp_num2);
+ }
+ tmp_int = mpz_get_ui(tmp_mpz);
+ mpz_clear(tmp_mpz);
+
+ mpz_pow_ui(tmp_num->_mpz, tmp_num->_mpz, tmp_int);
+
+ return tmp_num;
+ }
+ if (exponent.type() == FloatType) {
+ // need to cast everything to float
+ _knumfloat tmp_num(*this);
+ return tmp_num.power(exponent);
+ }
+
+ return new _knumerror(Infinity);
+}
+
+_knumber * _knumfraction::power(_knumber const & exponent) const
+{
+ _knuminteger tmp_num = _knuminteger();
+
+ mpz_set(tmp_num._mpz, mpq_numref(_mpq));
+ _knumber *numer = tmp_num.power(exponent);
+
+ mpz_set(tmp_num._mpz, mpq_denref(_mpq));
+ _knumber *denom = tmp_num.power(exponent);
+
+ _knumber *result = numer->divide(*denom);
+ delete numer;
+ delete denom;
+ return result;
+}
+
+_knumber * _knumfloat::power(_knumber const & exponent) const
+{
+ return new _knumfloat(pow(static_cast<double>(*this),
+ static_cast<double>(exponent)));
+}
+
+
+int _knumerror::compare(_knumber const &arg2) const
+{
+ if (arg2.type() != SpecialType) {
+ switch(_error) {
+ case Infinity:
+ return 1;
+ case MinusInfinity:
+ return -1;
+ default:
+ return 1; // Not really o.k., but what should I return
+ }
+ }
+
+ switch(_error) {
+ case Infinity:
+ if (dynamic_cast<_knumerror const &>(arg2)._error == Infinity)
+ // Infinity is larger than anything else, but itself
+ return 0;
+ return 1;
+ case MinusInfinity:
+ if (dynamic_cast<_knumerror const &>(arg2)._error == MinusInfinity)
+ // MinusInfinity is smaller than anything else, but itself
+ return 0;
+ return -1;
+ default:
+ if (dynamic_cast<_knumerror const &>(arg2)._error == UndefinedNumber)
+ // Undefined only equal to itself
+ return 0;
+ return -arg2.compare(*this);
+ }
+}
+
+int _knuminteger::compare(_knumber const &arg2) const
+{
+ if (arg2.type() != IntegerType)
+ return - arg2.compare(*this);
+
+ return mpz_cmp(_mpz, dynamic_cast<_knuminteger const &>(arg2)._mpz);
+}
+
+int _knumfraction::compare(_knumber const &arg2) const
+{
+ if (arg2.type() != FractionType) {
+ if (arg2.type() == IntegerType) {
+ mpq_t tmp_frac;
+ mpq_init(tmp_frac);
+ mpq_set_z(tmp_frac,
+ dynamic_cast<_knuminteger const &>(arg2)._mpz);
+ int cmp_result = mpq_cmp(_mpq, tmp_frac);
+ mpq_clear(tmp_frac);
+ return cmp_result;
+ } else
+ return - arg2.compare(*this);
+ }
+
+ return mpq_cmp(_mpq, dynamic_cast<_knumfraction const &>(arg2)._mpq);
+}
+
+int _knumfloat::compare(_knumber const &arg2) const
+{
+ if (arg2.type() != FloatType) {
+ mpf_t tmp_float;
+ if (arg2.type() == IntegerType) {
+ mpf_init(tmp_float);
+ mpf_set_z(tmp_float,
+ dynamic_cast<_knuminteger const &>(arg2)._mpz);
+ } else if (arg2.type() == FractionType) {
+ mpf_init(tmp_float);
+ mpf_set_q(tmp_float,
+ dynamic_cast<_knumfraction const &>(arg2)._mpq);
+ } else
+ return - arg2.compare(*this);
+
+ int cmp_result = mpf_cmp(_mpf, tmp_float);
+ mpf_clear(tmp_float);
+ return cmp_result;
+ }
+
+ return mpf_cmp(_mpf, dynamic_cast<_knumfloat const &>(arg2)._mpf);
+}
+
+
+
+_knumerror::operator signed long int (void) const
+{
+ // what would be the correct return values here?
+ if (_error == Infinity)
+ return 0;
+ if (_error == MinusInfinity)
+ return 0;
+ else // if (_error == UndefinedNumber)
+ return 0;
+}
+
+_knumerror::operator unsigned long int (void) const
+{
+ // what would be the correct return values here?
+ if (_error == Infinity)
+ return 0;
+ if (_error == MinusInfinity)
+ return 0;
+ else // if (_error == UndefinedNumber)
+ return 0;
+}
+
+
+_knuminteger::operator signed long int (void) const
+{
+ return mpz_get_si(_mpz);
+}
+
+_knumfraction::operator signed long int (void) const
+{
+ return static_cast<signed long int>(mpq_get_d(_mpq));
+}
+
+_knumfloat::operator signed long int (void) const
+{
+ return mpf_get_si(_mpf);
+}
+
+_knuminteger::operator unsigned long int (void) const
+{
+ return mpz_get_ui(_mpz);
+}
+
+_knumfraction::operator unsigned long int (void) const
+{
+ return static_cast<unsigned long int>(mpq_get_d(_mpq));
+}
+
+_knumfloat::operator unsigned long int (void) const
+{
+ return mpf_get_ui(_mpf);
+}
+
+
+
+_knumerror::operator double (void) const
+{
+ if (_error == Infinity)
+ return INFINITY;
+ if (_error == MinusInfinity)
+ return -INFINITY;
+ else // if (_error == UndefinedNumber)
+ return NAN;
+}
+
+_knuminteger::operator double (void) const
+{
+ return mpz_get_d(_mpz);
+}
+
+_knumfraction::operator double (void) const
+{
+ return mpq_get_d(_mpq);
+}
+
+_knumfloat::operator double (void) const
+{
+ return mpf_get_d(_mpf);
+}
+
+
+
+
+_knuminteger * _knuminteger::intAnd(_knuminteger const &arg2) const
+{
+ _knuminteger * tmp_num = new _knuminteger();
+
+ mpz_and(tmp_num->_mpz, _mpz, arg2._mpz);
+
+ return tmp_num;
+}
+
+_knuminteger * _knuminteger::intOr(_knuminteger const &arg2) const
+{
+ _knuminteger * tmp_num = new _knuminteger();
+
+ mpz_ior(tmp_num->_mpz, _mpz, arg2._mpz);
+
+ return tmp_num;
+}
+
+_knumber * _knuminteger::mod(_knuminteger const &arg2) const
+{
+ if(mpz_cmp_si(arg2._mpz, 0) == 0) return new _knumerror(UndefinedNumber);
+
+ _knuminteger * tmp_num = new _knuminteger();
+
+ mpz_mod(tmp_num->_mpz, _mpz, arg2._mpz);
+
+ return tmp_num;
+}
+
+_knumber * _knuminteger::shift(_knuminteger const &arg2) const
+{
+ mpz_t tmp_mpz;
+
+ mpz_init_set (tmp_mpz, arg2._mpz);
+
+ if (! mpz_fits_slong_p(tmp_mpz)) {
+ mpz_clear(tmp_mpz);
+ return new _knumerror(UndefinedNumber);
+ }
+
+ signed long int tmp_arg2 = mpz_get_si(tmp_mpz);
+ mpz_clear(tmp_mpz);
+
+
+ _knuminteger * tmp_num = new _knuminteger();
+
+ if (tmp_arg2 > 0) // left shift
+ mpz_mul_2exp(tmp_num->_mpz, _mpz, tmp_arg2);
+ else // right shift
+ mpz_tdiv_q_2exp(tmp_num->_mpz, _mpz, -tmp_arg2);
+
+
+ return tmp_num;
+}
+
diff --git a/kcalc/knumber/knumber_priv.h b/kcalc/knumber/knumber_priv.h
new file mode 100644
index 0000000..7dd58a6
--- /dev/null
+++ b/kcalc/knumber/knumber_priv.h
@@ -0,0 +1,313 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2005 Klaus Niederkrueger <kniederk@math.uni-koeln.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#ifndef _KNUMBER_PRIV_H
+#define _KNUMBER_PRIV_H
+
+class QString;
+
+#include <cstdio>
+#include <gmp.h>
+
+// work-around for pre-C99-libs
+#ifndef INFINITY
+#define INFINITY HUGE_VAL
+#endif
+// this is really ugly
+#ifndef NAN
+#define NAN (atof("nan"))
+#endif
+
+class _knumber
+{
+ public:
+ enum NumType {SpecialType, IntegerType, FractionType, FloatType};
+ enum ErrorType {UndefinedNumber, Infinity, MinusInfinity};
+
+ _knumber() {}
+
+ virtual ~_knumber() {}
+
+ virtual void copy(_knumber const & num) = 0;
+
+ virtual NumType type(void) const = 0;
+
+ virtual QString const ascii(int prec = -1) const = 0;
+
+ virtual _knumber * abs(void) const = 0;
+ virtual _knumber * intPart(void) const = 0;
+ virtual int sign(void) const = 0;
+ virtual _knumber * sqrt(void) const = 0;
+ virtual _knumber * cbrt(void) const = 0;
+ virtual _knumber * change_sign(void) const = 0;
+ virtual _knumber * reciprocal(void) const = 0;
+ virtual _knumber * add(_knumber const & arg2) const = 0;
+ virtual _knumber * multiply(_knumber const & arg2) const = 0;
+ _knumber * divide(_knumber const & arg2) const;
+
+ virtual _knumber * power(_knumber const & exponent) const = 0;
+
+ virtual int compare(_knumber const &arg2) const = 0;
+
+ virtual operator signed long int (void) const = 0;
+ virtual operator unsigned long int (void) const = 0;
+ virtual operator double (void) const = 0;
+};
+
+
+
+class _knumerror : public _knumber
+{
+ public:
+ _knumerror(ErrorType error = UndefinedNumber)
+ : _error(error) { }
+
+ _knumerror(_knumber const & num);
+
+ _knumerror(const QString & num);
+
+ //virtual ~_knumerror() { }
+
+ _knumerror const & operator = (_knumerror const & num);
+
+ virtual void copy(_knumber const & num)
+ {
+ _error = dynamic_cast<_knumerror const &>(num)._error;
+ }
+
+ virtual NumType type(void) const {return SpecialType;}
+
+ virtual QString const ascii(int prec = -1) const;
+
+ virtual _knumber * abs(void) const;
+ virtual _knumber * intPart(void) const;
+ virtual int sign(void) const;
+ virtual _knumber * cbrt(void) const;
+ virtual _knumber * sqrt(void) const;
+ virtual _knumber * change_sign(void) const;
+ virtual _knumber * reciprocal(void) const;
+ virtual _knumber * add(_knumber const & arg2) const;
+ virtual _knumber * multiply(_knumber const & arg2) const;
+
+ virtual _knumber * power(_knumber const & exponent) const;
+
+ virtual int compare(_knumber const &arg2) const;
+
+ virtual operator signed long int (void) const;
+ virtual operator unsigned long int (void) const;
+ virtual operator double (void) const;
+
+ private:
+
+ ErrorType _error;
+
+ friend class _knuminteger;
+ friend class _knumfraction;
+ friend class _knumfloat;
+};
+
+
+
+class _knuminteger : public _knumber
+{
+ public:
+ _knuminteger(signed int num = 0)
+ {
+ mpz_init_set_si(_mpz, num);
+ }
+
+ _knuminteger(unsigned int num)
+ {
+ mpz_init_set_ui(_mpz, num);
+ }
+
+ _knuminteger(signed long int num)
+ {
+ mpz_init_set_si(_mpz, num);
+ }
+
+ _knuminteger(unsigned long int num)
+ {
+ mpz_init_set_ui(_mpz, num);
+ }
+
+ _knuminteger(unsigned long long int num);
+
+ _knuminteger(_knumber const & num);
+
+ _knuminteger(const QString & num);
+
+ virtual ~_knuminteger()
+ {
+ mpz_clear(_mpz);
+ }
+
+ _knuminteger const & operator = (_knuminteger const & num);
+
+ virtual void copy(_knumber const & num)
+ {
+ mpz_set(_mpz, dynamic_cast<_knuminteger const &>(num)._mpz);
+ }
+
+ virtual NumType type(void) const {return IntegerType;}
+
+ virtual QString const ascii(int prec = -1) const;
+
+ virtual _knumber * abs(void) const;
+ virtual _knumber * intPart(void) const;
+ virtual int sign(void) const;
+ virtual _knumber * cbrt(void) const;
+ virtual _knumber * sqrt(void) const;
+ virtual _knumber * change_sign(void) const;
+ virtual _knumber * reciprocal(void) const;
+ virtual _knumber * add(_knumber const & arg2) const;
+ virtual _knumber * multiply(_knumber const & arg2) const;
+
+ virtual int compare(_knumber const &arg2) const;
+
+ virtual _knumber * power(_knumber const & exponent) const;
+
+ virtual operator signed long int (void) const;
+ virtual operator unsigned long int (void) const;
+ virtual operator double (void) const;
+
+ _knuminteger * intAnd(_knuminteger const &arg2) const;
+ _knuminteger * intOr(_knuminteger const &arg2) const;
+ _knumber * mod(_knuminteger const &arg2) const;
+ _knumber * shift(_knuminteger const &arg2) const;
+
+ private:
+ mpz_t _mpz;
+
+ friend class _knumfraction;
+ friend class _knumfloat;
+};
+
+
+
+class _knumfraction : public _knumber
+{
+ public:
+
+ _knumfraction(signed long int nom = 0, signed long int denom = 1)
+ {
+ mpq_init(_mpq);
+ mpq_set_si(_mpq, nom, denom);
+ mpq_canonicalize(_mpq);
+ }
+
+ _knumfraction(_knumber const & num);
+
+ _knumfraction(QString const & num);
+
+ virtual ~_knumfraction()
+ {
+ mpq_clear(_mpq);
+ }
+
+ virtual void copy(_knumber const & num)
+ {
+ mpq_set(_mpq, dynamic_cast<_knumfraction const &>(num)._mpq);
+ }
+
+ virtual NumType type(void) const {return FractionType;}
+
+ virtual QString const ascii(int prec = -1) const;
+
+ bool isInteger(void) const;
+
+ virtual _knumber * abs(void) const;
+ virtual _knumber * intPart(void) const;
+ virtual int sign(void) const;
+ virtual _knumber * cbrt(void) const;
+ virtual _knumber * sqrt(void) const;
+ virtual _knumber * change_sign(void) const;
+ virtual _knumber * reciprocal(void) const;
+ virtual _knumber * add(_knumber const & arg2) const;
+ virtual _knumber * multiply(_knumber const & arg2) const;
+
+ virtual _knumber * power(_knumber const & exponent) const;
+
+ virtual int compare(_knumber const &arg2) const;
+
+ virtual operator signed long int (void) const;
+ virtual operator unsigned long int (void) const;
+ virtual operator double (void) const;
+
+ private:
+ mpq_t _mpq;
+
+ friend class _knuminteger;
+ friend class _knumfloat;
+};
+
+class _knumfloat : public _knumber
+{
+ public:
+ _knumfloat(double num = 1.0)
+ {
+ mpf_init(_mpf);
+ mpf_set_d(_mpf, num);
+ }
+
+ _knumfloat(_knumber const & num);
+
+ _knumfloat(QString const & num);
+
+ virtual ~_knumfloat()
+ {
+ mpf_clear(_mpf);
+ }
+
+ virtual void copy(_knumber const & num)
+ {
+ mpf_set(_mpf, dynamic_cast<_knumfloat const &>(num)._mpf);
+ }
+
+ virtual NumType type(void) const {return FloatType;}
+
+ virtual QString const ascii(int prec = -1) const;
+
+ virtual _knumber * abs(void) const;
+ virtual _knumber * intPart(void) const;
+ virtual int sign(void) const;
+ virtual _knumber * cbrt(void) const;
+ virtual _knumber * sqrt(void) const;
+ virtual _knumber * change_sign(void) const;
+ virtual _knumber * reciprocal(void) const;
+ virtual _knumber * add(_knumber const & arg2) const;
+ virtual _knumber * multiply(_knumber const & arg2) const;
+ virtual _knumber * divide(_knumber const & arg2) const;
+
+ virtual _knumber * power(_knumber const & exponent) const;
+
+ virtual int compare(_knumber const &arg2) const;
+
+ virtual operator signed long int (void) const;
+ virtual operator unsigned long int (void) const;
+ virtual operator double (void) const;
+
+ private:
+ mpf_t _mpf;
+
+ friend class _knuminteger;
+ friend class _knumfraction;
+};
+
+
+#endif // _KNUMBER_PRIV_H
diff --git a/kcalc/knumber/tests/Makefile.am b/kcalc/knumber/tests/Makefile.am
new file mode 100644
index 0000000..73b0600
--- /dev/null
+++ b/kcalc/knumber/tests/Makefile.am
@@ -0,0 +1,32 @@
+# This file is part of the KDE libraries
+# Copyright (C) 1996-1997 Matthias Kalle Dalheimer (kalle@kde.org)
+# (C) 1997-1998 Stephan Kulow (coolo@kde.org)
+
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Library General Public License for more details.
+
+# You should have received a copy of the GNU Library General Public License
+# along with this library; see the file COPYING.LIB. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301, USA.
+
+INCLUDES = -I$(top_srcdir)/kcalc/knumber $(all_includes)
+
+check_PROGRAMS = knumbertest
+
+TESTS = knumbertest
+
+noinst_HEADERS = knumbertest.h
+
+METASOURCES = AUTO
+
+knumbertest_SOURCES = knumbertest.cpp
+knumbertest_LDADD = ../libknumber.la $(LIB_QT) $(LIBGMP)
+knumbertest_LDFLAGS = $(all_libraries) $(KDE_RPATH)
diff --git a/kcalc/knumber/tests/knumbertest.cpp b/kcalc/knumber/tests/knumbertest.cpp
new file mode 100644
index 0000000..814410e
--- /dev/null
+++ b/kcalc/knumber/tests/knumbertest.cpp
@@ -0,0 +1,582 @@
+//
+// Author: Klaus Niederkrueger <kniederk@math.uni-koeln.de>
+//
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <iostream>
+#include <qstring.h>
+
+#include "knumbertest.h"
+
+QString const numtypeToString(KNumber::NumType arg)
+{
+ switch(arg) {
+ case KNumber::SpecialType:
+ return QString("Special");
+ case KNumber::IntegerType:
+ return QString("Integer");
+ case KNumber::FractionType:
+ return QString("Fraction");
+ case KNumber::FloatType:
+ return QString("Float");
+ default:
+ return QString("Unknown:") + QString::number(static_cast<int>(arg));
+
+ }
+}
+
+void checkResult(QString const &string, KNumber const & result,
+ QString const & desired_string, KNumber::NumType desired)
+{
+ std::cout << "Testing result of: " << string.ascii() <<
+ " should give " << desired_string.ascii() << " and gives " <<
+ result.toQString(8).ascii() << "....\n";
+ std::cout << "The type of the result should be " <<
+ numtypeToString(desired).ascii() << " and gives " <<
+ numtypeToString(result.type()).ascii() << ".... ";
+
+ if (result.type() == desired &&
+ result.toQString(8) == desired_string) {
+ std::cout << "OK\n";
+ return;
+ }
+
+ std::cout << "Failed\n";
+ exit(1);
+}
+
+void checkTruth(QString const &string, bool computation,
+ bool desired_result)
+{
+ std::cout << "Testing truth of: " << string.ascii() <<
+ " should be " << desired_result << " and is " <<
+ computation << "....\n";
+
+ if (computation == desired_result) {
+ std::cout << "OK\n";
+ return;
+ }
+
+ std::cout << "Failed\n";
+ exit(1);
+}
+
+
+void checkType(QString const &string, KNumber::NumType test_arg,
+ KNumber::NumType desired)
+{
+ std::cout << "Testing type of: " << string.ascii() << " should give " <<
+ numtypeToString(desired).ascii() << " and gives " <<
+ numtypeToString(test_arg).ascii() << "....";
+
+ if (test_arg == desired) {
+ std::cout << "OK\n";
+ return;
+ }
+
+ std::cout << "Failed\n";
+ exit(1);
+
+}
+
+
+void testingCompare(void)
+{
+ std::cout << "\n\nTesting Compare:\n";
+
+ checkTruth("KNumber(5) == KNumber(2)", KNumber(5) == KNumber(2), false);
+ checkTruth("KNumber(5) > KNumber(2)", KNumber(5) > KNumber(2), true);
+ checkTruth("KNumber(5) < KNumber(2)", KNumber(5) < KNumber(2), false);
+ checkTruth("KNumber(5) < KNumber(0)", KNumber(5) < KNumber(0), false);
+ checkTruth("KNumber(-5) < KNumber(0)", KNumber(-5) < KNumber(0), true);
+ checkTruth("KNumber(5) >= KNumber(2)", KNumber(5) >= KNumber(2), true);
+ checkTruth("KNumber(5) <= KNumber(2)", KNumber(5) <= KNumber(2), false);
+ checkTruth("KNumber(5) != KNumber(2)", KNumber(5) != KNumber(2), true);
+
+ checkTruth("KNumber(2) == KNumber(2)", KNumber(2) == KNumber(2), true);
+ checkTruth("KNumber(2) > KNumber(2)", KNumber(2) > KNumber(2), false);
+ checkTruth("KNumber(2) < KNumber(2)", KNumber(2) < KNumber(2), false);
+ checkTruth("KNumber(2) >= KNumber(2)", KNumber(2) >= KNumber(2), true);
+ checkTruth("KNumber(2) <= KNumber(2)", KNumber(2) <= KNumber(2), true);
+ checkTruth("KNumber(2) != KNumber(2)", KNumber(2) != KNumber(2), false);
+
+ checkTruth("KNumber(5) == KNumber(\"1/2\")", KNumber(5) == KNumber("1/2"), false);
+ checkTruth("KNumber(5) > KNumber(\"1/2\")", KNumber(5) > KNumber("1/2"), true);
+ checkTruth("KNumber(5) < KNumber(\"1/2\")", KNumber(5) < KNumber("1/2"), false);
+ checkTruth("KNumber(5) >= KNumber(\"1/2\")", KNumber(5) >= KNumber("1/2"), true);
+ checkTruth("KNumber(5) <= KNumber(\"1/2\")", KNumber(5) <= KNumber("1/2"), false);
+ checkTruth("KNumber(5) != KNumber(\"1/2\")", KNumber(5) != KNumber("1/2"), true);
+
+ checkTruth("KNumber(\"1/2\") == KNumber(\"1/2\")", KNumber("1/2") == KNumber("1/2"), true);
+ checkTruth("KNumber(\"1/2\") > KNumber(\"1/2\")", KNumber("1/2") > KNumber("1/2"), false);
+ checkTruth("KNumber(\"1/2\") < KNumber(\"1/2\")", KNumber("1/2") < KNumber("1/2"), false);
+ checkTruth("KNumber(\"1/2\") >= KNumber(\"1/2\")", KNumber("1/2") >= KNumber("1/2"), true);
+ checkTruth("KNumber(\"1/2\") <= KNumber(\"1/2\")", KNumber("1/2") <= KNumber("1/2"), true);
+ checkTruth("KNumber(\"1/2\") != KNumber(\"1/2\")", KNumber("1/2") != KNumber("1/2"), false);
+
+ checkTruth("KNumber(\"3/2\") == KNumber(\"1/2\")", KNumber("3/2") == KNumber("1/2"), false);
+ checkTruth("KNumber(\"3/2\") > KNumber(\"1/2\")", KNumber("3/2") > KNumber("1/2"), true);
+ checkTruth("KNumber(\"3/2\") < KNumber(\"1/2\")", KNumber("3/2") < KNumber("1/2"), false);
+ checkTruth("KNumber(\"3/2\") >= KNumber(\"1/2\")", KNumber("3/2") >= KNumber("1/2"), true);
+ checkTruth("KNumber(\"3/2\") <= KNumber(\"1/2\")", KNumber("3/2") <= KNumber("1/2"), false);
+ checkTruth("KNumber(\"3/2\") != KNumber(\"1/2\")", KNumber("3/2") != KNumber("1/2"), true);
+
+}
+
+
+void testingAdditions(void)
+{
+ std::cout << "\n\nTesting additions:\n";
+
+ checkResult("KNumber(5) + KNumber(2)", KNumber(5) + KNumber(2), "7", KNumber::IntegerType);
+ checkResult("KNumber(5) + KNumber(\"2/3\")", KNumber(5) + KNumber("2/3"), "17/3", KNumber::FractionType);
+ checkResult("KNumber(5) + KNumber(\"2.3\")", KNumber(5) + KNumber("2.3"), "7.3", KNumber::FloatType);
+
+ checkResult("KNumber(\"5/3\") + KNumber(2)", KNumber("5/3") + KNumber(2), "11/3", KNumber::FractionType);
+ checkResult("KNumber(\"5/3\") + KNumber(\"2/3\")", KNumber("5/3") + KNumber("2/3"), "7/3", KNumber::FractionType);
+ checkResult("KNumber(\"5/3\") + KNumber(\"1/3\")", KNumber("5/3") + KNumber("1/3"), "2", KNumber::IntegerType);
+ checkResult("KNumber(\"5/3\") + KNumber(\"-26/3\")", KNumber("5/3") + KNumber("-26/3"), "-7", KNumber::IntegerType);
+ checkResult("KNumber(\"5/2\") + KNumber(2.3)", KNumber("5/2") + KNumber(2.3), "4.8", KNumber::FloatType);
+
+ checkResult("KNumber(5.3) + KNumber(2)", KNumber(5.3) + KNumber(2), "7.3", KNumber::FloatType);
+ checkResult("KNumber(5.3) + KNumber(\"2/4\")", KNumber(5.3) + KNumber("2/4"), "5.8", KNumber::FloatType);
+ checkResult("KNumber(5.3) + KNumber(2.3)", KNumber(5.3) + KNumber(2.3), "7.6", KNumber::FloatType);
+
+}
+
+void testingSubtractions(void)
+{
+ std::cout << "\n\nTesting subtractions:\n";
+
+ checkResult("KNumber(5) - KNumber(2)", KNumber(5) - KNumber(2), "3", KNumber::IntegerType);
+ checkResult("KNumber(5) - KNumber(\"2/3\")", KNumber(5) - KNumber("2/3"), "13/3", KNumber::FractionType);
+ checkResult("KNumber(5) - KNumber(2.3)", KNumber(5) - KNumber(2.3), "2.7", KNumber::FloatType);
+
+ checkResult("KNumber(\"5/3\") - KNumber(2)", KNumber("5/3") - KNumber(2), "-1/3", KNumber::FractionType);
+ checkResult("KNumber(\"5/3\") - KNumber(\"1/3\")", KNumber("5/3") - KNumber("1/3"), "4/3", KNumber::FractionType);
+ checkResult("KNumber(\"5/3\") - KNumber(\"2/3\")", KNumber("5/3") - KNumber("2/3"), "1", KNumber::IntegerType);
+ checkResult("KNumber(\"-5/3\") - KNumber(\"4/3\")", KNumber("-5/3") - KNumber("4/3"), "-3", KNumber::IntegerType);
+ checkResult("KNumber(\"5/4\") - KNumber(2.2)", KNumber("5/4") - KNumber(2.2), "-0.95", KNumber::FloatType);
+
+ checkResult("KNumber(5.3) - KNumber(2)", KNumber(5.3) - KNumber(2), "3.3", KNumber::FloatType);
+ checkResult("KNumber(5.3) - KNumber(\"3/4\")", KNumber(5.3) - KNumber("3/4"), "4.55", KNumber::FloatType);
+ checkResult("KNumber(5.3) - KNumber(2.3)", KNumber(5.3) - KNumber(2.3), "3", KNumber::FloatType);
+
+}
+
+
+void testingMultiplications(void)
+{
+ std::cout << "\n\nTesting multiplications:\n";
+
+ checkResult("KNumber(5) * KNumber(2)", KNumber(5) * KNumber(2), "10", KNumber::IntegerType);
+ checkResult("KNumber(5) * KNumber(\"2/3\")", KNumber(5) * KNumber("2/3"), "10/3", KNumber::FractionType);
+ checkResult("KNumber(5) * KNumber(\"2/5\")", KNumber(5) * KNumber("2/5"), "2", KNumber::IntegerType);
+ checkResult("KNumber(5) * KNumber(2.3)", KNumber(5) * KNumber(2.3), "11.5", KNumber::FloatType);
+ checkResult("KNumber(0) * KNumber(\"2/5\")", KNumber(0) * KNumber("2/5"), "0", KNumber::IntegerType);
+ checkResult("KNumber(0) * KNumber(2.3)", KNumber(0) * KNumber(2.3), "0", KNumber::IntegerType);
+
+ checkResult("KNumber(\"5/3\") * KNumber(2)", KNumber("5/3") * KNumber(2), "10/3", KNumber::FractionType);
+ checkResult("KNumber(\"5/3\") * KNumber(0)", KNumber("5/3") * KNumber(0), "0", KNumber::IntegerType);
+ checkResult("KNumber(\"5/3\") * KNumber(\"2/3\")", KNumber("5/3") * KNumber("2/3"), "10/9", KNumber::FractionType);
+ checkResult("KNumber(\"25/6\") * KNumber(\"12/5\")", KNumber("25/6") * KNumber("12/5"), "10", KNumber::IntegerType);
+ checkResult("KNumber(\"5/2\") * KNumber(2.3)", KNumber("5/2") * KNumber(2.3), "5.75",KNumber::FloatType);
+
+ checkResult("KNumber(5.3) * KNumber(2)", KNumber(5.3) * KNumber(2), "10.6", KNumber::FloatType);
+ checkResult("KNumber(5.3) * KNumber(0)", KNumber(5.3) * KNumber(0), "0", KNumber::IntegerType);
+ checkResult("KNumber(5.3) * KNumber(\"1/2\")", KNumber(5.3) * KNumber("1/2"), "2.65", KNumber::FloatType);
+ checkResult("KNumber(5.3) * KNumber(2.3)", KNumber(5.3) * KNumber(2.3), "12.19", KNumber::FloatType);
+
+}
+
+void testingDivisions(void)
+{
+ std::cout << "\n\nTesting divisions:\n";
+
+ checkResult("KNumber(5) / KNumber(2)", KNumber(5) / KNumber(2), "5/2", KNumber::FractionType);
+ checkResult("KNumber(122) / KNumber(2)", KNumber(122) / KNumber(2), "61", KNumber::IntegerType);
+ checkResult("KNumber(12) / KNumber(0)", KNumber(12) / KNumber(0), "inf", KNumber::SpecialType);
+ checkResult("KNumber(-12) / KNumber(0)", KNumber(-12) / KNumber(0), "-inf", KNumber::SpecialType);
+ checkResult("KNumber(5) / KNumber(\"2/3\")", KNumber(5) / KNumber("2/3"), "15/2", KNumber::FractionType);
+ checkResult("KNumber(6) / KNumber(\"2/3\")", KNumber(6) / KNumber("2/3"), "9", KNumber::IntegerType);
+ checkResult("KNumber(5) / KNumber(2.5)", KNumber(5) / KNumber(2.5), "2", KNumber::FloatType);
+ checkResult("KNumber(5) / KNumber(0.0)", KNumber(5) / KNumber(0.0), "inf", KNumber::SpecialType);
+ checkResult("KNumber(-5) / KNumber(0.0)", KNumber(-5) / KNumber(0.0), "-inf", KNumber::SpecialType);
+
+ checkResult("KNumber(\"5/3\") / KNumber(2)", KNumber("5/3") / KNumber(2), "5/6", KNumber::FractionType);
+ checkResult("KNumber(\"5/3\") / KNumber(0)", KNumber("5/3") / KNumber(0), "inf", KNumber::SpecialType);
+ checkResult("KNumber(\"-5/3\") / KNumber(0)", KNumber("-5/3") / KNumber(0), "-inf", KNumber::SpecialType);
+ checkResult("KNumber(\"5/3\") / KNumber(\"2/3\")", KNumber("5/3") / KNumber("2/3"), "5/2", KNumber::FractionType);
+ checkResult("KNumber(\"49/3\") / KNumber(\"7/9\")", KNumber("49/3") / KNumber("7/9"), "21", KNumber::IntegerType);
+ checkResult("KNumber(\"5/2\") / KNumber(2.5)", KNumber("5/2") / KNumber(2.5), "1", KNumber::FloatType);
+ checkResult("KNumber(\"5/2\") / KNumber(0.0)", KNumber("5/2") / KNumber(0.0), "inf", KNumber::SpecialType);
+ checkResult("KNumber(\"-5/2\") / KNumber(0.0)", KNumber("-5/2") / KNumber(0.0), "-inf", KNumber::SpecialType);
+
+ checkResult("KNumber(5.3) / KNumber(2)", KNumber(5.3) / KNumber(2), "2.65", KNumber::FloatType);
+ checkResult("KNumber(5.3) / KNumber(0)", KNumber(5.3) / KNumber(0), "inf", KNumber::SpecialType);
+ checkResult("KNumber(-5.3) / KNumber(0)", KNumber(-5.3) / KNumber(0), "-inf", KNumber::SpecialType);
+ checkResult("KNumber(5.3) / KNumber(\"2/3\")", KNumber(5.3) / KNumber("2/3"), "7.95", KNumber::FloatType);
+ checkResult("KNumber(5.5) / KNumber(2.5)", KNumber(5.5) / KNumber(2.5), "2.2", KNumber::FloatType);
+ checkResult("KNumber(5.5) / KNumber(0.0)", KNumber(5.5) / KNumber(0.0), "inf", KNumber::SpecialType);
+ checkResult("KNumber(-5.5) / KNumber(0.0)", KNumber(-5.5) / KNumber(0.0), "-inf", KNumber::SpecialType);
+}
+
+void testingModulus(void)
+{
+ std::cout << "\n\nTesting modulus:\n";
+
+ checkResult("KNumber(23) % KNumber(4)", KNumber(23) % KNumber(4), "3", KNumber::IntegerType);
+ checkResult("KNumber(12) % KNumber(-5)", KNumber(12) % KNumber(-5), "2", KNumber::IntegerType);
+ checkResult("KNumber(-12) % KNumber(5)", KNumber(-12) % KNumber(5), "3", KNumber::IntegerType);
+ checkResult("KNumber(12) % KNumber(0)", KNumber(-12) % KNumber(0), "nan", KNumber::SpecialType);
+ checkResult("KNumber(-12) % KNumber(0)", KNumber(-12) % KNumber(0), "nan", KNumber::SpecialType);
+
+#warning test for other types
+
+}
+
+void testingAndOr(void)
+{
+ std::cout << "\n\nTesting And/Or:\n";
+
+ checkResult("KNumber(17) & KNumber(9)", KNumber(17) & KNumber(9), "1", KNumber::IntegerType);
+ checkResult("KNumber(17) | KNumber(9)", KNumber(17) | KNumber(9), "25", KNumber::IntegerType);
+ checkResult("KNumber(1023) & KNumber(255)", KNumber(1023) & KNumber(255), "255", KNumber::IntegerType);
+ checkResult("KNumber(1023) | KNumber(255)", KNumber(1023) | KNumber(255), "1023", KNumber::IntegerType);
+
+#warning test for other types
+
+}
+
+
+void testingAbs(void)
+{
+ std::cout << "\n\nTesting absolute value:\n";
+
+ checkResult("KNumber(5).abs()", KNumber(5).abs(), "5", KNumber::IntegerType);
+ checkResult("KNumber(\"2/3\").abs()", KNumber("2/3").abs(), "2/3", KNumber::FractionType);
+ checkResult("KNumber(\"2.3\").abs()", KNumber("2.3").abs(), "2.3", KNumber::FloatType);
+
+ checkResult("KNumber(-5).abs()", KNumber(-5).abs(), "5", KNumber::IntegerType);
+ checkResult("KNumber(\"-2/3\").abs()", KNumber("-2/3").abs(), "2/3", KNumber::FractionType);
+ checkResult("KNumber(\"-2.3\").abs()", KNumber("-2.3").abs(), "2.3", KNumber::FloatType);
+}
+
+void testingTruncateToInteger(void)
+{
+ std::cout << "\n\nTesting truncate to an integer:\n";
+
+ checkResult("KNumber(16).integerPart()", KNumber(16).integerPart(), "16", KNumber::IntegerType);
+ checkResult("KNumber(\"43/9\").integerPart()", KNumber("43/9").integerPart(), "4", KNumber::IntegerType);
+ checkResult("KNumber(\"-43/9\").integerPart()", KNumber("-43/9").integerPart(), "-4", KNumber::IntegerType);
+ checkResult("KNumber(\"5.25\").integerPart()", KNumber("5.25").integerPart(), "5", KNumber::IntegerType);
+ checkResult("KNumber(\"-5.25\").integerPart()", KNumber("-5.25").integerPart(), "-5", KNumber::IntegerType);
+}
+
+
+void testingSqrt(void)
+{
+ std::cout << "\n\nTesting square root, cubic root:\n";
+
+ checkResult("KNumber(16).sqrt()", KNumber(16).sqrt(), "4", KNumber::IntegerType);
+ checkResult("KNumber(-16).sqrt()", KNumber(-16).sqrt(), "nan", KNumber::SpecialType);
+ checkResult("KNumber(\"16/9\").sqrt()", KNumber("16/9").sqrt(), "4/3", KNumber::FractionType);
+ checkResult("KNumber(\"-16/9\").sqrt()", KNumber("-16/9").sqrt(), "nan", KNumber::SpecialType);
+ checkResult("KNumber(2).sqrt()", KNumber(2).sqrt(), "1.4142136", KNumber::FloatType);
+ checkResult("KNumber(\"2/3\").sqrt()", KNumber("2/3").sqrt(), "0.81649658", KNumber::FloatType);
+ checkResult("KNumber(\"0.25\").sqrt()", KNumber("0.25").sqrt(), "0.5", KNumber::FloatType);
+ checkResult("KNumber(\"-0.25\").sqrt()", KNumber("-0.25").sqrt(), "nan", KNumber::SpecialType);
+
+
+ checkResult("KNumber(27).cbrt()", KNumber(27).cbrt(), "3", KNumber::IntegerType);
+ checkResult("KNumber(-27).cbrt()", KNumber(-27).cbrt(), "-3", KNumber::IntegerType);
+ checkResult("KNumber(\"27/8\").cbrt()", KNumber("27/8").cbrt(), "3/2", KNumber::FractionType);
+ checkResult("KNumber(\"-8/27\").cbrt()", KNumber("-8/27").cbrt(), "-2/3", KNumber::FractionType);
+#warning need to check non-perfect cube roots
+ // checkResult("KNumber(2).cbrt()", KNumber(2).cbrt(), "1.4142136", KNumber::FloatType);
+ // checkResult("KNumber(\"2/3\").cbrt()", KNumber("2/3").cbrt(), "0.81649658", KNumber::FloatType);
+ // checkResult("KNumber(\"0.25\").cbrt()", KNumber("0.25").cbrt(), "0.5", KNumber::FloatType);
+ // checkResult("KNumber(\"-0.25\").cbrt()", KNumber("-0.25").cbrt(), "nan", KNumber::SpecialType);
+
+}
+
+void testingShifts(void)
+{
+ std::cout << "\n\nTesting left/right shift:\n";
+
+ checkResult("KNumber(16) << KNumber(2)", KNumber(16) << KNumber(2), "64", KNumber::IntegerType);
+ checkResult("KNumber(16) >> KNumber(2)", KNumber(16) >> KNumber(2), "4", KNumber::IntegerType);
+
+}
+
+void testingPower(void)
+{
+ std::cout << "\n\nTesting Power:\n";
+
+ checkResult("KNumber(0) ^ KNumber(-4)", KNumber(0).power(KNumber(-4)), "inf", KNumber::SpecialType);
+ checkResult("KNumber(5) ^ KNumber(4)", KNumber(5).power(KNumber(4)), "625", KNumber::IntegerType);
+ checkResult("KNumber(122) ^ KNumber(0)", KNumber(122).power(KNumber(0)), "1", KNumber::IntegerType);
+ checkResult("KNumber(-5) ^ KNumber(0)", KNumber(-5).power(KNumber(0)), "nan", KNumber::SpecialType);
+ checkResult("KNumber(-2) ^ KNumber(3)", KNumber(-2).power(KNumber(3)), "-8", KNumber::IntegerType);
+ checkResult("KNumber(-2) ^ KNumber(4)", KNumber(-2).power(KNumber(4)), "16", KNumber::IntegerType);
+ checkResult("KNumber(5) ^ KNumber(-2)", KNumber(5).power(KNumber(-2)), "1/25", KNumber::FractionType);
+ checkResult("KNumber(8) ^ KNumber(\"2/3\")", KNumber(8).power(KNumber("2/3")), "4", KNumber::IntegerType);
+ checkResult("KNumber(8) ^ KNumber(\"-2/3\")", KNumber(8).power(KNumber("-2/3")), "1/4", KNumber::FractionType);
+ checkResult("KNumber(-16) ^ KNumber(\"1/4\")", KNumber(-16).power(KNumber("1/4")), "nan", KNumber::SpecialType);
+ checkResult("KNumber(-8) ^ KNumber(\"1/3\")", KNumber(-8).power(KNumber("1/3")), "nan", KNumber::SpecialType);
+ checkResult("KNumber(5) ^ KNumber(0.0)", KNumber(5).power(KNumber(0.0)), "1", KNumber::IntegerType);
+ checkResult("KNumber(-5) ^ KNumber(0.0)", KNumber(-5).power(KNumber(0.0)), "nan", KNumber::SpecialType);
+
+ checkResult("KNumber(\"5/3\") ^ KNumber(2)", KNumber("5/3").power(KNumber(2)), "25/9", KNumber::FractionType);
+ checkResult("KNumber(\"5/3\") ^ KNumber(0)", KNumber("5/3").power(KNumber(0)), "1", KNumber::IntegerType);
+ checkResult("KNumber(\"-5/3\") ^ KNumber(0)", KNumber("-5/3").power(KNumber(0)), "nan", KNumber::SpecialType);
+ checkResult("KNumber(\"8/27\") ^ KNumber(\"2/3\")", KNumber("8/27").power(KNumber("2/3")), "4/9", KNumber::FractionType);
+ checkResult("KNumber(\"49/3\") ^ KNumber(\"7/9\")", KNumber("49/3").power(KNumber("7/9")), "21", KNumber::IntegerType);
+ checkResult("KNumber(\"5/2\") ^ KNumber(2.5)", KNumber("5/2").power(KNumber(2.5)), "1", KNumber::FloatType);
+ checkResult("KNumber(\"5/2\") ^ KNumber(0.0)", KNumber("5/2").power(KNumber(0.0)), "inf", KNumber::SpecialType);
+ checkResult("KNumber(\"-5/2\") ^ KNumber(0.0)", KNumber("-5/2").power(KNumber(0.0)), "-inf", KNumber::SpecialType);
+
+ checkResult("KNumber(5.3) ^ KNumber(2)", KNumber(5.3).power(KNumber(2)), "2.65", KNumber::FloatType);
+ checkResult("KNumber(5.3) ^ KNumber(0)", KNumber(5.3).power(KNumber(0)), "inf", KNumber::SpecialType);
+ checkResult("KNumber(-5.3) ^ KNumber(0)", KNumber(-5.3).power(KNumber(0)), "-inf", KNumber::SpecialType);
+ checkResult("KNumber(5.3) ^ KNumber(\"2/3\")", KNumber(5.3).power(KNumber("2/3")), "7.95", KNumber::FloatType);
+ checkResult("KNumber(5.5) ^ KNumber(2.5)", KNumber(5.5).power(KNumber(2.5)), "2.2", KNumber::FloatType);
+ checkResult("KNumber(5.5) ^ KNumber(0.0)", KNumber(5.5).power(KNumber(0.0)), "inf", KNumber::SpecialType);
+ checkResult("KNumber(-5.5) ^ KNumber(0.0)", KNumber(-5.5).power(KNumber(0.0)), "-inf", KNumber::SpecialType);
+}
+
+void testingInfArithmetic(void)
+{
+ std::cout << "\n\nTesting inf/nan-arithmetics:\n";
+
+ KNumber tmp_inf = KNumber("inf");
+ KNumber tmp_mininf = KNumber("-inf");
+ KNumber tmp_nan = KNumber("nan");
+
+ checkResult("inf + KNumber(2)", tmp_inf + KNumber(2), "inf", KNumber::SpecialType);
+ checkResult("KNumber(-5) + inf", KNumber(-5) + tmp_inf, "inf", KNumber::SpecialType);
+ checkResult("inf + KNumber(\"1/2\")", tmp_inf + KNumber("1/2"), "inf", KNumber::SpecialType);
+ checkResult("KNumber(\"-5/3\") + inf", KNumber("-5/3") + tmp_inf, "inf", KNumber::SpecialType);
+ checkResult("inf + KNumber(2.01)", tmp_inf + KNumber(2.01), "inf", KNumber::SpecialType);
+ checkResult("KNumber(-5.4) + inf", KNumber(-5.4) + tmp_inf, "inf", KNumber::SpecialType);
+ checkResult("mininf + KNumber(2)", tmp_mininf + KNumber(2), "-inf", KNumber::SpecialType);
+ checkResult("KNumber(-5) + mininf", KNumber(-5) + tmp_mininf, "-inf", KNumber::SpecialType);
+ checkResult("mininf + KNumber(\"1/2\")", tmp_mininf + KNumber("1/2"), "-inf", KNumber::SpecialType);
+ checkResult("KNumber(\"-5/3\") + mininf", KNumber("-5/3") + tmp_mininf, "-inf", KNumber::SpecialType);
+ checkResult("mininf + KNumber(2.01)", tmp_mininf + KNumber(2.01), "-inf", KNumber::SpecialType);
+ checkResult("KNumber(-5.4) + mininf", KNumber(-5.4) + tmp_mininf, "-inf", KNumber::SpecialType);
+ checkResult("nan + KNumber(2)", tmp_nan + KNumber(2), "nan", KNumber::SpecialType);
+ checkResult("KNumber(-5) + nan", KNumber(-5) + tmp_nan, "nan", KNumber::SpecialType);
+ checkResult("nan + KNumber(\"1/2\")", tmp_nan + KNumber("1/2"), "nan", KNumber::SpecialType);
+ checkResult("KNumber(\"-5/3\") + nan", KNumber("-5/3") + tmp_nan, "nan", KNumber::SpecialType);
+ checkResult("nan + KNumber(2.01)", tmp_nan + KNumber(2.01), "nan", KNumber::SpecialType);
+ checkResult("KNumber(-5.4) + nan", KNumber(-5.4) + tmp_nan, "nan", KNumber::SpecialType);
+ checkResult("inf + inf", tmp_inf + tmp_inf, "inf", KNumber::SpecialType);
+ checkResult("inf + mininf", tmp_inf + tmp_mininf, "nan", KNumber::SpecialType);
+ checkResult("mininf + inf", tmp_mininf + tmp_inf, "nan", KNumber::SpecialType);
+ checkResult("mininf + mininf", tmp_mininf + tmp_mininf, "-inf", KNumber::SpecialType);
+ checkResult("inf + nan", tmp_inf + tmp_nan, "nan", KNumber::SpecialType);
+ checkResult("mininf + nan", tmp_mininf + tmp_nan, "nan", KNumber::SpecialType);
+ checkResult("nan + inf", tmp_nan + tmp_inf, "nan", KNumber::SpecialType);
+ checkResult("mininf + nan", tmp_mininf + tmp_nan, "nan", KNumber::SpecialType);
+
+
+ checkResult("inf - KNumber(2)", tmp_inf - KNumber(2), "inf", KNumber::SpecialType);
+ checkResult("KNumber(-5) - inf", KNumber(-5) - tmp_inf, "-inf", KNumber::SpecialType);
+ checkResult("inf - KNumber(\"1/2\")", tmp_inf - KNumber("1/2"), "inf", KNumber::SpecialType);
+ checkResult("KNumber(\"-5/3\") - inf", KNumber("-5/3") - tmp_inf, "-inf", KNumber::SpecialType);
+ checkResult("inf - KNumber(2.01)", tmp_inf - KNumber(2.01), "inf", KNumber::SpecialType);
+ checkResult("KNumber(-5.4) - inf", KNumber(-5.4) - tmp_inf, "-inf", KNumber::SpecialType);
+ checkResult("mininf - KNumber(2)", tmp_mininf - KNumber(2), "-inf", KNumber::SpecialType);
+ checkResult("KNumber(-5) - mininf", KNumber(-5) - tmp_mininf, "inf", KNumber::SpecialType);
+ checkResult("mininf - KNumber(\"1/2\")", tmp_mininf - KNumber("1/2"), "-inf", KNumber::SpecialType);
+ checkResult("KNumber(\"-5/3\") - mininf", KNumber("-5/3") - tmp_mininf, "inf", KNumber::SpecialType);
+ checkResult("mininf - KNumber(2.01)", tmp_mininf - KNumber(2.01), "-inf", KNumber::SpecialType);
+ checkResult("KNumber(-5.4) - mininf", KNumber(-5.4) - tmp_mininf, "inf", KNumber::SpecialType);
+ checkResult("nan - KNumber(2)", tmp_nan - KNumber(2), "nan", KNumber::SpecialType);
+ checkResult("KNumber(-5) - nan", KNumber(-5) - tmp_nan, "nan", KNumber::SpecialType);
+ checkResult("nan - KNumber(\"1/2\")", tmp_nan - KNumber("1/2"), "nan", KNumber::SpecialType);
+ checkResult("KNumber(\"-5/3\") - nan", KNumber("-5/3") - tmp_nan, "nan", KNumber::SpecialType);
+ checkResult("nan - KNumber(2.01)", tmp_nan - KNumber(2.01), "nan", KNumber::SpecialType);
+ checkResult("KNumber(-5.4) - nan", KNumber(-5.4) - tmp_nan, "nan", KNumber::SpecialType);
+ checkResult("inf - inf", tmp_inf - tmp_inf, "nan", KNumber::SpecialType);
+ checkResult("inf - mininf", tmp_inf - tmp_mininf, "inf", KNumber::SpecialType);
+ checkResult("mininf - inf", tmp_mininf - tmp_inf, "-inf", KNumber::SpecialType);
+ checkResult("mininf - mininf", tmp_mininf - tmp_mininf, "nan", KNumber::SpecialType);
+ checkResult("inf - nan", tmp_inf - tmp_nan, "nan", KNumber::SpecialType);
+ checkResult("mininf - nan", tmp_mininf - tmp_nan, "nan", KNumber::SpecialType);
+ checkResult("nan - inf", tmp_nan - tmp_inf, "nan", KNumber::SpecialType);
+ checkResult("mininf - nan", tmp_mininf - tmp_nan, "nan", KNumber::SpecialType);
+
+
+ checkResult("inf * KNumber(2)", tmp_inf * KNumber(2), "inf", KNumber::SpecialType);
+ checkResult("KNumber(-5) * inf", KNumber(-5) * tmp_inf, "-inf", KNumber::SpecialType);
+ checkResult("inf * KNumber(\"1/2\")", tmp_inf * KNumber("1/2"), "inf", KNumber::SpecialType);
+ checkResult("KNumber(\"-5/3\") * inf", KNumber("-5/3") * tmp_inf, "-inf", KNumber::SpecialType);
+ checkResult("inf * KNumber(2.01)", tmp_inf * KNumber(2.01), "inf", KNumber::SpecialType);
+ checkResult("KNumber(-5.4) * inf", KNumber(-5.4) * tmp_inf, "-inf", KNumber::SpecialType);
+ checkResult("mininf * KNumber(2)", tmp_mininf * KNumber(2), "-inf", KNumber::SpecialType);
+ checkResult("KNumber(-5) * mininf", KNumber(-5) * tmp_mininf, "inf", KNumber::SpecialType);
+ checkResult("mininf * KNumber(\"1/2\")", tmp_mininf * KNumber("1/2"), "-inf", KNumber::SpecialType);
+ checkResult("KNumber(\"-5/3\") * mininf", KNumber("-5/3") * tmp_mininf, "inf", KNumber::SpecialType);
+ checkResult("mininf * KNumber(2.01)", tmp_mininf * KNumber(2.01), "-inf", KNumber::SpecialType);
+ checkResult("KNumber(-5.4) * mininf", KNumber(-5.4) * tmp_mininf, "inf", KNumber::SpecialType);
+ checkResult("nan * KNumber(2)", tmp_nan * KNumber(2), "nan", KNumber::SpecialType);
+ checkResult("KNumber(-5) * nan", KNumber(-5) * tmp_nan, "nan", KNumber::SpecialType);
+ checkResult("nan * KNumber(\"1/2\")", tmp_nan * KNumber("1/2"), "nan", KNumber::SpecialType);
+ checkResult("KNumber(\"-5/3\") * nan", KNumber("-5/3") * tmp_nan, "nan", KNumber::SpecialType);
+ checkResult("nan * KNumber(2.01)", tmp_nan * KNumber(2.01), "nan", KNumber::SpecialType);
+ checkResult("KNumber(-5.4) * nan", KNumber(-5.4) * tmp_nan, "nan", KNumber::SpecialType);
+ checkResult("inf * inf", tmp_inf * tmp_inf, "inf", KNumber::SpecialType);
+ checkResult("inf * mininf", tmp_inf * tmp_mininf, "-inf", KNumber::SpecialType);
+ checkResult("mininf * inf", tmp_mininf * tmp_inf, "-inf", KNumber::SpecialType);
+ checkResult("mininf * mininf", tmp_mininf * tmp_mininf, "inf", KNumber::SpecialType);
+ checkResult("inf * nan", tmp_inf * tmp_nan, "nan", KNumber::SpecialType);
+ checkResult("mininf * nan", tmp_mininf * tmp_nan, "nan", KNumber::SpecialType);
+ checkResult("nan * inf", tmp_nan * tmp_inf, "nan", KNumber::SpecialType);
+ checkResult("mininf * nan", tmp_mininf * tmp_nan, "nan", KNumber::SpecialType);
+ checkResult("KNumber(0) * inf", KNumber(0) * tmp_inf, "nan", KNumber::SpecialType);
+ checkResult("KNumber(0) * mininf", KNumber(0) * tmp_mininf, "nan", KNumber::SpecialType);
+ checkResult("inf * KNumber(0)", tmp_inf * KNumber(0), "nan", KNumber::SpecialType);
+ checkResult("mininf * KNumber(0)", tmp_mininf * KNumber(0), "nan", KNumber::SpecialType);
+ checkResult("KNumber(0.0) * inf", KNumber(0.0) * tmp_inf, "nan", KNumber::SpecialType);
+ checkResult("KNumber(0.0) * mininf", KNumber(0.0) * tmp_mininf, "nan", KNumber::SpecialType);
+ checkResult("inf * KNumber(0.0)", tmp_inf * KNumber(0.0), "nan", KNumber::SpecialType);
+ checkResult("mininf * KNumber(0.0)", tmp_mininf * KNumber(0.0), "nan", KNumber::SpecialType);
+
+
+ checkResult("inf / KNumber(2)", tmp_inf / KNumber(2), "inf", KNumber::SpecialType);
+ checkResult("KNumber(-5) / inf", KNumber(-5) / tmp_inf, "0", KNumber::IntegerType);
+ checkResult("inf / KNumber(\"1/2\")", tmp_inf / KNumber("1/2"), "inf", KNumber::SpecialType);
+ checkResult("KNumber(\"-5/3\") / inf", KNumber("-5/3") / tmp_inf, "0", KNumber::IntegerType);
+ checkResult("inf / KNumber(2.01)", tmp_inf / KNumber(2.01), "inf", KNumber::SpecialType);
+ checkResult("KNumber(-5.4) / inf", KNumber(-5.4) / tmp_inf, "0", KNumber::IntegerType);
+ checkResult("mininf / KNumber(2)", tmp_mininf / KNumber(2), "-inf", KNumber::SpecialType);
+ checkResult("KNumber(-5) / mininf", KNumber(-5) / tmp_mininf, "0", KNumber::IntegerType);
+ checkResult("mininf / KNumber(\"1/2\")", tmp_mininf / KNumber("1/2"), "-inf", KNumber::SpecialType);
+ checkResult("KNumber(\"-5/3\") / mininf", KNumber("-5/3") / tmp_mininf, "0", KNumber::IntegerType);
+ checkResult("mininf / KNumber(2.01)", tmp_mininf / KNumber(2.01), "-inf", KNumber::SpecialType);
+ checkResult("KNumber(-5.4) / mininf", KNumber(-5.4) / tmp_mininf, "0", KNumber::IntegerType);
+ checkResult("nan / KNumber(2)", tmp_nan / KNumber(2), "nan", KNumber::SpecialType);
+ checkResult("KNumber(-5) / nan", KNumber(-5) / tmp_nan, "nan", KNumber::SpecialType);
+ checkResult("nan / KNumber(\"1/2\")", tmp_nan / KNumber("1/2"), "nan", KNumber::SpecialType);
+ checkResult("KNumber(\"-5/3\") / nan", KNumber("-5/3") / tmp_nan, "nan", KNumber::SpecialType);
+ checkResult("nan / KNumber(2.01)", tmp_nan / KNumber(2.01), "nan", KNumber::SpecialType);
+ checkResult("KNumber(-5.4) / nan", KNumber(-5.4) / tmp_nan, "nan", KNumber::SpecialType);
+ checkResult("inf / inf", tmp_inf / tmp_inf, "nan", KNumber::SpecialType);
+ checkResult("inf / mininf", tmp_inf / tmp_mininf, "nan", KNumber::SpecialType);
+ checkResult("mininf / inf", tmp_mininf / tmp_inf, "nan", KNumber::SpecialType);
+ checkResult("mininf / mininf", tmp_mininf / tmp_mininf, "nan", KNumber::SpecialType);
+ checkResult("inf / nan", tmp_inf / tmp_nan, "nan", KNumber::SpecialType);
+ checkResult("mininf / nan", tmp_mininf / tmp_nan, "nan", KNumber::SpecialType);
+ checkResult("nan / inf", tmp_nan / tmp_inf, "nan", KNumber::SpecialType);
+ checkResult("mininf / nan", tmp_mininf / tmp_nan, "nan", KNumber::SpecialType);
+ checkResult("KNumber(0) / inf", KNumber(0) / tmp_inf, "0", KNumber::IntegerType);
+ checkResult("KNumber(0) / mininf", KNumber(0) / tmp_mininf, "0", KNumber::IntegerType);
+ checkResult("inf / KNumber(0)", tmp_inf / KNumber(0), "inf", KNumber::SpecialType);
+ checkResult("mininf / KNumber(0)", tmp_mininf / KNumber(0), "-inf", KNumber::SpecialType);
+ checkResult("KNumber(0.0) / inf", KNumber(0.0) / tmp_inf, "0", KNumber::IntegerType);
+ checkResult("KNumber(0.0) / mininf", KNumber(0.0) / tmp_mininf, "0", KNumber::IntegerType);
+ checkResult("inf / KNumber(0.0)", tmp_inf / KNumber(0.0), "inf", KNumber::SpecialType);
+ checkResult("mininf / KNumber(0.0)", tmp_mininf / KNumber(0.0), "-inf", KNumber::SpecialType);
+}
+
+void testingFloatPrecision(void)
+{
+ KNumber::setDefaultFloatPrecision(100);
+ checkResult("Precision >= 100: (KNumber(1) + KNumber(\"1e-80\")) - KNumber(1)",
+ (KNumber(1) + KNumber("1e-80")) - KNumber(1), "1e-80", KNumber::FloatType);
+ checkResult("Precision >= 100: (KNumber(1) + KNumber(\"1e-980\")) - KNumber(1)",
+ (KNumber(1) + KNumber("1e-980")) - KNumber(1), "0", KNumber::FloatType);
+
+ KNumber::setDefaultFloatPrecision(1000);
+ checkResult("Precision >= 1000: (KNumber(1) + KNumber(\"1e-980\")) - KNumber(1)",
+ (KNumber(1) + KNumber("1e-980")) - KNumber(1), "1e-980", KNumber::FloatType);
+
+}
+
+void testingOutput(void)
+{
+ KNumber::setDefaultFloatOutput(false);
+ checkResult("Fractional output: KNumber(\"1/4\")", KNumber("1/4"), "1/4", KNumber::FractionType);
+ KNumber::setDefaultFloatOutput(true);
+ checkResult("Float: KNumber(\"1/4\")", KNumber("1/4"), "0.25", KNumber::FractionType);
+ KNumber::setDefaultFloatOutput(false);
+ KNumber::setSplitoffIntegerForFractionOutput(true);
+ checkResult("Fractional output: KNumber(\"1/4\")", KNumber("1/4"), "1/4", KNumber::FractionType);
+ checkResult("Fractional output: KNumber(\"-1/4\")", KNumber("-1/4"), "-1/4", KNumber::FractionType);
+ checkResult("Fractional output: KNumber(\"21/4\")", KNumber("21/4"), "5 1/4", KNumber::FractionType);
+ checkResult("Fractional output: KNumber(\"-21/4\")", KNumber("-21/4"), "-5 1/4", KNumber::FractionType);
+ KNumber::setSplitoffIntegerForFractionOutput(false);
+ checkResult("Fractional output: KNumber(\"1/4\")", KNumber("1/4"), "1/4", KNumber::FractionType);
+ checkResult("Fractional output: KNumber(\"-1/4\")", KNumber("-1/4"), "-1/4", KNumber::FractionType);
+ checkResult("Fractional output: KNumber(\"21/4\")", KNumber("21/4"), "21/4", KNumber::FractionType);
+ checkResult("Fractional output: KNumber(\"-21/4\")", KNumber("-21/4"), "-21/4", KNumber::FractionType);
+}
+
+
+int main(void)
+{
+ std::cout << "Testing Constructors:\n";
+
+ checkResult("KNumber(5)", KNumber(5), "5", KNumber::IntegerType);
+ checkType("KNumber(5.3)", KNumber(5.3).type(), KNumber::FloatType);
+ checkType("KNumber(0.0)", KNumber(0.0).type(), KNumber::FloatType);
+
+ checkResult("KNumber(\"5\")", KNumber("5"), "5", KNumber::IntegerType);
+ checkResult("KNumber(\"5/3\")", KNumber("5/3"), "5/3", KNumber::FractionType);
+ checkResult("KNumber(\"5/1\")", KNumber("5/1"), "5", KNumber::IntegerType);
+ checkResult("KNumber(\"0/12\")", KNumber("0/12"), "0", KNumber::IntegerType);
+ KNumber::setDefaultFractionalInput(true);
+ std::cout << "Read decimals as fractions:\n";
+ checkResult("KNumber(\"5\")", KNumber("5"), "5", KNumber::IntegerType);
+ checkResult("KNumber(\"1.2\")", KNumber("1.2"), "6/5", KNumber::FractionType);
+ checkResult("KNumber(\"-0.02\")", KNumber("-0.02"), "-1/50", KNumber::FractionType);
+ checkResult("KNumber(\"5e-2\")", KNumber("5e-2"), "1/20", KNumber::FractionType);
+ checkResult("KNumber(\"1.2e3\")", KNumber("1.2e3"), "1200", KNumber::IntegerType);
+ checkResult("KNumber(\"0.02e+1\")", KNumber("0.02e+1"), "1/5", KNumber::FractionType);
+
+ KNumber::setDefaultFractionalInput(false);
+ std::cout << "Read decimals as floats:\n";
+ checkResult("KNumber(\"5.3\")", KNumber("5.3"), "5.3", KNumber::FloatType);
+
+ checkResult("KNumber(\"nan\")", KNumber("nan"), "nan", KNumber::SpecialType);
+ checkResult("KNumber(\"inf\")", KNumber("inf"), "inf", KNumber::SpecialType);
+ checkResult("KNumber(\"-inf\")", KNumber("-inf"), "-inf", KNumber::SpecialType);
+
+ std::cout << "\n\nConstants:\n";
+
+ checkType("KNumber::Zero", KNumber::Zero.type(), KNumber::IntegerType);
+ checkType("KNumber::One", KNumber::One.type(), KNumber::IntegerType);
+ checkType("KNumber::MinusOne", KNumber::MinusOne.type(), KNumber::IntegerType);
+ checkType("KNumber::Pi", KNumber::Pi.type(), KNumber::FloatType);
+
+ testingCompare();
+
+ testingAdditions();
+ testingSubtractions();
+ testingMultiplications();
+ testingDivisions();
+
+ testingAndOr();
+ testingModulus();
+
+ testingAbs();
+ testingSqrt();
+ //testingPower();
+ testingTruncateToInteger();
+
+ testingShifts();
+
+ testingInfArithmetic();
+
+ testingFloatPrecision();
+
+ testingOutput();
+
+ return 0;
+}
+
+
diff --git a/kcalc/knumber/tests/knumbertest.h b/kcalc/knumber/tests/knumbertest.h
new file mode 100644
index 0000000..b93dc4a
--- /dev/null
+++ b/kcalc/knumber/tests/knumbertest.h
@@ -0,0 +1,9 @@
+#ifndef KNUMBERTEST_H
+#define KNUMBERTEST_H
+
+#include "knumber.h"
+
+/** test: a small test program for KNumber
+ */
+
+#endif // KNUMBERTEST_H