diff --git a/.codecov.yml b/.codecov.yml index cbb62bff12..c229399926 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -2,7 +2,6 @@ coverage: precision: 2 ignore: - - "include/geos/algorithm/ttmath" - "tests/unit/tut" - "tests/xmltester/tinyxml2" diff --git a/Makefile.am b/Makefile.am index dbc745146a..f064d45da9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -73,5 +73,4 @@ valgrindcheck: check-local: ! find $(srcdir) -name '*.cpp' -o -name '*.h' | \ grep -v tests/xmltester/tinyxml | \ - grep -v include/geos/algorithm/ttmath | \ xargs grep -n '[[:space:]]$$' diff --git a/configure.ac b/configure.ac index 7c54d75ef8..1eade62f5e 100644 --- a/configure.ac +++ b/configure.ac @@ -376,7 +376,6 @@ AC_OUTPUT([ include/geos/algorithm/Makefile include/geos/algorithm/locate/Makefile include/geos/algorithm/distance/Makefile - include/geos/algorithm/ttmath/Makefile include/geos/geom/Makefile include/geos/geom/prep/Makefile include/geos/geom/util/Makefile @@ -391,6 +390,7 @@ AC_OUTPUT([ include/geos/index/sweepline/Makefile include/geos/io/Makefile include/geos/linearref/Makefile + include/geos/math/Makefile include/geos/noding/Makefile include/geos/noding/snapround/Makefile include/geos/operation/Makefile @@ -423,6 +423,7 @@ AC_OUTPUT([ src/index/sweepline/Makefile src/io/Makefile src/linearref/Makefile + src/math/Makefile src/noding/Makefile src/noding/snapround/Makefile src/operation/Makefile diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index 6490c2c8a6..0f9d70bacd 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -853,7 +853,6 @@ EXCLUDE_PATTERNS = */examples/* \ */test/* \ */bigtest/* \ */io/markup/* \ - */ttmath/* \ config.h \ acconfig.h \ CoordinateList.cpp \ diff --git a/include/geos/Makefile.am b/include/geos/Makefile.am index 363494cf5e..e34f56d5ee 100644 --- a/include/geos/Makefile.am +++ b/include/geos/Makefile.am @@ -8,6 +8,7 @@ SUBDIRS = \ index \ io \ linearref \ + math \ noding \ operation \ planargraph \ diff --git a/include/geos/algorithm/CGAlgorithmsDD.h b/include/geos/algorithm/CGAlgorithmsDD.h index f596466cd2..583532c147 100644 --- a/include/geos/algorithm/CGAlgorithmsDD.h +++ b/include/geos/algorithm/CGAlgorithmsDD.h @@ -19,17 +19,7 @@ #ifndef GEOS_ALGORITHM_CGALGORITHMDD_H #define GEOS_ALGORITHM_CGALGORITHMDD_H #include -#include - -/// \file CGAlgorithmsDD.h - -/// \brief Close to DoubleDouble equivalent used by JTS -/// -/// Usage: `ttmath::Big` -typedef ttmath::Big DD; -//typedef ttmath::Big DD; -//typedef ttmath::Big DD; -//typedef ttmath::Big DD; +#include // Forward declarations namespace geos { @@ -39,6 +29,8 @@ class CoordinateSequence; } } +using namespace geos::math; + namespace geos { namespace algorithm { // geos::algorithm @@ -139,7 +131,7 @@ class GEOS_DLL CGAlgorithmsDD { * The circumcentre does not necessarily lie within the triangle. For example, * the circumcentre of an obtuse isosceles triangle lies outside the triangle. * - * This method uses @ref DD extended-precision arithmetic to provide more accurate + * This method uses @ref geos::math::DD extended-precision arithmetic to provide more accurate * results than [circumcentre(Coordinate, Coordinate, Coordinate)] * (@ref geos::geom::Triangle::circumcentre(const Coordinate& p0, const Coordinate& p1, const Coordinate& p2)). * diff --git a/include/geos/algorithm/Makefile.am b/include/geos/algorithm/Makefile.am index 717e63d883..dbd5a619ca 100644 --- a/include/geos/algorithm/Makefile.am +++ b/include/geos/algorithm/Makefile.am @@ -3,8 +3,7 @@ # SUBDIRS = \ locate \ - distance \ - ttmath + distance EXTRA_DIST = diff --git a/include/geos/algorithm/RayCrossingCounterDD.h b/include/geos/algorithm/RayCrossingCounterDD.h index 2328ab3e44..d7ba41e30b 100644 --- a/include/geos/algorithm/RayCrossingCounterDD.h +++ b/include/geos/algorithm/RayCrossingCounterDD.h @@ -22,7 +22,6 @@ #include #include -#include #include diff --git a/include/geos/algorithm/ttmath/COPYRIGHT b/include/geos/algorithm/ttmath/COPYRIGHT deleted file mode 100644 index 3111d0b88c..0000000000 --- a/include/geos/algorithm/ttmath/COPYRIGHT +++ /dev/null @@ -1,28 +0,0 @@ -Copyright (c) 2006-2017, Tomasz Sowa -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - * Neither the name Tomasz Sowa nor the names of contributors to this - project may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -THE POSSIBILITY OF SUCH DAMAGE. diff --git a/include/geos/algorithm/ttmath/Makefile.am b/include/geos/algorithm/ttmath/Makefile.am deleted file mode 100644 index e60a3bf68d..0000000000 --- a/include/geos/algorithm/ttmath/Makefile.am +++ /dev/null @@ -1,24 +0,0 @@ -# -# This file is part of project GEOS (http://trac.osgeo.org/geos/) -# -SUBDIRS = - -EXTRA_DIST = - -geosdir = $(includedir)/geos/algorithm/ttmath - -geos_HEADERS = \ - ttmath.h \ - ttmathbig.h \ - ttmathdec.h \ - ttmathint.h \ - ttmathmisc.h \ - ttmathobjects.h \ - ttmathparser.h \ - ttmaththreads.h \ - ttmathtypes.h \ - ttmathuint.h \ - ttmathuint_noasm.h \ - ttmathuint_x86.h \ - ttmathuint_x86_64.h \ - ttmathuint_x86_64_msvc.asm diff --git a/include/geos/algorithm/ttmath/README b/include/geos/algorithm/ttmath/README deleted file mode 100644 index ea5bc1c502..0000000000 --- a/include/geos/algorithm/ttmath/README +++ /dev/null @@ -1,23 +0,0 @@ -A bignum library for C++ - -TTMath is a small library which allows one to perform arithmetic operations -with big unsigned integer, big signed integer and big floating point numbers. -It provides standard mathematical operations like adding, subtracting, -multiplying, dividing. With the library also goes a mathematical parser to -help you solving mathematical expressions. - -TTMath is developed under the BSD licence which means that it is free for -both personal and commercial use. - -The main goal of the library is to allow one to use big values in the same -way as the standard types like int or float. It does not need to be compiled -first because the whole library is written as the C++ templates. This means -only C++ developers can use this library and one thing they have to do is -to use 'include' directive of the preprocessor. How big the values can be -is set at compile time. - -Author: Tomasz Sowa -WWW: http://www.ttmath.org - -Contributors: -Christian Kaiser diff --git a/include/geos/algorithm/ttmath/ttmath.h b/include/geos/algorithm/ttmath/ttmath.h deleted file mode 100644 index 94630a7bc1..0000000000 --- a/include/geos/algorithm/ttmath/ttmath.h +++ /dev/null @@ -1,2880 +0,0 @@ -/* - * This file is a part of TTMath Bignum Library - * and is distributed under the 3-Clause BSD Licence. - * Author: Tomasz Sowa - */ - -/* - * Copyright (c) 2006-2017, Tomasz Sowa - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * * Neither the name Tomasz Sowa nor the names of contributors to this - * project may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#ifndef headerfilettmathmathtt -#define headerfilettmathmathtt - -/*! - \file ttmath.h - \brief Mathematics functions. -*/ - -#ifdef _MSC_VER -//warning C4127: conditional expression is constant -#pragma warning( disable: 4127 ) -//warning C4702: unreachable code -#pragma warning( disable: 4702 ) -//warning C4800: forcing value to bool 'true' or 'false' (performance warning) -#pragma warning( disable: 4800 ) -#endif - - -#include "ttmathbig.h" -#include "ttmathobjects.h" - - -namespace ttmath -{ - /* - * - * functions defined here are used only with Big<> types - * - * - */ - - - /* - * - * functions for rounding - * - * - */ - - - /*! - this function skips the fraction from x - - samples - - 2.2 = 2 - - 2.7 = 2 - - -2.2 = 2 - - -2.7 = 2 - */ - template - ValueType SkipFraction(const ValueType & x) - { - ValueType result( x ); - result.SkipFraction(); - - return result; - } - - - /*! - this function rounds to the nearest integer value - - samples - - 2.2 = 2 - - 2.7 = 3 - - -2.2 = -2 - - -2.7 = -3 - */ - template - ValueType Round(const ValueType & x, ErrorCode * err = 0) - { - if( x.IsNan() ) - { - if( err ) - *err = err_improper_argument; - - return x; // NaN - } - - ValueType result( x ); - uint c = result.Round(); - - if( err ) - *err = c ? err_overflow : err_ok; - - return result; - } - - - - /*! - this function returns a value representing the smallest integer - that is greater than or equal to x - - - Ceil(-3.7) = -3 - - Ceil(-3.1) = -3 - - Ceil(-3.0) = -3 - - Ceil(4.0) = 4 - - Ceil(4.2) = 5 - - Ceil(4.8) = 5 - */ - template - ValueType Ceil(const ValueType & x, ErrorCode * err = 0) - { - if( x.IsNan() ) - { - if( err ) - *err = err_improper_argument; - - return x; // NaN - } - - ValueType result(x); - uint c = 0; - - result.SkipFraction(); - - if( result != x ) - { - // x is with fraction - // if x is negative we don't have to do anything - if( !x.IsSign() ) - { - ValueType one; - one.SetOne(); - - c += result.Add(one); - } - } - - if( err ) - *err = c ? err_overflow : err_ok; - - return result; - } - - - /*! - this function returns a value representing the largest integer - that is less than or equal to x - - - Floor(-3.6) = -4 - - Floor(-3.1) = -4 - - Floor(-3) = -3 - - Floor(2) = 2 - - Floor(2.3) = 2 - - Floor(2.8) = 2 - */ - template - ValueType Floor(const ValueType & x, ErrorCode * err = 0) - { - if( x.IsNan() ) - { - if( err ) - *err = err_improper_argument; - - return x; // NaN - } - - ValueType result(x); - uint c = 0; - - result.SkipFraction(); - - if( result != x ) - { - // x is with fraction - // if x is positive we don't have to do anything - if( x.IsSign() ) - { - ValueType one; - one.SetOne(); - - c += result.Sub(one); - } - } - - if( err ) - *err = c ? err_overflow : err_ok; - - return result; - } - - - - /* - * - * logarithms and the exponent - * - * - */ - - - /*! - this function calculates the natural logarithm (logarithm with the base 'e') - */ - template - ValueType Ln(const ValueType & x, ErrorCode * err = 0) - { - if( x.IsNan() ) - { - if( err ) - *err = err_improper_argument; - - return x; // NaN - } - - ValueType result; - uint state = result.Ln(x); - - if( err ) - { - switch( state ) - { - case 0: - *err = err_ok; - break; - case 1: - *err = err_overflow; - break; - case 2: - *err = err_improper_argument; - break; - default: - *err = err_internal_error; - break; - } - } - - - return result; - } - - - /*! - this function calculates the logarithm - */ - template - ValueType Log(const ValueType & x, const ValueType & base, ErrorCode * err = 0) - { - if( x.IsNan() ) - { - if( err ) *err = err_improper_argument; - return x; - } - - if( base.IsNan() ) - { - if( err ) *err = err_improper_argument; - return base; - } - - ValueType result; - uint state = result.Log(x, base); - - if( err ) - { - switch( state ) - { - case 0: - *err = err_ok; - break; - case 1: - *err = err_overflow; - break; - case 2: - case 3: - *err = err_improper_argument; - break; - default: - *err = err_internal_error; - break; - } - } - - return result; - } - - - /*! - this function calculates the expression e^x - */ - template - ValueType Exp(const ValueType & x, ErrorCode * err = 0) - { - if( x.IsNan() ) - { - if( err ) - *err = err_improper_argument; - - return x; // NaN - } - - ValueType result; - uint c = result.Exp(x); - - if( err ) - *err = c ? err_overflow : err_ok; - - return result; - } - - - /*! - * - * trigonometric functions - * - */ - - - /* - this namespace consists of auxiliary functions - (something like 'private' in a class) - - this is excluded from doxygen documentation - (option EXCLUDE_SYMBOLS in doxygen.cfg) - */ - namespace auxiliaryfunctions - { - - /*! - an auxiliary function for calculating the Sine - (you don't have to call this function) - */ - template - uint PrepareSin(ValueType & x, bool & change_sign) - { - ValueType temp; - - change_sign = false; - - if( x.IsSign() ) - { - // we're using the formula 'sin(-x) = -sin(x)' - change_sign = !change_sign; - x.ChangeSign(); - } - - // we're reducing the period 2*PI - // (for big values there'll always be zero) - temp.Set2Pi(); - - if( x.Mod(temp) ) - return 1; - - - // we're setting 'x' as being in the range of <0, 0.5PI> - - temp.SetPi(); - - if( x > temp ) - { - // x is in (pi, 2*pi> - x.Sub( temp ); - change_sign = !change_sign; - } - - temp.Set05Pi(); - - if( x > temp ) - { - // x is in (0.5pi, pi> - x.Sub( temp ); - x = temp - x; - } - - return 0; - } - - - /*! - an auxiliary function for calculating the Sine - (you don't have to call this function) - - it returns Sin(x) where 'x' is from <0, PI/2> - we're calculating the Sin with using Taylor series in zero or PI/2 - (depending on which point of these two points is nearer to the 'x') - - Taylor series: - sin(x) = sin(a) + cos(a)*(x-a)/(1!) - - sin(a)*((x-a)^2)/(2!) - cos(a)*((x-a)^3)/(3!) - + sin(a)*((x-a)^4)/(4!) + ... - - when a=0 it'll be: - sin(x) = (x)/(1!) - (x^3)/(3!) + (x^5)/(5!) - (x^7)/(7!) + (x^9)/(9!) ... - - and when a=PI/2: - sin(x) = 1 - ((x-PI/2)^2)/(2!) + ((x-PI/2)^4)/(4!) - ((x-PI/2)^6)/(6!) ... - */ - template - ValueType Sin0pi05(const ValueType & x) - { - ValueType result; - ValueType numerator, denominator; - ValueType d_numerator, d_denominator; - ValueType one, temp, old_result; - - // temp = pi/4 - temp.Set05Pi(); - temp.exponent.SubOne(); - - one.SetOne(); - - if( x < temp ) - { - // we're using the Taylor series with a=0 - result = x; - numerator = x; - denominator = one; - - // d_numerator = x^2 - d_numerator = x; - d_numerator.Mul(x); - - d_denominator = 2; - } - else - { - // we're using the Taylor series with a=PI/2 - result = one; - numerator = one; - denominator = one; - - // d_numerator = (x-pi/2)^2 - ValueType pi05; - pi05.Set05Pi(); - - temp = x; - temp.Sub( pi05 ); - d_numerator = temp; - d_numerator.Mul( temp ); - - d_denominator = one; - } - - uint c = 0; - bool addition = false; - - old_result = result; - for(uint i=1 ; i<=TTMATH_ARITHMETIC_MAX_LOOP ; ++i) - { - // we're starting from a second part of the formula - c += numerator. Mul( d_numerator ); - c += denominator. Mul( d_denominator ); - c += d_denominator.Add( one ); - c += denominator. Mul( d_denominator ); - c += d_denominator.Add( one ); - temp = numerator; - c += temp.Div(denominator); - - if( c ) - // Sin is from <-1,1> and cannot make an overflow - // but the carry can be from the Taylor series - // (then we only break our calculations) - break; - - if( addition ) - result.Add( temp ); - else - result.Sub( temp ); - - - addition = !addition; - - // we're testing whether the result has changed after adding - // the next part of the Taylor formula, if not we end the loop - // (it means 'x' is zero or 'x' is PI/2 or this part of the formula - // is too small) - if( result == old_result ) - break; - - old_result = result; - } - - return result; - } - - } // namespace auxiliaryfunctions - - - - /*! - this function calculates the Sine - */ - template - ValueType Sin(ValueType x, ErrorCode * err = 0) - { - using namespace auxiliaryfunctions; - - ValueType one, result; - bool change_sign; - - if( x.IsNan() ) - { - if( err ) - *err = err_improper_argument; - - return x; - } - - if( err ) - *err = err_ok; - - if( PrepareSin( x, change_sign ) ) - { - // x is too big, we cannnot reduce the 2*PI period - // prior to version 0.8.5 the result was zero - - // result has NaN flag set by default - - if( err ) - *err = err_overflow; // maybe another error code? err_improper_argument? - - return result; // NaN is set by default - } - - result = Sin0pi05( x ); - - one.SetOne(); - - // after calculations there can be small distortions in the result - if( result > one ) - result = one; - else - if( result.IsSign() ) - // we've calculated the sin from <0, pi/2> and the result - // should be positive - result.SetZero(); - - if( change_sign ) - result.ChangeSign(); - - return result; - } - - - /*! - this function calulates the Cosine - we're using the formula cos(x) = sin(x + PI/2) - */ - template - ValueType Cos(ValueType x, ErrorCode * err = 0) - { - if( x.IsNan() ) - { - if( err ) - *err = err_improper_argument; - - return x; // NaN - } - - ValueType pi05; - pi05.Set05Pi(); - - uint c = x.Add( pi05 ); - - if( c ) - { - if( err ) - *err = err_overflow; - - return ValueType(); // result is undefined (NaN is set by default) - } - - return Sin(x, err); - } - - - /*! - this function calulates the Tangent - we're using the formula tan(x) = sin(x) / cos(x) - - it takes more time than calculating the Tan directly - from for example Taylor series but should be a bit preciser - because Tan receives its values from -infinity to +infinity - and when we calculate it from any series then we can make - a greater mistake than calculating 'sin/cos' - */ - template - ValueType Tan(const ValueType & x, ErrorCode * err = 0) - { - ValueType result = Cos(x, err); - - if( err && *err != err_ok ) - return result; - - if( result.IsZero() ) - { - if( err ) - *err = err_improper_argument; - - result.SetNan(); - - return result; - } - - return Sin(x, err) / result; - } - - - /*! - this function calulates the Tangent - look at the description of Tan(...) - - (the abbreviation of Tangent can be 'tg' as well) - */ - template - ValueType Tg(const ValueType & x, ErrorCode * err = 0) - { - return Tan(x, err); - } - - - /*! - this function calulates the Cotangent - we're using the formula tan(x) = cos(x) / sin(x) - - (why do we make it in this way? - look at information in Tan() function) - */ - template - ValueType Cot(const ValueType & x, ErrorCode * err = 0) - { - ValueType result = Sin(x, err); - - if( err && *err != err_ok ) - return result; - - if( result.IsZero() ) - { - if( err ) - *err = err_improper_argument; - - result.SetNan(); - - return result; - } - - return Cos(x, err) / result; - } - - - /*! - this function calulates the Cotangent - look at the description of Cot(...) - - (the abbreviation of Cotangent can be 'ctg' as well) - */ - template - ValueType Ctg(const ValueType & x, ErrorCode * err = 0) - { - return Cot(x, err); - } - - - /* - * - * inverse trigonometric functions - * - * - */ - - namespace auxiliaryfunctions - { - - /*! - an auxiliary function for calculating the Arc Sine - - we're calculating asin from the following formula: - asin(x) = x + (1*x^3)/(2*3) + (1*3*x^5)/(2*4*5) + (1*3*5*x^7)/(2*4*6*7) + ... - where abs(x) <= 1 - - we're using this formula when x is from <0, 1/2> - */ - template - ValueType ASin_0(const ValueType & x) - { - ValueType nominator, denominator, nominator_add, nominator_x, denominator_add, denominator_x; - ValueType two, result(x), x2(x); - ValueType nominator_temp, denominator_temp, old_result = result; - uint c = 0; - - x2.Mul(x); - two = 2; - - nominator.SetOne(); - denominator = two; - nominator_add = nominator; - denominator_add = denominator; - nominator_x = x; - denominator_x = 3; - - for(uint i=1 ; i<=TTMATH_ARITHMETIC_MAX_LOOP ; ++i) - { - c += nominator_x.Mul(x2); - nominator_temp = nominator_x; - c += nominator_temp.Mul(nominator); - denominator_temp = denominator; - c += denominator_temp.Mul(denominator_x); - c += nominator_temp.Div(denominator_temp); - - // if there is a carry somewhere we only break the calculating - // the result should be ok -- it's from <-pi/2, pi/2> - if( c ) - break; - - result.Add(nominator_temp); - - if( result == old_result ) - // there's no sense to calculate more - break; - - old_result = result; - - - c += nominator_add.Add(two); - c += denominator_add.Add(two); - c += nominator.Mul(nominator_add); - c += denominator.Mul(denominator_add); - c += denominator_x.Add(two); - } - - return result; - } - - - - /*! - an auxiliary function for calculating the Arc Sine - - we're calculating asin from the following formula: - asin(x) = pi/2 - sqrt(2)*sqrt(1-x) * asin_temp - asin_temp = 1 + (1*(1-x))/((2*3)*(2)) + (1*3*(1-x)^2)/((2*4*5)*(4)) + (1*3*5*(1-x)^3)/((2*4*6*7)*(8)) + ... - - where abs(x) <= 1 - - we're using this formula when x is from (1/2, 1> - */ - template - ValueType ASin_1(const ValueType & x) - { - ValueType nominator, denominator, nominator_add, nominator_x, nominator_x_add, denominator_add, denominator_x; - ValueType denominator2; - ValueType one, two, result; - ValueType nominator_temp, denominator_temp, old_result; - uint c = 0; - - two = 2; - - one.SetOne(); - nominator = one; - result = one; - old_result = result; - denominator = two; - nominator_add = nominator; - denominator_add = denominator; - nominator_x = one; - nominator_x.Sub(x); - nominator_x_add = nominator_x; - denominator_x = 3; - denominator2 = two; - - - for(uint i=1 ; i<=TTMATH_ARITHMETIC_MAX_LOOP ; ++i) - { - nominator_temp = nominator_x; - c += nominator_temp.Mul(nominator); - denominator_temp = denominator; - c += denominator_temp.Mul(denominator_x); - c += denominator_temp.Mul(denominator2); - c += nominator_temp.Div(denominator_temp); - - // if there is a carry somewhere we only break the calculating - // the result should be ok -- it's from <-pi/2, pi/2> - if( c ) - break; - - result.Add(nominator_temp); - - if( result == old_result ) - // there's no sense to calculate more - break; - - old_result = result; - - c += nominator_x.Mul(nominator_x_add); - c += nominator_add.Add(two); - c += denominator_add.Add(two); - c += nominator.Mul(nominator_add); - c += denominator.Mul(denominator_add); - c += denominator_x.Add(two); - c += denominator2.Mul(two); - } - - - nominator_x_add.exponent.AddOne(); // *2 - one.exponent.SubOne(); // =0.5 - nominator_x_add.Pow(one); // =sqrt(nominator_x_add) - result.Mul(nominator_x_add); - - one.Set05Pi(); - one.Sub(result); - - return one; - } - - - } // namespace auxiliaryfunctions - - - /*! - this function calculates the Arc Sine - x is from <-1,1> - */ - template - ValueType ASin(ValueType x, ErrorCode * err = 0) - { - using namespace auxiliaryfunctions; - - ValueType result, one; - one.SetOne(); - bool change_sign = false; - - if( x.IsNan() ) - { - if( err ) - *err = err_improper_argument; - - return x; - } - - if( x.GreaterWithoutSignThan(one) ) - { - if( err ) - *err = err_improper_argument; - - return result; // NaN is set by default - } - - if( x.IsSign() ) - { - change_sign = true; - x.Abs(); - } - - one.exponent.SubOne(); // =0.5 - - // asin(-x) = -asin(x) - if( x.GreaterWithoutSignThan(one) ) - result = ASin_1(x); - else - result = ASin_0(x); - - if( change_sign ) - result.ChangeSign(); - - if( err ) - *err = err_ok; - - return result; - } - - - /*! - this function calculates the Arc Cosine - - we're using the formula: - acos(x) = pi/2 - asin(x) - */ - template - ValueType ACos(const ValueType & x, ErrorCode * err = 0) - { - ValueType temp; - - temp.Set05Pi(); - temp.Sub(ASin(x, err)); - - return temp; - } - - - - namespace auxiliaryfunctions - { - - /*! - an auxiliary function for calculating the Arc Tangent - - arc tan (x) where x is in <0; 0.5) - (x can be in (-0.5 ; 0.5) too) - - we're using the Taylor series expanded in zero: - atan(x) = x - (x^3)/3 + (x^5)/5 - (x^7)/7 + ... - */ - template - ValueType ATan0(const ValueType & x) - { - ValueType nominator, denominator, nominator_add, denominator_add, temp; - ValueType result, old_result; - bool adding = false; - uint c = 0; - - result = x; - old_result = result; - nominator = x; - nominator_add = x; - nominator_add.Mul(x); - - denominator.SetOne(); - denominator_add = 2; - - for(uint i=1 ; i<=TTMATH_ARITHMETIC_MAX_LOOP ; ++i) - { - c += nominator.Mul(nominator_add); - c += denominator.Add(denominator_add); - - temp = nominator; - c += temp.Div(denominator); - - if( c ) - // the result should be ok - break; - - if( adding ) - result.Add(temp); - else - result.Sub(temp); - - if( result == old_result ) - // there's no sense to calculate more - break; - - old_result = result; - adding = !adding; - } - - return result; - } - - - /*! - an auxiliary function for calculating the Arc Tangent - - where x is in <0 ; 1> - */ - template - ValueType ATan01(const ValueType & x) - { - ValueType half; - half.Set05(); - - /* - it would be better if we chose about sqrt(2)-1=0.41... instead of 0.5 here - - because as you can see below: - when x = sqrt(2)-1 - abs(x) = abs( (x-1)/(1+x) ) - so when we're calculating values around x - then they will be better converged to each other - - for example if we have x=0.4999 then during calculating ATan0(0.4999) - we have to make about 141 iterations but when we have x=0.5 - then during calculating ATan0( (x-1)/(1+x) ) we have to make - only about 89 iterations (both for Big<3,9>) - - in the future this 0.5 can be changed - */ - if( x.SmallerWithoutSignThan(half) ) - return ATan0(x); - - - /* - x>=0.5 and x<=1 - (x can be even smaller than 0.5) - - y = atac(x) - x = tan(y) - - tan(y-b) = (tan(y)-tab(b)) / (1+tan(y)*tan(b)) - y-b = atan( (tan(y)-tab(b)) / (1+tan(y)*tan(b)) ) - y = b + atan( (x-tab(b)) / (1+x*tan(b)) ) - - let b = pi/4 - tan(b) = tan(pi/4) = 1 - y = pi/4 + atan( (x-1)/(1+x) ) - - so - atac(x) = pi/4 + atan( (x-1)/(1+x) ) - when x->1 (x converges to 1) the (x-1)/(1+x) -> 0 - and we can use ATan0() function here - */ - - ValueType n(x),d(x),one,result; - - one.SetOne(); - n.Sub(one); - d.Add(one); - n.Div(d); - - result = ATan0(n); - - n.Set05Pi(); - n.exponent.SubOne(); // =pi/4 - result.Add(n); - - return result; - } - - - /*! - an auxiliary function for calculating the Arc Tangent - where x > 1 - - we're using the formula: - atan(x) = pi/2 - atan(1/x) for x>0 - */ - template - ValueType ATanGreaterThanPlusOne(const ValueType & x) - { - ValueType temp, atan; - - temp.SetOne(); - - if( temp.Div(x) ) - { - // if there was a carry here that means x is very big - // and atan(1/x) fast converged to 0 - atan.SetZero(); - } - else - atan = ATan01(temp); - - temp.Set05Pi(); - temp.Sub(atan); - - return temp; - } - - } // namespace auxiliaryfunctions - - - /*! - this function calculates the Arc Tangent - */ - template - ValueType ATan(ValueType x) - { - using namespace auxiliaryfunctions; - - ValueType one, result; - one.SetOne(); - bool change_sign = false; - - if( x.IsNan() ) - return x; - - // if x is negative we're using the formula: - // atan(-x) = -atan(x) - if( x.IsSign() ) - { - change_sign = true; - x.Abs(); - } - - if( x.GreaterWithoutSignThan(one) ) - result = ATanGreaterThanPlusOne(x); - else - result = ATan01(x); - - if( change_sign ) - result.ChangeSign(); - - return result; - } - - - /*! - this function calculates the Arc Tangent - look at the description of ATan(...) - - (the abbreviation of Arc Tangent can be 'atg' as well) - */ - template - ValueType ATg(const ValueType & x) - { - return ATan(x); - } - - - /*! - this function calculates the Arc Cotangent - - we're using the formula: - actan(x) = pi/2 - atan(x) - */ - template - ValueType ACot(const ValueType & x) - { - ValueType result; - - result.Set05Pi(); - result.Sub(ATan(x)); - - return result; - } - - - /*! - this function calculates the Arc Cotangent - look at the description of ACot(...) - - (the abbreviation of Arc Cotangent can be 'actg' as well) - */ - template - ValueType ACtg(const ValueType & x) - { - return ACot(x); - } - - - /* - * - * hyperbolic functions - * - * - */ - - - /*! - this function calculates the Hyperbolic Sine - - we're using the formula sinh(x)= ( e^x - e^(-x) ) / 2 - */ - template - ValueType Sinh(const ValueType & x, ErrorCode * err = 0) - { - if( x.IsNan() ) - { - if( err ) - *err = err_improper_argument; - - return x; // NaN - } - - ValueType ex, emx; - uint c = 0; - - c += ex.Exp(x); - c += emx.Exp(-x); - - c += ex.Sub(emx); - c += ex.exponent.SubOne(); - - if( err ) - *err = c ? err_overflow : err_ok; - - return ex; - } - - - /*! - this function calculates the Hyperbolic Cosine - - we're using the formula cosh(x)= ( e^x + e^(-x) ) / 2 - */ - template - ValueType Cosh(const ValueType & x, ErrorCode * err = 0) - { - if( x.IsNan() ) - { - if( err ) - *err = err_improper_argument; - - return x; // NaN - } - - ValueType ex, emx; - uint c = 0; - - c += ex.Exp(x); - c += emx.Exp(-x); - - c += ex.Add(emx); - c += ex.exponent.SubOne(); - - if( err ) - *err = c ? err_overflow : err_ok; - - return ex; - } - - - /*! - this function calculates the Hyperbolic Tangent - - we're using the formula tanh(x)= ( e^x - e^(-x) ) / ( e^x + e^(-x) ) - */ - template - ValueType Tanh(const ValueType & x, ErrorCode * err = 0) - { - if( x.IsNan() ) - { - if( err ) - *err = err_improper_argument; - - return x; // NaN - } - - ValueType ex, emx, nominator, denominator; - uint c = 0; - - c += ex.Exp(x); - c += emx.Exp(-x); - - nominator = ex; - c += nominator.Sub(emx); - denominator = ex; - c += denominator.Add(emx); - - c += nominator.Div(denominator); - - if( err ) - *err = c ? err_overflow : err_ok; - - return nominator; - } - - - /*! - this function calculates the Hyperbolic Tangent - look at the description of Tanh(...) - - (the abbreviation of Hyperbolic Tangent can be 'tgh' as well) - */ - template - ValueType Tgh(const ValueType & x, ErrorCode * err = 0) - { - return Tanh(x, err); - } - - /*! - this function calculates the Hyperbolic Cotangent - - we're using the formula coth(x)= ( e^x + e^(-x) ) / ( e^x - e^(-x) ) - */ - template - ValueType Coth(const ValueType & x, ErrorCode * err = 0) - { - if( x.IsNan() ) - { - if( err ) - *err = err_improper_argument; - - return x; // NaN - } - - if( x.IsZero() ) - { - if( err ) - *err = err_improper_argument; - - return ValueType(); // NaN is set by default - } - - ValueType ex, emx, nominator, denominator; - uint c = 0; - - c += ex.Exp(x); - c += emx.Exp(-x); - - nominator = ex; - c += nominator.Add(emx); - denominator = ex; - c += denominator.Sub(emx); - - c += nominator.Div(denominator); - - if( err ) - *err = c ? err_overflow : err_ok; - - return nominator; - } - - - /*! - this function calculates the Hyperbolic Cotangent - look at the description of Coth(...) - - (the abbreviation of Hyperbolic Cotangent can be 'ctgh' as well) - */ - template - ValueType Ctgh(const ValueType & x, ErrorCode * err = 0) - { - return Coth(x, err); - } - - - /* - * - * inverse hyperbolic functions - * - * - */ - - - /*! - inverse hyperbolic sine - - asinh(x) = ln( x + sqrt(x^2 + 1) ) - */ - template - ValueType ASinh(const ValueType & x, ErrorCode * err = 0) - { - if( x.IsNan() ) - { - if( err ) - *err = err_improper_argument; - - return x; // NaN - } - - ValueType xx(x), one, result; - uint c = 0; - one.SetOne(); - - c += xx.Mul(x); - c += xx.Add(one); - one.exponent.SubOne(); // one=0.5 - // xx is >= 1 - c += xx.PowFrac(one); // xx=sqrt(xx) - c += xx.Add(x); - c += result.Ln(xx); // xx > 0 - - // here can only be a carry - if( err ) - *err = c ? err_overflow : err_ok; - - return result; - } - - - /*! - inverse hyperbolic cosine - - acosh(x) = ln( x + sqrt(x^2 - 1) ) x in <1, infinity) - */ - template - ValueType ACosh(const ValueType & x, ErrorCode * err = 0) - { - if( x.IsNan() ) - { - if( err ) - *err = err_improper_argument; - - return x; // NaN - } - - ValueType xx(x), one, result; - uint c = 0; - one.SetOne(); - - if( x < one ) - { - if( err ) - *err = err_improper_argument; - - return result; // NaN is set by default - } - - c += xx.Mul(x); - c += xx.Sub(one); - // xx is >= 0 - // we can't call a PowFrac when the 'x' is zero - // if x is 0 the sqrt(0) is 0 - if( !xx.IsZero() ) - { - one.exponent.SubOne(); // one=0.5 - c += xx.PowFrac(one); // xx=sqrt(xx) - } - c += xx.Add(x); - c += result.Ln(xx); // xx >= 1 - - // here can only be a carry - if( err ) - *err = c ? err_overflow : err_ok; - - return result; - } - - - /*! - inverse hyperbolic tangent - - atanh(x) = 0.5 * ln( (1+x) / (1-x) ) x in (-1, 1) - */ - template - ValueType ATanh(const ValueType & x, ErrorCode * err = 0) - { - if( x.IsNan() ) - { - if( err ) - *err = err_improper_argument; - - return x; // NaN - } - - ValueType nominator(x), denominator, one, result; - uint c = 0; - one.SetOne(); - - if( !x.SmallerWithoutSignThan(one) ) - { - if( err ) - *err = err_improper_argument; - - return result; // NaN is set by default - } - - c += nominator.Add(one); - denominator = one; - c += denominator.Sub(x); - c += nominator.Div(denominator); - c += result.Ln(nominator); - c += result.exponent.SubOne(); - - // here can only be a carry - if( err ) - *err = c ? err_overflow : err_ok; - - return result; - } - - - /*! - inverse hyperbolic tantent - */ - template - ValueType ATgh(const ValueType & x, ErrorCode * err = 0) - { - return ATanh(x, err); - } - - - /*! - inverse hyperbolic cotangent - - acoth(x) = 0.5 * ln( (x+1) / (x-1) ) x in (-infinity, -1) or (1, infinity) - */ - template - ValueType ACoth(const ValueType & x, ErrorCode * err = 0) - { - if( x.IsNan() ) - { - if( err ) - *err = err_improper_argument; - - return x; // NaN - } - - ValueType nominator(x), denominator(x), one, result; - uint c = 0; - one.SetOne(); - - if( !x.GreaterWithoutSignThan(one) ) - { - if( err ) - *err = err_improper_argument; - - return result; // NaN is set by default - } - - c += nominator.Add(one); - c += denominator.Sub(one); - c += nominator.Div(denominator); - c += result.Ln(nominator); - c += result.exponent.SubOne(); - - // here can only be a carry - if( err ) - *err = c ? err_overflow : err_ok; - - return result; - } - - - /*! - inverse hyperbolic cotantent - */ - template - ValueType ACtgh(const ValueType & x, ErrorCode * err = 0) - { - return ACoth(x, err); - } - - - - - - /* - * - * functions for converting between degrees, radians and gradians - * - * - */ - - - /*! - this function converts degrees to radians - - it returns: x * pi / 180 - */ - template - ValueType DegToRad(const ValueType & x, ErrorCode * err = 0) - { - ValueType result, temp; - uint c = 0; - - if( x.IsNan() ) - { - if( err ) - *err = err_improper_argument; - - return x; - } - - result = x; - - // it is better to make division first and then multiplication - // the result is more accurate especially when x is: 90,180,270 or 360 - temp = 180; - c += result.Div(temp); - - temp.SetPi(); - c += result.Mul(temp); - - if( err ) - *err = c ? err_overflow : err_ok; - - return result; - } - - - /*! - this function converts radians to degrees - - it returns: x * 180 / pi - */ - template - ValueType RadToDeg(const ValueType & x, ErrorCode * err = 0) - { - ValueType result, delimiter; - uint c = 0; - - if( x.IsNan() ) - { - if( err ) - *err = err_improper_argument; - - return x; - } - - result = 180; - c += result.Mul(x); - - delimiter.SetPi(); - c += result.Div(delimiter); - - if( err ) - *err = c ? err_overflow : err_ok; - - return result; - } - - - /*! - this function converts degrees in the long format into one value - - long format: (degrees, minutes, seconds) - minutes and seconds must be greater than or equal zero - - result: - - if d>=0 : result= d + ((s/60)+m)/60 - - if d<0 : result= d - ((s/60)+m)/60 - - ((s/60)+m)/60 = (s+60*m)/3600 (second version is faster because - there's only one division) - - samples: - - - DegToDeg(10, 30, 0) = 10.5 - - DegToDeg(10, 24, 35.6)=10.4098(8) - */ - template - ValueType DegToDeg( const ValueType & d, const ValueType & m, const ValueType & s, - ErrorCode * err = 0) - { - ValueType delimiter, multipler; - uint c = 0; - - if( d.IsNan() || m.IsNan() || s.IsNan() || m.IsSign() || s.IsSign() ) - { - if( err ) - *err = err_improper_argument; - - delimiter.SetZeroNan(); // not needed, only to get rid of GCC warning about an uninitialized variable - - return delimiter; - } - - multipler = 60; - delimiter = 3600; - - c += multipler.Mul(m); - c += multipler.Add(s); - c += multipler.Div(delimiter); - - if( d.IsSign() ) - multipler.ChangeSign(); - - c += multipler.Add(d); - - if( err ) - *err = c ? err_overflow : err_ok; - - return multipler; - } - - - /*! - this function converts degrees in the long format to radians - */ - template - ValueType DegToRad( const ValueType & d, const ValueType & m, const ValueType & s, - ErrorCode * err = 0) - { - ValueType temp_deg = DegToDeg(d,m,s,err); - - if( err && *err!=err_ok ) - return temp_deg; - - return DegToRad(temp_deg, err); - } - - - /*! - this function converts gradians to radians - - it returns: x * pi / 200 - */ - template - ValueType GradToRad(const ValueType & x, ErrorCode * err = 0) - { - ValueType result, temp; - uint c = 0; - - if( x.IsNan() ) - { - if( err ) - *err = err_improper_argument; - - return x; - } - - result = x; - - // it is better to make division first and then multiplication - // the result is more accurate especially when x is: 100,200,300 or 400 - temp = 200; - c += result.Div(temp); - - temp.SetPi(); - c += result.Mul(temp); - - if( err ) - *err = c ? err_overflow : err_ok; - - return result; - } - - - /*! - this function converts radians to gradians - - it returns: x * 200 / pi - */ - template - ValueType RadToGrad(const ValueType & x, ErrorCode * err = 0) - { - ValueType result, delimiter; - uint c = 0; - - if( x.IsNan() ) - { - if( err ) - *err = err_improper_argument; - - return x; - } - - result = 200; - c += result.Mul(x); - - delimiter.SetPi(); - c += result.Div(delimiter); - - if( err ) - *err = c ? err_overflow : err_ok; - - return result; - } - - - /*! - this function converts degrees to gradians - - it returns: x * 200 / 180 - */ - template - ValueType DegToGrad(const ValueType & x, ErrorCode * err = 0) - { - ValueType result, temp; - uint c = 0; - - if( x.IsNan() ) - { - if( err ) - *err = err_improper_argument; - - return x; - } - - result = x; - - temp = 200; - c += result.Mul(temp); - - temp = 180; - c += result.Div(temp); - - if( err ) - *err = c ? err_overflow : err_ok; - - return result; - } - - - /*! - this function converts degrees in the long format to gradians - */ - template - ValueType DegToGrad( const ValueType & d, const ValueType & m, const ValueType & s, - ErrorCode * err = 0) - { - ValueType temp_deg = DegToDeg(d,m,s,err); - - if( err && *err!=err_ok ) - return temp_deg; - - return DegToGrad(temp_deg, err); - } - - - /*! - this function converts degrees to gradians - - it returns: x * 180 / 200 - */ - template - ValueType GradToDeg(const ValueType & x, ErrorCode * err = 0) - { - ValueType result, temp; - uint c = 0; - - if( x.IsNan() ) - { - if( err ) - *err = err_improper_argument; - - return x; - } - - result = x; - - temp = 180; - c += result.Mul(temp); - - temp = 200; - c += result.Div(temp); - - if( err ) - *err = c ? err_overflow : err_ok; - - return result; - } - - - - - /* - * - * another functions - * - * - */ - - - /*! - this function calculates the square root - - Sqrt(9) = 3 - */ - template - ValueType Sqrt(ValueType x, ErrorCode * err = 0) - { - if( x.IsNan() || x.IsSign() ) - { - if( err ) - *err = err_improper_argument; - - x.SetNan(); - - return x; - } - - uint c = x.Sqrt(); - - if( err ) - *err = c ? err_overflow : err_ok; - - return x; - } - - - - namespace auxiliaryfunctions - { - - template - bool RootCheckIndexSign(ValueType & x, const ValueType & index, ErrorCode * err) - { - if( index.IsSign() ) - { - // index cannot be negative - if( err ) - *err = err_improper_argument; - - x.SetNan(); - - return true; - } - - return false; - } - - - template - bool RootCheckIndexZero(ValueType & x, const ValueType & index, ErrorCode * err) - { - if( index.IsZero() ) - { - if( x.IsZero() ) - { - // there isn't root(0;0) - we assume it's not defined - if( err ) - *err = err_improper_argument; - - x.SetNan(); - - return true; - } - - // root(x;0) is 1 (if x!=0) - x.SetOne(); - - if( err ) - *err = err_ok; - - return true; - } - - return false; - } - - - template - bool RootCheckIndexOne(const ValueType & index, ErrorCode * err) - { - ValueType one; - one.SetOne(); - - if( index == one ) - { - //root(x;1) is x - // we do it because if we used the PowFrac function - // we would lose the precision - if( err ) - *err = err_ok; - - return true; - } - - return false; - } - - - template - bool RootCheckIndexTwo(ValueType & x, const ValueType & index, ErrorCode * err) - { - if( index == 2 ) - { - x = Sqrt(x, err); - - return true; - } - - return false; - } - - - template - bool RootCheckIndexFrac(ValueType & x, const ValueType & index, ErrorCode * err) - { - if( !index.IsInteger() ) - { - // index must be integer - if( err ) - *err = err_improper_argument; - - x.SetNan(); - - return true; - } - - return false; - } - - - template - bool RootCheckXZero(ValueType & x, ErrorCode * err) - { - if( x.IsZero() ) - { - // root(0;index) is zero (if index!=0) - // RootCheckIndexZero() must be called beforehand - x.SetZero(); - - if( err ) - *err = err_ok; - - return true; - } - - return false; - } - - - template - bool RootCheckIndex(ValueType & x, const ValueType & index, ErrorCode * err, bool * change_sign) - { - *change_sign = false; - - if( index.Mod2() ) - { - // index is odd (1,3,5...) - if( x.IsSign() ) - { - *change_sign = true; - x.Abs(); - } - } - else - { - // index is even - // x cannot be negative - if( x.IsSign() ) - { - if( err ) - *err = err_improper_argument; - - x.SetNan(); - - return true; - } - } - - return false; - } - - - template - uint RootCorrectInteger(ValueType & old_x, ValueType & x, const ValueType & index) - { - if( !old_x.IsInteger() || x.IsInteger() || !index.exponent.IsSign() ) - return 0; - - // old_x is integer, - // x is not integer, - // index is relatively small (index.exponent<0 or index.exponent<=0) - // (because we're using a special powering algorithm Big::PowUInt()) - - uint c = 0; - - ValueType temp(x); - c += temp.Round(); - - ValueType temp_round(temp); - c += temp.PowUInt(index); - - if( temp == old_x ) - x = temp_round; - - return (c==0)? 0 : 1; - } - - - - } // namespace auxiliaryfunctions - - - - /*! - caltulate the index'th Root of x - - index must be integer and not negative <0;1;2;3....) - - - if index==0 the result is one - - if x==0 the result is zero and we assume root(0;0) is not defined - - - if index is even (2;4;6...) the result is x^(1/index) and x>0 - - if index is odd (1;2;3;...) the result is either - - -(abs(x)^(1/index)) if x<0, or - - x^(1/index)) if x>0 - - - for index==1 the result is equal x - */ - template - ValueType Root(ValueType x, const ValueType & index, ErrorCode * err = 0) - { - using namespace auxiliaryfunctions; - - if( x.IsNan() || index.IsNan() ) - { - if( err ) - *err = err_improper_argument; - - x.SetNan(); - - return x; - } - - if( RootCheckIndexSign(x, index, err) ) return x; - if( RootCheckIndexZero(x, index, err) ) return x; - if( RootCheckIndexOne ( index, err) ) return x; - if( RootCheckIndexTwo (x, index, err) ) return x; - if( RootCheckIndexFrac(x, index, err) ) return x; - if( RootCheckXZero (x, err) ) return x; - - // index integer and index!=0 - // x!=0 - - ValueType old_x(x); - bool change_sign; - - if( RootCheckIndex(x, index, err, &change_sign ) ) return x; - - ValueType temp; - uint c = 0; - - // we're using the formula: root(x ; n) = exp( ln(x) / n ) - c += temp.Ln(x); - c += temp.Div(index); - c += x.Exp(temp); - - if( change_sign ) - { - // x is different from zero - x.SetSign(); - } - - c += RootCorrectInteger(old_x, x, index); - - if( err ) - *err = c ? err_overflow : err_ok; - - return x; - } - - - - /*! - absolute value of x - - samples: - - -2 = 2 - - 2 = 2 - */ - template - ValueType Abs(const ValueType & x) - { - ValueType result( x ); - result.Abs(); - - return result; - } - - - /*! - it returns the sign of the value - - samples: - - -2 = -1 - - 0 = 0 - - 10 = 1 - */ - template - ValueType Sgn(ValueType x) - { - x.Sgn(); - - return x; - } - - - /*! - the remainder from a division - - samples: - - mod( 12.6 ; 3) = 0.6 because 12.6 = 3*4 + 0.6 - - mod(-12.6 ; 3) = -0.6 bacause -12.6 = 3*(-4) + (-0.6) - - mod( 12.6 ; -3) = 0.6 - - mod(-12.6 ; -3) = -0.6 - */ - template - ValueType Mod(ValueType a, const ValueType & b, ErrorCode * err = 0) - { - if( a.IsNan() || b.IsNan() ) - { - if( err ) - *err = err_improper_argument; - - a.SetNan(); - - return a; - } - - uint c = a.Mod(b); - - if( err ) - *err = c ? err_overflow : err_ok; - - return a; - } - - - - namespace auxiliaryfunctions - { - - /*! - this function is used to store factorials in a given container - 'more' means how many values should be added at the end - - sample: - - std::vector fact; - SetFactorialSequence(fact, 3); - // now the container has three values: 1 1 2 - - SetFactorialSequence(fact, 2); - // now the container has five values: 1 1 2 6 24 - */ - template - void SetFactorialSequence(std::vector & fact, uint more = 20) - { - if( more == 0 ) - more = 1; - - uint start = static_cast(fact.size()); - fact.resize(fact.size() + more); - - if( start == 0 ) - { - fact[0] = 1; - ++start; - } - - for(uint i=start ; i - ValueType SetBernoulliNumbersSum(CGamma & cgamma, const ValueType & n_, uint m, - const volatile StopCalculating * stop = 0) - { - ValueType k_, temp, temp2, temp3, sum; - - sum.SetZero(); - - for(uint k=0 ; kWasStopSignal() ) - return ValueType(); // NaN - - if( k>1 && (k & 1) == 1 ) // for that k the Bernoulli number is zero - continue; - - k_ = k; - - temp = n_; // n_ is equal 2 - temp.Pow(k_); - // temp = 2^k - - temp2 = cgamma.fact[m]; - temp3 = cgamma.fact[k]; - temp3.Mul(cgamma.fact[m-k]); - temp2.Div(temp3); - // temp2 = (m k) = m! / ( k! * (m-k)! ) - - temp.Mul(temp2); - temp.Mul(cgamma.bern[k]); - - sum.Add(temp); - // sum += 2^k * (m k) * B(k) - - if( sum.IsNan() ) - break; - } - - return sum; - } - - - /*! - an auxiliary function used to calculate Bernoulli numbers - start is >= 2 - - we use the recurrence formula: - - B(m) = 1 / (2*(1 - 2^m)) * sum(m) - where sum(m) is calculated by SetBernoulliNumbersSum() - */ - template - bool SetBernoulliNumbersMore(CGamma & cgamma, uint start, const volatile StopCalculating * stop = 0) - { - ValueType denominator, temp, temp2, temp3, m_, sum, sum2, n_, k_; - - const uint n = 2; - n_ = n; - - // start is >= 2 - for(uint m=start ; mWasStopSignal() ) - { - cgamma.bern.resize(m); // valid numbers are in [0, m-1] - return false; - } - - cgamma.bern[m].Div(denominator); - } - } - - return true; - } - - - /*! - this function is used to calculate Bernoulli numbers, - returns false if there was a stop signal, - 'more' means how many values should be added at the end - - sample: - - typedef Big<1,2> MyBig; - CGamma cgamma; - SetBernoulliNumbers(cgamma, 3); - // now we have three first Bernoulli numbers: 1 -0.5 0.16667 - - SetBernoulliNumbers(cgamma, 4); - // now we have 7 Bernoulli numbers: 1 -0.5 0.16667 0 -0.0333 0 0.0238 - */ - template - bool SetBernoulliNumbers(CGamma & cgamma, uint more = 20, const volatile StopCalculating * stop = 0) - { - if( more == 0 ) - more = 1; - - uint start = static_cast(cgamma.bern.size()); - cgamma.bern.resize(cgamma.bern.size() + more); - - if( start == 0 ) - { - cgamma.bern[0].SetOne(); - ++start; - } - - if( cgamma.bern.size() == 1 ) - return true; - - if( start == 1 ) - { - cgamma.bern[1].Set05(); - cgamma.bern[1].ChangeSign(); - ++start; - } - - // we should have sufficient factorials in cgamma.fact - if( cgamma.fact.size() < cgamma.bern.size() ) - SetFactorialSequence(cgamma.fact, static_cast(cgamma.bern.size() - cgamma.fact.size())); - - - return SetBernoulliNumbersMore(cgamma, start, stop); - } - - - /*! - an auxiliary function used to calculate the Gamma() function - - we calculate a sum: - - sum(n) = sum_{m=2} { B(m) / ( (m^2 - m) * n^(m-1) ) } = 1/(12*n) - 1/(360*n^3) + 1/(1260*n^5) + ... - - B(m) means a mth Bernoulli number - the sum starts from m=2, we calculate as long as the value will not change after adding a next part - */ - template - ValueType GammaFactorialHighSum(const ValueType & n, CGamma & cgamma, ErrorCode & err, - const volatile StopCalculating * stop) - { - ValueType temp, temp2, denominator, sum, oldsum; - - sum.SetZero(); - - for(uint m=2 ; mWasStopSignal() ) - { - err = err_interrupt; - return ValueType(); // NaN - } - - temp = (m-1); - denominator = n; - denominator.Pow(temp); - // denominator = n ^ (m-1) - - temp = m; - temp2 = temp; - temp.Mul(temp2); - temp.Sub(temp2); - // temp = m^2 - m - - denominator.Mul(temp); - // denominator = (m^2 - m) * n ^ (m-1) - - if( m >= cgamma.bern.size() ) - { - if( !SetBernoulliNumbers(cgamma, m - cgamma.bern.size() + 1 + 3, stop) ) // 3 more than needed - { - // there was the stop signal - err = err_interrupt; - return ValueType(); // NaN - } - } - - temp = cgamma.bern[m]; - temp.Div(denominator); - - oldsum = sum; - sum.Add(temp); - - if( sum.IsNan() || oldsum==sum ) - break; - } - - return sum; - } - - - /*! - an auxiliary function used to calculate the Gamma() function - - we calculate a helper function GammaFactorialHigh() by using Stirling's series: - - n! = (n/e)^n * sqrt(2*pi*n) * exp( sum(n) ) - - where n is a real number (not only an integer) and is sufficient large (greater than TTMATH_GAMMA_BOUNDARY) - and sum(n) is calculated by GammaFactorialHighSum() - */ - template - ValueType GammaFactorialHigh(const ValueType & n, CGamma & cgamma, ErrorCode & err, - const volatile StopCalculating * stop) - { - ValueType temp, temp2, temp3, denominator, sum; - - temp.Set2Pi(); - temp.Mul(n); - temp2 = Sqrt(temp); - // temp2 = sqrt(2*pi*n) - - temp = n; - temp3.SetE(); - temp.Div(temp3); - temp.Pow(n); - // temp = (n/e)^n - - sum = GammaFactorialHighSum(n, cgamma, err, stop); - temp3.Exp(sum); - // temp3 = exp(sum) - - temp.Mul(temp2); - temp.Mul(temp3); - - return temp; - } - - - /*! - an auxiliary function used to calculate the Gamma() function - - Gamma(x) = GammaFactorialHigh(x-1) - */ - template - ValueType GammaPlusHigh(ValueType n, CGamma & cgamma, ErrorCode & err, const volatile StopCalculating * stop) - { - ValueType one; - - one.SetOne(); - n.Sub(one); - - return GammaFactorialHigh(n, cgamma, err, stop); - } - - - /*! - an auxiliary function used to calculate the Gamma() function - - we use this function when n is integer and a small value (from 0 to TTMATH_GAMMA_BOUNDARY] - we use the formula: - - gamma(n) = (n-1)! = 1 * 2 * 3 * ... * (n-1) - */ - template - ValueType GammaPlusLowIntegerInt(uint n, CGamma & cgamma) - { - TTMATH_ASSERT( n > 0 ) - - if( n - 1 < static_cast(cgamma.fact.size()) ) - return cgamma.fact[n - 1]; - - ValueType res; - uint start = 2; - - if( cgamma.fact.size() < 2 ) - { - res.SetOne(); - } - else - { - start = static_cast(cgamma.fact.size()); - res = cgamma.fact[start-1]; - } - - for(uint i=start ; i - ValueType GammaPlusLowInteger(const ValueType & n, CGamma & cgamma) - { - sint n_; - - n.ToInt(n_); - - return GammaPlusLowIntegerInt(n_, cgamma); - } - - - /*! - an auxiliary function used to calculate the Gamma() function - - we use this function when n is a small value (from 0 to TTMATH_GAMMA_BOUNDARY] - we use a recurrence formula: - - gamma(z+1) = z * gamma(z) - then: gamma(z) = gamma(z+1) / z - - samples: - - gamma(3.89) = gamma(2001.89) / ( 3.89 * 4.89 * 5.89 * ... * 1999.89 * 2000.89 ) - */ - template - ValueType GammaPlusLow(ValueType n, CGamma & cgamma, ErrorCode & err, const volatile StopCalculating * stop) - { - ValueType one, denominator, temp, boundary; - - if( n.IsInteger() ) - return GammaPlusLowInteger(n, cgamma); - - one.SetOne(); - denominator = n; - boundary = TTMATH_GAMMA_BOUNDARY; - - while( n < boundary ) - { - n.Add(one); - denominator.Mul(n); - } - - n.Add(one); - - // now n is sufficient big - temp = GammaPlusHigh(n, cgamma, err, stop); - temp.Div(denominator); - - return temp; - } - - - /*! - an auxiliary function used to calculate the Gamma() function - */ - template - ValueType GammaPlus(const ValueType & n, CGamma & cgamma, ErrorCode & err, const volatile StopCalculating * stop) - { - if( n > TTMATH_GAMMA_BOUNDARY ) - return GammaPlusHigh(n, cgamma, err, stop); - - return GammaPlusLow(n, cgamma, err, stop); - } - - - /*! - an auxiliary function used to calculate the Gamma() function - - this function is used when n is negative - we use the reflection formula: - gamma(1-z) * gamma(z) = pi / sin(pi*z) - then: gamma(z) = pi / (sin(pi*z) * gamma(1-z)) - - */ - template - ValueType GammaMinus(const ValueType & n, CGamma & cgamma, ErrorCode & err, const volatile StopCalculating * stop) - { - ValueType pi, denominator, temp, temp2; - - if( n.IsInteger() ) - { - // gamma function is not defined when n is negative and integer - err = err_improper_argument; - return temp; // NaN - } - - pi.SetPi(); - - temp = pi; - temp.Mul(n); - temp2 = Sin(temp); - // temp2 = sin(pi * n) - - temp.SetOne(); - temp.Sub(n); - temp = GammaPlus(temp, cgamma, err, stop); - // temp = gamma(1 - n) - - temp.Mul(temp2); - pi.Div(temp); - - return pi; - } - - } // namespace auxiliaryfunctions - - - - /*! - this function calculates the Gamma function - - it's multithread safe, you should create a CGamma<> object and use it whenever you call the Gamma() - e.g. - - typedef Big<1,2> MyBig; - MyBig x=234, y=345.53; - CGamma cgamma; - std::cout << Gamma(x, cgamma) << std::endl; - std::cout << Gamma(y, cgamma) << std::endl; - - in the CGamma<> object the function stores some coefficients (factorials, Bernoulli numbers), - and they will be reused in next calls to the function - - each thread should have its own CGamma<> object, and you can use these objects with Factorial() function too - */ - template - ValueType Gamma(const ValueType & n, CGamma & cgamma, ErrorCode * err = 0, - const volatile StopCalculating * stop = 0) - { - using namespace auxiliaryfunctions; - - ValueType result; - ErrorCode err_tmp; - - if( n.IsNan() ) - { - if( err ) - *err = err_improper_argument; - - return n; - } - - if( cgamma.history.Get(n, result, err_tmp) ) - { - if( err ) - *err = err_tmp; - - return result; - } - - err_tmp = err_ok; - - if( n.IsSign() ) - { - result = GammaMinus(n, cgamma, err_tmp, stop); - } - else - if( n.IsZero() ) - { - err_tmp = err_improper_argument; - result.SetNan(); - } - else - { - result = GammaPlus(n, cgamma, err_tmp, stop); - } - - if( result.IsNan() && err_tmp==err_ok ) - err_tmp = err_overflow; - - if( err ) - *err = err_tmp; - - if( stop && !stop->WasStopSignal() ) - cgamma.history.Add(n, result, err_tmp); - - return result; - } - - - /*! - this function calculates the Gamma function - - note: this function should be used only in a single-thread environment - */ - template - ValueType Gamma(const ValueType & n, ErrorCode * err = 0) - { - // warning: this static object is not thread safe - static CGamma cgamma; - - return Gamma(n, cgamma, err); - } - - - - namespace auxiliaryfunctions - { - - /*! - an auxiliary function for calculating the factorial function - - we use the formula: - x! = gamma(x+1) - */ - template - ValueType Factorial2(ValueType x, - CGamma * cgamma = 0, - ErrorCode * err = 0, - const volatile StopCalculating * stop = 0) - { - ValueType result, one; - - if( x.IsNan() || x.IsSign() || !x.IsInteger() ) - { - if( err ) - *err = err_improper_argument; - - x.SetNan(); - - return x; - } - - one.SetOne(); - x.Add(one); - - if( cgamma ) - return Gamma(x, *cgamma, err, stop); - - return Gamma(x, err); - } - - } // namespace auxiliaryfunctions - - - - /*! - the factorial from given 'x' - e.g. - Factorial(4) = 4! = 1*2*3*4 - - it's multithread safe, you should create a CGamma<> object and use it whenever you call the Factorial() - e.g. - - typedef Big<1,2> MyBig; - MyBig x=234, y=54345; - CGamma cgamma; - std::cout << Factorial(x, cgamma) << std::endl; - std::cout << Factorial(y, cgamma) << std::endl; - - in the CGamma<> object the function stores some coefficients (factorials, Bernoulli numbers), - and they will be reused in next calls to the function - - each thread should have its own CGamma<> object, and you can use these objects with Gamma() function too - */ - template - ValueType Factorial(const ValueType & x, CGamma & cgamma, ErrorCode * err = 0, - const volatile StopCalculating * stop = 0) - { - return auxiliaryfunctions::Factorial2(x, &cgamma, err, stop); - } - - - /*! - the factorial from given 'x' - e.g. - Factorial(4) = 4! = 1*2*3*4 - - note: this function should be used only in a single-thread environment - */ - template - ValueType Factorial(const ValueType & x, ErrorCode * err = 0) - { - return auxiliaryfunctions::Factorial2(x, (CGamma*)0, err, 0); - } - - - /*! - this method prepares some coefficients: factorials and Bernoulli numbers - stored in 'fact' and 'bern' objects - - we're defining the method here because we're using Gamma() function which - is not available in ttmathobjects.h - - read the doc info in ttmathobjects.h file where CGamma<> struct is declared - */ - template - void CGamma::InitAll() - { - ValueType x = TTMATH_GAMMA_BOUNDARY + 1; - - // history.Remove(x) removes only one object - // we must be sure that there are not others objects with the key 'x' - while( history.Remove(x) ) - { - } - - // the simplest way to initialize is to call the Gamma function with (TTMATH_GAMMA_BOUNDARY + 1) - // when x is larger then fewer coefficients we need - Gamma(x, *this); - } - - - -} // namespace - - -/*! - this is for convenience for the user - he can only use '#include ' -*/ -#include "ttmathparser.h" - -// Dec is not finished yet -//#include "ttmathdec.h" - - - -#ifdef _MSC_VER -//warning C4127: conditional expression is constant -#pragma warning( default: 4127 ) -//warning C4702: unreachable code -#pragma warning( default: 4702 ) -//warning C4800: forcing value to bool 'true' or 'false' (performance warning) -#pragma warning( default: 4800 ) -#endif - -#endif diff --git a/include/geos/algorithm/ttmath/ttmathbig.h b/include/geos/algorithm/ttmath/ttmathbig.h deleted file mode 100644 index bbbbda0b5c..0000000000 --- a/include/geos/algorithm/ttmath/ttmathbig.h +++ /dev/null @@ -1,6093 +0,0 @@ -/* - * This file is a part of TTMath Bignum Library - * and is distributed under the 3-Clause BSD Licence. - * Author: Tomasz Sowa - */ - -/* - * Copyright (c) 2006-2017, Tomasz Sowa - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * * Neither the name Tomasz Sowa nor the names of contributors to this - * project may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef headerfilettmathbig -#define headerfilettmathbig - -/*! - \file ttmathbig.h - \brief A Class for representing floating point numbers -*/ - -#include "ttmathint.h" -#include "ttmaththreads.h" - -#include - -#ifdef TTMATH_MULTITHREADS -#include -#endif - -namespace ttmath -{ - - -/*! - \brief Big implements the floating point numbers -*/ -template -class Big -{ - -/* - value = mantissa * 2^exponent - - - exponent - an integer value with a sign - - mantissa - an integer value without a sing - - mantissa must be pushed into the left side that is the highest bit from - mantissa must be one (of course if there's another value than zero) -- this job - (pushing bits into the left side) is doing by Standardizing() method - - for example: - if we want to store value one (1) into our Big object we must: - - set mantissa to 1 - - set exponent to 0 - - set info to 0 - - and call method Standardizing() -*/ - - -public: - -Int exponent{0}; -UInt mantissa{0}; -unsigned char info{0}; - - -/*! - Sign - the mask of a bit from 'info' which means that there is a sign - (when the bit is set) -*/ -#define TTMATH_BIG_SIGN 128 - - -/*! - Not a number - if this bit is set that there is not a valid number -*/ -#define TTMATH_BIG_NAN 64 - - -/*! - Zero - if this bit is set that there is value zero - mantissa should be zero and exponent should be zero too - (the Standardizing() method does this) -*/ -#define TTMATH_BIG_ZERO 32 - - - /*! - this method sets NaN if there was a carry (and returns 1 in such a case) - - c can be 0, 1 or other value different from zero - */ - uint CheckCarry(uint c) - { - if( c != 0 ) - { - SetNan(); - return 1; - } - - return 0; - } - -public: - - - /*! - returning the string represents the currect type of the library - we have following types: - - asm_vc_32 - with asm code designed for Microsoft Visual C++ (32 bits) - - asm_gcc_32 - with asm code designed for GCC (32 bits) - - asm_vc_64 - with asm for VC (64 bit) - - asm_gcc_64 - with asm for GCC (64 bit) - - no_asm_32 - pure C++ version (32 bit) - without any asm code - - no_asm_64 - pure C++ version (64 bit) - without any asm code - */ - static const char * LibTypeStr() - { - return UInt::LibTypeStr(); - } - - - /*! - returning the currect type of the library - */ - static LibTypeCode LibType() - { - return UInt::LibType(); - } - - - - /*! - this method moves all bits from mantissa into its left side - (suitably changes the exponent) or if the mantissa is zero - it sets the exponent to zero as well - (and clears the sign bit and sets the zero bit) - - it can return a carry - the carry will be when we don't have enough space in the exponent - - you don't have to use this method if you don't change the mantissa - and exponent directly - */ - uint Standardizing() - { - if( mantissa.IsTheHighestBitSet() ) - { - ClearInfoBit(TTMATH_BIG_ZERO); - return 0; - } - - if( CorrectZero() ) - return 0; - - uint comp = mantissa.CompensationToLeft(); - - return exponent.Sub( comp ); - } - - -private: - - /*! - if the mantissa is equal zero this method sets exponent to zero and - info without the sign - - it returns true if there was the correction - */ - bool CorrectZero() - { - if( mantissa.IsZero() ) - { - SetInfoBit(TTMATH_BIG_ZERO); - ClearInfoBit(TTMATH_BIG_SIGN); - exponent.SetZero(); - - return true; - } - else - { - ClearInfoBit(TTMATH_BIG_ZERO); - } - - return false; - } - - -public: - - /*! - this method clears a specific bit in the 'info' variable - - bit is one of: TTMATH_BIG_SIGN, TTMATH_BIG_NAN etc. - */ - void ClearInfoBit(unsigned char bit) - { - info = info & (unsigned char)(~bit); - } - - - /*! - this method sets a specific bit in the 'info' variable - - bit is one of: TTMATH_BIG_SIGN, TTMATH_BIG_NAN etc. - - */ - void SetInfoBit(unsigned char bit) - { - info = info | bit; - } - - - /*! - this method returns true if a specific bit in the 'info' variable is set - - bit is one of: TTMATH_BIG_SIGN, TTMATH_BIG_NAN etc. - */ - bool IsInfoBit(unsigned char bit) const - { - return (info & bit) != 0; - } - - - /*! - this method sets zero - */ - void SetZero() - { - info = TTMATH_BIG_ZERO; - exponent.SetZero(); - mantissa.SetZero(); - - /* - we don't have to compensate zero - */ - } - - - /*! - this method sets one - */ - void SetOne() - { - info = 0; - mantissa.SetZero(); - mantissa.table[man-1] = TTMATH_UINT_HIGHEST_BIT; - exponent = -sint(man * TTMATH_BITS_PER_UINT - 1); - - // don't have to Standardize() - the last bit from mantissa is set - } - - - /*! - this method sets value 0.5 - */ - void Set05() - { - SetOne(); - exponent.SubOne(); - } - - - /*! - this method sets NaN flag (Not a Number) - when this flag is set that means there is no a valid number - */ - void SetNan() - { - SetInfoBit(TTMATH_BIG_NAN); - } - - - /*! - this method sets NaN flag (Not a Number) - also clears the mantissa and exponent (similarly as it would be a zero value) - */ - void SetZeroNan() - { - SetZero(); - SetNan(); - } - - - /*! - this method swappes this for an argument - */ - void Swap(Big & ss2) - { - unsigned char info_temp = info; - info = ss2.info; - ss2.info = info_temp; - - exponent.Swap(ss2.exponent); - mantissa.Swap(ss2.mantissa); - } - - -private: - - /*! - this method sets the mantissa of the value of pi - */ - void SetMantissaPi() - { - // this is a static table which represents the value of Pi (mantissa of it) - // (first is the highest word) - // we must define this table as 'unsigned int' because - // both on 32bit and 64bit platforms this table is 32bit - static const unsigned int temp_table[] = { - 0xc90fdaa2, 0x2168c234, 0xc4c6628b, 0x80dc1cd1, 0x29024e08, 0x8a67cc74, 0x020bbea6, 0x3b139b22, - 0x514a0879, 0x8e3404dd, 0xef9519b3, 0xcd3a431b, 0x302b0a6d, 0xf25f1437, 0x4fe1356d, 0x6d51c245, - 0xe485b576, 0x625e7ec6, 0xf44c42e9, 0xa637ed6b, 0x0bff5cb6, 0xf406b7ed, 0xee386bfb, 0x5a899fa5, - 0xae9f2411, 0x7c4b1fe6, 0x49286651, 0xece45b3d, 0xc2007cb8, 0xa163bf05, 0x98da4836, 0x1c55d39a, - 0x69163fa8, 0xfd24cf5f, 0x83655d23, 0xdca3ad96, 0x1c62f356, 0x208552bb, 0x9ed52907, 0x7096966d, - 0x670c354e, 0x4abc9804, 0xf1746c08, 0xca18217c, 0x32905e46, 0x2e36ce3b, 0xe39e772c, 0x180e8603, - 0x9b2783a2, 0xec07a28f, 0xb5c55df0, 0x6f4c52c9, 0xde2bcbf6, 0x95581718, 0x3995497c, 0xea956ae5, - 0x15d22618, 0x98fa0510, 0x15728e5a, 0x8aaac42d, 0xad33170d, 0x04507a33, 0xa85521ab, 0xdf1cba64, - 0xecfb8504, 0x58dbef0a, 0x8aea7157, 0x5d060c7d, 0xb3970f85, 0xa6e1e4c7, 0xabf5ae8c, 0xdb0933d7, - 0x1e8c94e0, 0x4a25619d, 0xcee3d226, 0x1ad2ee6b, 0xf12ffa06, 0xd98a0864, 0xd8760273, 0x3ec86a64, - 0x521f2b18, 0x177b200c, 0xbbe11757, 0x7a615d6c, 0x770988c0, 0xbad946e2, 0x08e24fa0, 0x74e5ab31, - 0x43db5bfc, 0xe0fd108e, 0x4b82d120, 0xa9210801, 0x1a723c12, 0xa787e6d7, 0x88719a10, 0xbdba5b26, - 0x99c32718, 0x6af4e23c, 0x1a946834, 0xb6150bda, 0x2583e9ca, 0x2ad44ce8, 0xdbbbc2db, 0x04de8ef9, - 0x2e8efc14, 0x1fbecaa6, 0x287c5947, 0x4e6bc05d, 0x99b2964f, 0xa090c3a2, 0x233ba186, 0x515be7ed, - 0x1f612970, 0xcee2d7af, 0xb81bdd76, 0x2170481c, 0xd0069127, 0xd5b05aa9, 0x93b4ea98, 0x8d8fddc1, - 0x86ffb7dc, 0x90a6c08f, 0x4df435c9, 0x34028492, 0x36c3fab4, 0xd27c7026, 0xc1d4dcb2, 0x602646de, - 0xc9751e76, 0x3dba37bd, 0xf8ff9406, 0xad9e530e, 0xe5db382f, 0x413001ae, 0xb06a53ed, 0x9027d831, - 0x179727b0, 0x865a8918, 0xda3edbeb, 0xcf9b14ed, 0x44ce6cba, 0xced4bb1b, 0xdb7f1447, 0xe6cc254b, - 0x33205151, 0x2bd7af42, 0x6fb8f401, 0x378cd2bf, 0x5983ca01, 0xc64b92ec, 0xf032ea15, 0xd1721d03, - 0xf482d7ce, 0x6e74fef6, 0xd55e702f, 0x46980c82, 0xb5a84031, 0x900b1c9e, 0x59e7c97f, 0xbec7e8f3, - 0x23a97a7e, 0x36cc88be, 0x0f1d45b7, 0xff585ac5, 0x4bd407b2, 0x2b4154aa, 0xcc8f6d7e, 0xbf48e1d8, - 0x14cc5ed2, 0x0f8037e0, 0xa79715ee, 0xf29be328, 0x06a1d58b, 0xb7c5da76, 0xf550aa3d, 0x8a1fbff0, - 0xeb19ccb1, 0xa313d55c, 0xda56c9ec, 0x2ef29632, 0x387fe8d7, 0x6e3c0468, 0x043e8f66, 0x3f4860ee, - 0x12bf2d5b, 0x0b7474d6, 0xe694f91e, 0x6dbe1159, 0x74a3926f, 0x12fee5e4, 0x38777cb6, 0xa932df8c, - 0xd8bec4d0, 0x73b931ba, 0x3bc832b6, 0x8d9dd300, 0x741fa7bf, 0x8afc47ed, 0x2576f693, 0x6ba42466, - 0x3aab639c, 0x5ae4f568, 0x3423b474, 0x2bf1c978, 0x238f16cb, 0xe39d652d, 0xe3fdb8be, 0xfc848ad9, - 0x22222e04, 0xa4037c07, 0x13eb57a8, 0x1a23f0c7, 0x3473fc64, 0x6cea306b, 0x4bcbc886, 0x2f8385dd, - 0xfa9d4b7f, 0xa2c087e8, 0x79683303, 0xed5bdd3a, 0x062b3cf5, 0xb3a278a6, 0x6d2a13f8, 0x3f44f82d, - 0xdf310ee0, 0x74ab6a36, 0x4597e899, 0xa0255dc1, 0x64f31cc5, 0x0846851d, 0xf9ab4819, 0x5ded7ea1, - 0xb1d510bd, 0x7ee74d73, 0xfaf36bc3, 0x1ecfa268, 0x359046f4, 0xeb879f92, 0x4009438b, 0x481c6cd7, - 0x889a002e, 0xd5ee382b, 0xc9190da6, 0xfc026e47, 0x9558e447, 0x5677e9aa, 0x9e3050e2, 0x765694df, - 0xc81f56e8, 0x80b96e71, 0x60c980dd, 0x98a573ea, 0x4472065a, 0x139cd290, 0x6cd1cb72, 0x9ec52a53 // last one was: 0x9ec52a52 - //0x86d44014, ... - // (the last word 0x9ec52a52 was rounded up because the next one is 0x86d44014 -- first bit is one 0x8..) - // 256 32bit words for the mantissa -- about 2464 valid decimal digits - }; - // the value of PI is comming from the website http://zenwerx.com/pi.php - // 3101 digits were taken from this website - // (later the digits were compared with: - // http://www.eveandersson.com/pi/digits/1000000 and http://www.geom.uiuc.edu/~huberty/math5337/groupe/digits.html ) - // and they were set into Big<1,400> type (using operator=(const char*) on a 32bit platform) - // and then the first 256 words were taken into this table - // (TTMATH_BUILTIN_VARIABLES_SIZE on 32bit platform should have the value 256, - // and on 64bit platform value 128 (256/2=128)) - - mantissa.SetFromTable(temp_table, sizeof(temp_table) / sizeof(int)); - } - -public: - - - /*! - this method sets the value of pi - */ - void SetPi() - { - // IMPROVE ME - // give some compiler-time warning when the size of mantissa is greater than the builtin size of the mantissa pi - SetMantissaPi(); - info = 0; - exponent = -sint(man)*sint(TTMATH_BITS_PER_UINT) + 2; - } - - - /*! - this method sets the value of 0.5 * pi - */ - void Set05Pi() - { - // IMPROVE ME - // give some compiler-time warning when the size of mantissa is greater than the builtin size of the mantissa pi - SetMantissaPi(); - info = 0; - exponent = -sint(man)*sint(TTMATH_BITS_PER_UINT) + 1; - } - - - /*! - this method sets the value of 2 * pi - */ - void Set2Pi() - { - // IMPROVE ME - // give some compiler-time warning when the size of mantissa is greater than the builtin size of the mantissa pi - SetMantissaPi(); - info = 0; - exponent = -sint(man)*sint(TTMATH_BITS_PER_UINT) + 3; - } - - - /*! - this method sets the value of e - (the base of the natural logarithm) - */ - void SetE() - { - static const unsigned int temp_table[] = { - 0xadf85458, 0xa2bb4a9a, 0xafdc5620, 0x273d3cf1, 0xd8b9c583, 0xce2d3695, 0xa9e13641, 0x146433fb, - 0xcc939dce, 0x249b3ef9, 0x7d2fe363, 0x630c75d8, 0xf681b202, 0xaec4617a, 0xd3df1ed5, 0xd5fd6561, - 0x2433f51f, 0x5f066ed0, 0x85636555, 0x3ded1af3, 0xb557135e, 0x7f57c935, 0x984f0c70, 0xe0e68b77, - 0xe2a689da, 0xf3efe872, 0x1df158a1, 0x36ade735, 0x30acca4f, 0x483a797a, 0xbc0ab182, 0xb324fb61, - 0xd108a94b, 0xb2c8e3fb, 0xb96adab7, 0x60d7f468, 0x1d4f42a3, 0xde394df4, 0xae56ede7, 0x6372bb19, - 0x0b07a7c8, 0xee0a6d70, 0x9e02fce1, 0xcdf7e2ec, 0xc03404cd, 0x28342f61, 0x9172fe9c, 0xe98583ff, - 0x8e4f1232, 0xeef28183, 0xc3fe3b1b, 0x4c6fad73, 0x3bb5fcbc, 0x2ec22005, 0xc58ef183, 0x7d1683b2, - 0xc6f34a26, 0xc1b2effa, 0x886b4238, 0x611fcfdc, 0xde355b3b, 0x6519035b, 0xbc34f4de, 0xf99c0238, - 0x61b46fc9, 0xd6e6c907, 0x7ad91d26, 0x91f7f7ee, 0x598cb0fa, 0xc186d91c, 0xaefe1309, 0x85139270, - 0xb4130c93, 0xbc437944, 0xf4fd4452, 0xe2d74dd3, 0x64f2e21e, 0x71f54bff, 0x5cae82ab, 0x9c9df69e, - 0xe86d2bc5, 0x22363a0d, 0xabc52197, 0x9b0deada, 0x1dbf9a42, 0xd5c4484e, 0x0abcd06b, 0xfa53ddef, - 0x3c1b20ee, 0x3fd59d7c, 0x25e41d2b, 0x669e1ef1, 0x6e6f52c3, 0x164df4fb, 0x7930e9e4, 0xe58857b6, - 0xac7d5f42, 0xd69f6d18, 0x7763cf1d, 0x55034004, 0x87f55ba5, 0x7e31cc7a, 0x7135c886, 0xefb4318a, - 0xed6a1e01, 0x2d9e6832, 0xa907600a, 0x918130c4, 0x6dc778f9, 0x71ad0038, 0x092999a3, 0x33cb8b7a, - 0x1a1db93d, 0x7140003c, 0x2a4ecea9, 0xf98d0acc, 0x0a8291cd, 0xcec97dcf, 0x8ec9b55a, 0x7f88a46b, - 0x4db5a851, 0xf44182e1, 0xc68a007e, 0x5e0dd902, 0x0bfd64b6, 0x45036c7a, 0x4e677d2c, 0x38532a3a, - 0x23ba4442, 0xcaf53ea6, 0x3bb45432, 0x9b7624c8, 0x917bdd64, 0xb1c0fd4c, 0xb38e8c33, 0x4c701c3a, - 0xcdad0657, 0xfccfec71, 0x9b1f5c3e, 0x4e46041f, 0x388147fb, 0x4cfdb477, 0xa52471f7, 0xa9a96910, - 0xb855322e, 0xdb6340d8, 0xa00ef092, 0x350511e3, 0x0abec1ff, 0xf9e3a26e, 0x7fb29f8c, 0x183023c3, - 0x587e38da, 0x0077d9b4, 0x763e4e4b, 0x94b2bbc1, 0x94c6651e, 0x77caf992, 0xeeaac023, 0x2a281bf6, - 0xb3a739c1, 0x22611682, 0x0ae8db58, 0x47a67cbe, 0xf9c9091b, 0x462d538c, 0xd72b0374, 0x6ae77f5e, - 0x62292c31, 0x1562a846, 0x505dc82d, 0xb854338a, 0xe49f5235, 0xc95b9117, 0x8ccf2dd5, 0xcacef403, - 0xec9d1810, 0xc6272b04, 0x5b3b71f9, 0xdc6b80d6, 0x3fdd4a8e, 0x9adb1e69, 0x62a69526, 0xd43161c1, - 0xa41d570d, 0x7938dad4, 0xa40e329c, 0xcff46aaa, 0x36ad004c, 0xf600c838, 0x1e425a31, 0xd951ae64, - 0xfdb23fce, 0xc9509d43, 0x687feb69, 0xedd1cc5e, 0x0b8cc3bd, 0xf64b10ef, 0x86b63142, 0xa3ab8829, - 0x555b2f74, 0x7c932665, 0xcb2c0f1c, 0xc01bd702, 0x29388839, 0xd2af05e4, 0x54504ac7, 0x8b758282, - 0x2846c0ba, 0x35c35f5c, 0x59160cc0, 0x46fd8251, 0x541fc68c, 0x9c86b022, 0xbb709987, 0x6a460e74, - 0x51a8a931, 0x09703fee, 0x1c217e6c, 0x3826e52c, 0x51aa691e, 0x0e423cfc, 0x99e9e316, 0x50c1217b, - 0x624816cd, 0xad9a95f9, 0xd5b80194, 0x88d9c0a0, 0xa1fe3075, 0xa577e231, 0x83f81d4a, 0x3f2fa457, - 0x1efc8ce0, 0xba8a4fe8, 0xb6855dfe, 0x72b0a66e, 0xded2fbab, 0xfbe58a30, 0xfafabe1c, 0x5d71a87e, - 0x2f741ef8, 0xc1fe86fe, 0xa6bbfde5, 0x30677f0d, 0x97d11d49, 0xf7a8443d, 0x0822e506, 0xa9f4614e, - 0x011e2a94, 0x838ff88c, 0xd68c8bb7, 0xc51eef6d, 0x49ea8ab4, 0xf2c3df5b, 0xb4e0735a, 0xb0d68749 - // 0x2fe26dd4, ... - // 256 32bit words for the mantissa -- about 2464 valid decimal digits - }; - - // above value was calculated using Big<1,400> type on a 32bit platform - // and then the first 256 words were taken, - // the calculating was made by using ExpSurrounding0(1) method - // which took 1420 iterations - // (the result was compared with e taken from http://antwrp.gsfc.nasa.gov/htmltest/gifcity/e.2mil) - // (TTMATH_BUILTIN_VARIABLES_SIZE on 32bit platform should have the value 256, - // and on 64bit platform value 128 (256/2=128)) - - mantissa.SetFromTable(temp_table, sizeof(temp_table) / sizeof(int)); - exponent = -sint(man)*sint(TTMATH_BITS_PER_UINT) + 2; - info = 0; - } - - - /*! - this method sets the value of ln(2) - the natural logarithm from 2 - */ - void SetLn2() - { - static const unsigned int temp_table[] = { - 0xb17217f7, 0xd1cf79ab, 0xc9e3b398, 0x03f2f6af, 0x40f34326, 0x7298b62d, 0x8a0d175b, 0x8baafa2b, - 0xe7b87620, 0x6debac98, 0x559552fb, 0x4afa1b10, 0xed2eae35, 0xc1382144, 0x27573b29, 0x1169b825, - 0x3e96ca16, 0x224ae8c5, 0x1acbda11, 0x317c387e, 0xb9ea9bc3, 0xb136603b, 0x256fa0ec, 0x7657f74b, - 0x72ce87b1, 0x9d6548ca, 0xf5dfa6bd, 0x38303248, 0x655fa187, 0x2f20e3a2, 0xda2d97c5, 0x0f3fd5c6, - 0x07f4ca11, 0xfb5bfb90, 0x610d30f8, 0x8fe551a2, 0xee569d6d, 0xfc1efa15, 0x7d2e23de, 0x1400b396, - 0x17460775, 0xdb8990e5, 0xc943e732, 0xb479cd33, 0xcccc4e65, 0x9393514c, 0x4c1a1e0b, 0xd1d6095d, - 0x25669b33, 0x3564a337, 0x6a9c7f8a, 0x5e148e82, 0x074db601, 0x5cfe7aa3, 0x0c480a54, 0x17350d2c, - 0x955d5179, 0xb1e17b9d, 0xae313cdb, 0x6c606cb1, 0x078f735d, 0x1b2db31b, 0x5f50b518, 0x5064c18b, - 0x4d162db3, 0xb365853d, 0x7598a195, 0x1ae273ee, 0x5570b6c6, 0x8f969834, 0x96d4e6d3, 0x30af889b, - 0x44a02554, 0x731cdc8e, 0xa17293d1, 0x228a4ef9, 0x8d6f5177, 0xfbcf0755, 0x268a5c1f, 0x9538b982, - 0x61affd44, 0x6b1ca3cf, 0x5e9222b8, 0x8c66d3c5, 0x422183ed, 0xc9942109, 0x0bbb16fa, 0xf3d949f2, - 0x36e02b20, 0xcee886b9, 0x05c128d5, 0x3d0bd2f9, 0x62136319, 0x6af50302, 0x0060e499, 0x08391a0c, - 0x57339ba2, 0xbeba7d05, 0x2ac5b61c, 0xc4e9207c, 0xef2f0ce2, 0xd7373958, 0xd7622658, 0x901e646a, - 0x95184460, 0xdc4e7487, 0x156e0c29, 0x2413d5e3, 0x61c1696d, 0xd24aaebd, 0x473826fd, 0xa0c238b9, - 0x0ab111bb, 0xbd67c724, 0x972cd18b, 0xfbbd9d42, 0x6c472096, 0xe76115c0, 0x5f6f7ceb, 0xac9f45ae, - 0xcecb72f1, 0x9c38339d, 0x8f682625, 0x0dea891e, 0xf07afff3, 0xa892374e, 0x175eb4af, 0xc8daadd8, - 0x85db6ab0, 0x3a49bd0d, 0xc0b1b31d, 0x8a0e23fa, 0xc5e5767d, 0xf95884e0, 0x6425a415, 0x26fac51c, - 0x3ea8449f, 0xe8f70edd, 0x062b1a63, 0xa6c4c60c, 0x52ab3316, 0x1e238438, 0x897a39ce, 0x78b63c9f, - 0x364f5b8a, 0xef22ec2f, 0xee6e0850, 0xeca42d06, 0xfb0c75df, 0x5497e00c, 0x554b03d7, 0xd2874a00, - 0x0ca8f58d, 0x94f0341c, 0xbe2ec921, 0x56c9f949, 0xdb4a9316, 0xf281501e, 0x53daec3f, 0x64f1b783, - 0x154c6032, 0x0e2ff793, 0x33ce3573, 0xfacc5fdc, 0xf1178590, 0x3155bbd9, 0x0f023b22, 0x0224fcd8, - 0x471bf4f4, 0x45f0a88a, 0x14f0cd97, 0x6ea354bb, 0x20cdb5cc, 0xb3db2392, 0x88d58655, 0x4e2a0e8a, - 0x6fe51a8c, 0xfaa72ef2, 0xad8a43dc, 0x4212b210, 0xb779dfe4, 0x9d7307cc, 0x846532e4, 0xb9694eda, - 0xd162af05, 0x3b1751f3, 0xa3d091f6, 0x56658154, 0x12b5e8c2, 0x02461069, 0xac14b958, 0x784934b8, - 0xd6cce1da, 0xa5053701, 0x1aa4fb42, 0xb9a3def4, 0x1bda1f85, 0xef6fdbf2, 0xf2d89d2a, 0x4b183527, - 0x8fd94057, 0x89f45681, 0x2b552879, 0xa6168695, 0xc12963b0, 0xff01eaab, 0x73e5b5c1, 0x585318e7, - 0x624f14a5, 0x1a4a026b, 0x68082920, 0x57fd99b6, 0x6dc085a9, 0x8ac8d8ca, 0xf9eeeea9, 0x8a2400ca, - 0xc95f260f, 0xd10036f9, 0xf91096ac, 0x3195220a, 0x1a356b2a, 0x73b7eaad, 0xaf6d6058, 0x71ef7afb, - 0x80bc4234, 0x33562e94, 0xb12dfab4, 0x14451579, 0xdf59eae0, 0x51707062, 0x4012a829, 0x62c59cab, - 0x347f8304, 0xd889659e, 0x5a9139db, 0x14efcc30, 0x852be3e8, 0xfc99f14d, 0x1d822dd6, 0xe2f76797, - 0xe30219c8, 0xaa9ce884, 0x8a886eb3, 0xc87b7295, 0x988012e8, 0x314186ed, 0xbaf86856, 0xccd3c3b6, - 0xee94e62f, 0x110a6783, 0xd2aae89c, 0xcc3b76fc, 0x435a0ce1, 0x34c2838f, 0xd571ec6c, 0x1366a993 // last one was: 0x1366a992 - //0xcbb9ac40, ... - // (the last word 0x1366a992 was rounded up because the next one is 0xcbb9ac40 -- first bit is one 0xc..) - // 256 32bit words for the mantissa -- about 2464 valid decimal digits - }; - - // above value was calculated using Big<1,400> type on a 32bit platform - // and then the first 256 words were taken, - // the calculating was made by using LnSurrounding1(2) method - // which took 4035 iterations - // (the result was compared with ln(2) taken from http://ja0hxv.calico.jp/pai/estart.html) - // (TTMATH_BUILTIN_VARIABLES_SIZE on 32bit platform should have the value 256, - // and on 64bit platform value 128 (256/2=128)) - - mantissa.SetFromTable(temp_table, sizeof(temp_table) / sizeof(int)); - exponent = -sint(man)*sint(TTMATH_BITS_PER_UINT); - info = 0; - } - - - /*! - this method sets the value of ln(10) - the natural logarithm from 10 - - I introduced this constant especially to make the conversion ToString() - being faster. In fact the method ToString() is keeping values of logarithms - it has calculated but it must calculate the logarithm at least once. - If a program, which uses this library, is running for a long time this - would be ok, but for programs which are running shorter, for example for - CGI applications which only once are printing values, this would be much - inconvenience. Then if we're printing with base (radix) 10 and the mantissa - of our value is smaller than or equal to TTMATH_BUILTIN_VARIABLES_SIZE - we don't calculate the logarithm but take it from this constant. - */ - void SetLn10() - { - static const unsigned int temp_table[] = { - 0x935d8ddd, 0xaaa8ac16, 0xea56d62b, 0x82d30a28, 0xe28fecf9, 0xda5df90e, 0x83c61e82, 0x01f02d72, - 0x962f02d7, 0xb1a8105c, 0xcc70cbc0, 0x2c5f0d68, 0x2c622418, 0x410be2da, 0xfb8f7884, 0x02e516d6, - 0x782cf8a2, 0x8a8c911e, 0x765aa6c3, 0xb0d831fb, 0xef66ceb0, 0x4ab3c6fa, 0x5161bb49, 0xd219c7bb, - 0xca67b35b, 0x23605085, 0x8e93368d, 0x44789c4f, 0x5b08b057, 0xd5ede20f, 0x469ea58e, 0x9305e981, - 0xe2478fca, 0xad3aee98, 0x9cd5b42e, 0x6a271619, 0xa47ecb26, 0x978c5d4f, 0xdb1d28ea, 0x57d4fdc0, - 0xe40bf3cc, 0x1e14126a, 0x45765cde, 0x268339db, 0xf47fa96d, 0xeb271060, 0xaf88486e, 0xa9b7401e, - 0x3dfd3c51, 0x748e6d6e, 0x3848c8d2, 0x5faf1bca, 0xe88047f1, 0x7b0d9b50, 0xa949eaaa, 0xdf69e8a5, - 0xf77e3760, 0x4e943960, 0xe38a5700, 0xffde2db1, 0xad6bfbff, 0xd821ba0a, 0x4cb0466d, 0x61ba648e, - 0xef99c8e5, 0xf6974f36, 0x3982a78c, 0xa45ddfc8, 0x09426178, 0x19127a6e, 0x3b70fcda, 0x2d732d47, - 0xb5e4b1c8, 0xc0e5a10a, 0xaa6604a5, 0x324ec3dc, 0xbc64ea80, 0x6e198566, 0x1f1d366c, 0x20663834, - 0x4d5e843f, 0x20642b97, 0x0a62d18e, 0x478f7bd5, 0x8fcd0832, 0x4a7b32a6, 0xdef85a05, 0xeb56323a, - 0x421ef5e0, 0xb00410a0, 0xa0d9c260, 0x794a976f, 0xf6ff363d, 0xb00b6b33, 0xf42c58de, 0xf8a3c52d, - 0xed69b13d, 0xc1a03730, 0xb6524dc1, 0x8c167e86, 0x99d6d20e, 0xa2defd2b, 0xd006f8b4, 0xbe145a2a, - 0xdf3ccbb3, 0x189da49d, 0xbc1261c8, 0xb3e4daad, 0x6a36cecc, 0xb2d5ae5b, 0x89bf752f, 0xb5dfb353, - 0xff3065c4, 0x0cfceec8, 0x1be5a9a9, 0x67fddc57, 0xc4b83301, 0x006bf062, 0x4b40ed7a, 0x56c6cdcd, - 0xa2d6fe91, 0x388e9e3e, 0x48a93f5f, 0x5e3b6eb4, 0xb81c4a5b, 0x53d49ea6, 0x8e668aea, 0xba83c7f8, - 0xfb5f06c3, 0x58ac8f70, 0xfa9d8c59, 0x8c574502, 0xbaf54c96, 0xc84911f0, 0x0482d095, 0x1a0af022, - 0xabbab080, 0xec97efd3, 0x671e4e0e, 0x52f166b6, 0xcd5cd226, 0x0dc67795, 0x2e1e34a3, 0xf799677f, - 0x2c1d48f1, 0x2944b6c5, 0x2ba1307e, 0x704d67f9, 0x1c1035e4, 0x4e927c63, 0x03cf12bf, 0xe2cd2e31, - 0xf8ee4843, 0x344d51b0, 0xf37da42b, 0x9f0b0fd9, 0x134fb2d9, 0xf815e490, 0xd966283f, 0x23962766, - 0xeceab1e4, 0xf3b5fc86, 0x468127e2, 0xb606d10d, 0x3a45f4b6, 0xb776102d, 0x2fdbb420, 0x80c8fa84, - 0xd0ff9f45, 0xc58aef38, 0xdb2410fd, 0x1f1cebad, 0x733b2281, 0x52ca5f36, 0xddf29daa, 0x544334b8, - 0xdeeaf659, 0x4e462713, 0x1ed485b4, 0x6a0822e1, 0x28db471c, 0xa53938a8, 0x44c3bef7, 0xf35215c8, - 0xb382bc4e, 0x3e4c6f15, 0x6285f54c, 0x17ab408e, 0xccbf7f5e, 0xd16ab3f6, 0xced2846d, 0xf457e14f, - 0xbb45d9c5, 0x646ad497, 0xac697494, 0x145de32e, 0x93907128, 0xd263d521, 0x79efb424, 0xd64651d6, - 0xebc0c9f0, 0xbb583a44, 0xc6412c84, 0x85bb29a6, 0x4d31a2cd, 0x92954469, 0xa32b1abd, 0xf7f5202c, - 0xa4aa6c93, 0x2e9b53cf, 0x385ab136, 0x2741f356, 0x5de9c065, 0x6009901c, 0x88abbdd8, 0x74efcf73, - 0x3f761ad4, 0x35f3c083, 0xfd6b8ee0, 0x0bef11c7, 0xc552a89d, 0x58ce4a21, 0xd71e54f2, 0x4157f6c7, - 0xd4622316, 0xe98956d7, 0x450027de, 0xcbd398d8, 0x4b98b36a, 0x0724c25c, 0xdb237760, 0xe9324b68, - 0x7523e506, 0x8edad933, 0x92197f00, 0xb853a326, 0xb330c444, 0x65129296, 0x34bc0670, 0xe177806d, - 0xe338dac4, 0x5537492a, 0xe19add83, 0xcf45000f, 0x5b423bce, 0x6497d209, 0xe30e18a1, 0x3cbf0687, - 0x67973103, 0xd9485366, 0x81506bba, 0x2e93a9a4, 0x7dd59d3f, 0xf17cd746, 0x8c2075be, 0x552a4348 // last one was: 0x552a4347 - // 0xb4a638ef, ... - //(the last word 0x552a4347 was rounded up because the next one is 0xb4a638ef -- first bit is one 0xb..) - // 256 32bit words for the mantissa -- about 2464 valid digits (decimal) - }; - - // above value was calculated using Big<1,400> type on a 32bit platform - // and then the first 256 32bit words were taken, - // the calculating was made by using LnSurrounding1(10) method - // which took 22080 iterations - // (the result was compared with ln(10) taken from http://ja0hxv.calico.jp/pai/estart.html) - // (the formula used in LnSurrounding1(x) converges badly when - // the x is greater than one but in fact we can use it, only the - // number of iterations will be greater) - // (TTMATH_BUILTIN_VARIABLES_SIZE on 32bit platform should have the value 256, - // and on 64bit platform value 128 (256/2=128)) - - mantissa.SetFromTable(temp_table, sizeof(temp_table) / sizeof(int)); - exponent = -sint(man)*sint(TTMATH_BITS_PER_UINT) + 2; - info = 0; - } - - - /*! - this method sets the maximum value which can be held in this type - */ - void SetMax() - { - info = 0; - mantissa.SetMax(); - exponent.SetMax(); - - // we don't have to use 'Standardizing()' because the last bit from - // the mantissa is set - } - - - /*! - this method sets the minimum value which can be held in this type - */ - void SetMin() - { - info = 0; - - mantissa.SetMax(); - exponent.SetMax(); - SetSign(); - - // we don't have to use 'Standardizing()' because the last bit from - // the mantissa is set - } - - - /*! - testing whether there is a value zero or not - */ - bool IsZero() const - { - return IsInfoBit(TTMATH_BIG_ZERO); - } - - - /*! - this method returns true when there's the sign set - also we don't check the NaN flag - */ - bool IsSign() const - { - return IsInfoBit(TTMATH_BIG_SIGN); - } - - - /*! - this method returns true when there is not a valid number - */ - bool IsNan() const - { - return IsInfoBit(TTMATH_BIG_NAN); - } - - - - /*! - this method clears the sign - (there'll be an absolute value) - - samples - - -1 -> 1 - - 2 -> 2 - */ - void Abs() - { - ClearInfoBit(TTMATH_BIG_SIGN); - } - - - /*! - this method remains the 'sign' of the value - - samples - - -2 = -1 - - 0 = 0 - - 10 = 1 - */ - void Sgn() - { - // we have to check the NaN flag, because the next SetOne() method would clear it - if( IsNan() ) - return; - - if( IsSign() ) - { - SetOne(); - SetSign(); - } - else - if( IsZero() ) - SetZero(); // !! is nedeed here? - else - SetOne(); - } - - - - /*! - this method sets the sign - - samples - - -1 -> -1 - - 2 -> -2 - - we do not check whether there is a zero or not, if you're using this method - you must be sure that the value is (or will be afterwards) different from zero - */ - void SetSign() - { - SetInfoBit(TTMATH_BIG_SIGN); - } - - - /*! - this method changes the sign - when there is a value of zero then the sign is not changed - - samples - - -1 -> 1 - - 2 -> -2 - */ - void ChangeSign() - { - // we don't have to check the NaN flag here - - if( IsZero() ) - return; - - if( IsSign() ) - ClearInfoBit(TTMATH_BIG_SIGN); - else - SetInfoBit(TTMATH_BIG_SIGN); - } - - - -private: - - /*! - this method does the half-to-even rounding (banker's rounding) - - if is_half is: - - true - that means the rest was equal the half (0.5 decimal) - - false - that means the rest was greater than a half (greater than 0.5 decimal) - - if the rest was less than a half then don't call this method - (the rounding should does nothing then) - */ - uint RoundHalfToEven(bool is_half, bool rounding_up = true) - { - uint c = 0; - - if( !is_half || mantissa.IsTheLowestBitSet() ) - { - if( rounding_up ) - { - if( mantissa.AddOne() ) - { - mantissa.Rcr(1, 1); - c = exponent.AddOne(); - } - } - else - { - #ifdef TTMATH_DEBUG - uint c_from_zero = - #endif - mantissa.SubOne(); - - // we're using rounding_up=false in Add() when the mantissas have different signs - // mantissa can be zero only when previous mantissa was equal to ss2.mantissa - // but in such a case 'last_bit_set' will not be set and consequently 'do_rounding' will be false - TTMATH_ASSERT( c_from_zero == 0 ) - } - } - - return c; - } - - - - - - /*! - * - * basic mathematic functions - * - */ - - - /*! - this method adds one to the existing value - */ - uint AddOne() - { - Big one; - - one.SetOne(); - - return Add(one); - } - - - /*! - this method subtracts one from the existing value - */ - uint SubOne() - { - Big one; - - one.SetOne(); - - return Sub(one); - } - - -private: - - - /*! - an auxiliary method for adding - */ - void AddCheckExponents( Big & ss2, - Int & exp_offset, - bool & last_bit_set, - bool & rest_zero, - bool & do_adding, - bool & do_rounding) - { - Int mantissa_size_in_bits( man * TTMATH_BITS_PER_UINT ); - - if( exp_offset == mantissa_size_in_bits ) - { - last_bit_set = ss2.mantissa.IsTheHighestBitSet(); - rest_zero = ss2.mantissa.AreFirstBitsZero(man*TTMATH_BITS_PER_UINT - 1); - do_rounding = true; // we'are only rounding - } - else - if( exp_offset < mantissa_size_in_bits ) - { - uint moved = exp_offset.ToInt(); // how many times we must move ss2.mantissa - rest_zero = true; - - if( moved > 0 ) - { - last_bit_set = static_cast( ss2.mantissa.GetBit(moved-1) ); - - if( moved > 1 ) - rest_zero = ss2.mantissa.AreFirstBitsZero(moved - 1); - - // (2) moving 'exp_offset' times - ss2.mantissa.Rcr(moved, 0); - } - - do_adding = true; - do_rounding = true; - } - - // if exp_offset is greater than mantissa_size_in_bits then we do nothing - // ss2 is too small for taking into consideration in the sum - } - - - /*! - an auxiliary method for adding - */ - uint AddMantissas( Big & ss2, - bool & last_bit_set, - bool & rest_zero) - { - uint c = 0; - - if( IsSign() == ss2.IsSign() ) - { - // values have the same signs - if( mantissa.Add(ss2.mantissa) ) - { - // we have one bit more from addition (carry) - // now rest_zero means the old rest_zero with the old last_bit_set - rest_zero = (!last_bit_set && rest_zero); - last_bit_set = mantissa.Rcr(1,1); - c += exponent.AddOne(); - } - } - else - { - // values have different signs - // there shouldn't be a carry here because - // (1) (2) guarantee that the mantissa of this - // is greater than or equal to the mantissa of the ss2 - - #ifdef TTMATH_DEBUG - uint c_temp = - #endif - mantissa.Sub(ss2.mantissa); - - TTMATH_ASSERT( c_temp == 0 ) - } - - return c; - } - - -public: - - - /*! - Addition this = this + ss2 - - it returns carry if the sum is too big - */ - uint Add(Big ss2, bool round = true, bool adding = true) - { - bool last_bit_set, rest_zero, do_adding, do_rounding, rounding_up; - Int exp_offset( exponent ); - uint c = 0; - - if( IsNan() || ss2.IsNan() ) - return CheckCarry(1); - - if( !adding ) - ss2.ChangeSign(); // subtracting - - exp_offset.Sub( ss2.exponent ); - exp_offset.Abs(); - - // (1) abs(this) will be >= abs(ss2) - if( SmallerWithoutSignThan(ss2) ) - Swap(ss2); - - if( ss2.IsZero() ) - return 0; - - last_bit_set = rest_zero = do_adding = do_rounding = false; - rounding_up = (IsSign() == ss2.IsSign()); - - AddCheckExponents(ss2, exp_offset, last_bit_set, rest_zero, do_adding, do_rounding); - - if( do_adding ) - c += AddMantissas(ss2, last_bit_set, rest_zero); - - if( !round || !last_bit_set ) - do_rounding = false; - - if( do_rounding ) - c += RoundHalfToEven(rest_zero, rounding_up); - - if( do_adding || do_rounding ) - c += Standardizing(); - - return CheckCarry(c); - } - - - /*! - Subtraction this = this - ss2 - - it returns carry if the result is too big - */ - uint Sub(const Big & ss2, bool round = true) - { - return Add(ss2, round, false); - } - - - /*! - bitwise AND - - this and ss2 must be >= 0 - - return values: - - 0 - ok - - 1 - carry - - 2 - this or ss2 was negative - */ - uint BitAnd(Big ss2) - { - if( IsNan() || ss2.IsNan() ) - return CheckCarry(1); - - if( IsSign() || ss2.IsSign() ) - { - SetNan(); - return 2; - } - - if( IsZero() ) - return 0; - - if( ss2.IsZero() ) - { - SetZero(); - return 0; - } - - Int exp_offset( exponent ); - Int mantissa_size_in_bits( man * TTMATH_BITS_PER_UINT ); - - uint c = 0; - - exp_offset.Sub( ss2.exponent ); - exp_offset.Abs(); - - // abs(this) will be >= abs(ss2) - if( SmallerWithoutSignThan(ss2) ) - Swap(ss2); - - if( exp_offset >= mantissa_size_in_bits ) - { - // the second value is too small - SetZero(); - return 0; - } - - // exp_offset < mantissa_size_in_bits, moving 'exp_offset' times - ss2.mantissa.Rcr( exp_offset.ToInt(), 0 ); - mantissa.BitAnd(ss2.mantissa); - - c += Standardizing(); - - return CheckCarry(c); - } - - - /*! - bitwise OR - - this and ss2 must be >= 0 - return values: - - - 0 - ok - - 1 - carry - - 2 - this or ss2 was negative - */ - uint BitOr(Big ss2) - { - if( IsNan() || ss2.IsNan() ) - return CheckCarry(1); - - if( IsSign() || ss2.IsSign() ) - { - SetNan(); - return 2; - } - - if( IsZero() ) - { - *this = ss2; - return 0; - } - - if( ss2.IsZero() ) - return 0; - - Int exp_offset( exponent ); - Int mantissa_size_in_bits( man * TTMATH_BITS_PER_UINT ); - - uint c = 0; - - exp_offset.Sub( ss2.exponent ); - exp_offset.Abs(); - - // abs(this) will be >= abs(ss2) - if( SmallerWithoutSignThan(ss2) ) - Swap(ss2); - - if( exp_offset >= mantissa_size_in_bits ) - // the second value is too small - return 0; - - // exp_offset < mantissa_size_in_bits, moving 'exp_offset' times - ss2.mantissa.Rcr( exp_offset.ToInt(), 0 ); - mantissa.BitOr(ss2.mantissa); - - c += Standardizing(); - - return CheckCarry(c); - } - - - /*! - bitwise XOR - - this and ss2 must be >= 0 - return values: - - - 0 - ok - - 1 - carry - - 2 - this or ss2 was negative - */ - uint BitXor(Big ss2) - { - if( IsNan() || ss2.IsNan() ) - return CheckCarry(1); - - if( IsSign() || ss2.IsSign() ) - { - SetNan(); - return 2; - } - - if( ss2.IsZero() ) - return 0; - - if( IsZero() ) - { - *this = ss2; - return 0; - } - - Int exp_offset( exponent ); - Int mantissa_size_in_bits( man * TTMATH_BITS_PER_UINT ); - - uint c = 0; - - exp_offset.Sub( ss2.exponent ); - exp_offset.Abs(); - - // abs(this) will be >= abs(ss2) - if( SmallerWithoutSignThan(ss2) ) - Swap(ss2); - - if( exp_offset >= mantissa_size_in_bits ) - // the second value is too small - return 0; - - // exp_offset < mantissa_size_in_bits, moving 'exp_offset' times - ss2.mantissa.Rcr( exp_offset.ToInt(), 0 ); - mantissa.BitXor(ss2.mantissa); - - c += Standardizing(); - - return CheckCarry(c); - } - - - - /*! - Multiplication this = this * ss2 (ss2 is uint) - - ss2 without a sign - */ - uint MulUInt(uint ss2) - { - UInt man_result; - uint i,c = 0; - - if( IsNan() ) - return 1; - - if( IsZero() ) - return 0; - - if( ss2 == 0 ) - { - SetZero(); - return 0; - } - - // man_result = mantissa * ss2.mantissa - mantissa.MulInt(ss2, man_result); - - sint bit = UInt::FindLeadingBitInWord(man_result.table[man]); // man - last word - - if( bit!=-1 && uint(bit) > (TTMATH_BITS_PER_UINT/2) ) - { - // 'i' will be from 0 to TTMATH_BITS_PER_UINT - i = man_result.CompensationToLeft(); - c = exponent.Add( TTMATH_BITS_PER_UINT - i ); - - for(i=0 ; i0 && (tab[len-1] & TTMATH_UINT_HIGHEST_BIT)!=0 ) - - for(i=0 ; i & ss2, bool round = true) - { - TTMATH_REFERENCE_ASSERT( ss2 ) - - UInt man_result; - uint c = 0; - uint i; - - if( IsNan() || ss2.IsNan() ) - return CheckCarry(1); - - if( IsZero() ) - return 0; - - if( ss2.IsZero() ) - { - SetZero(); - return 0; - } - - // man_result = mantissa * ss2.mantissa - mantissa.MulBig(ss2.mantissa, man_result); - - // 'i' will be from 0 to man*TTMATH_BITS_PER_UINT - // because mantissa and ss2.mantissa are standardized - // (the highest bit in man_result is set to 1 or - // if there is a zero value in man_result the method CompensationToLeft() - // returns 0 but we'll correct this at the end in Standardizing() method) - i = man_result.CompensationToLeft(); - uint exp_add = man * TTMATH_BITS_PER_UINT - i; - - if( exp_add ) - c += exponent.Add( exp_add ); - - c += exponent.Add( ss2.exponent ); - - for(i=0 ; i & ss2, bool round = true) - { - if( this == &ss2 ) - { - Big copy_ss2(ss2); - return MulRef(copy_ss2, round); - } - else - { - return MulRef(ss2, round); - } - } - - -private: - - /*! - division this = this / ss2 - - return value: - - 0 - ok - - 1 - carry (in a division carry can be as well) - - 2 - improper argument (ss2 is zero) - */ - uint DivRef(const Big & ss2, bool round = true) - { - TTMATH_REFERENCE_ASSERT( ss2 ) - - UInt man1; - UInt man2; - uint i,c = 0; - - if( IsNan() || ss2.IsNan() ) - return CheckCarry(1); - - if( ss2.IsZero() ) - { - SetNan(); - return 2; - } - - if( IsZero() ) - return 0; - - // !! this two loops can be joined together - - for(i=0 ; i & ss2, bool round = true) - { - if( this == &ss2 ) - { - Big copy_ss2(ss2); - return DivRef(copy_ss2, round); - } - else - { - return DivRef(ss2, round); - } - } - - -private: - - /*! - the remainder from a division - */ - uint ModRef(const Big & ss2) - { - TTMATH_REFERENCE_ASSERT( ss2 ) - - uint c = 0; - - if( IsNan() || ss2.IsNan() ) - return CheckCarry(1); - - if( ss2.IsZero() ) - { - SetNan(); - return 2; - } - - if( !SmallerWithoutSignThan(ss2) ) - { - Big temp(*this); - - c = temp.Div(ss2); - temp.SkipFraction(); - c += temp.Mul(ss2); - c += Sub(temp); - - if( !SmallerWithoutSignThan( ss2 ) ) - c += 1; - } - - return CheckCarry(c); - } - - -public: - - /*! - caltulate the remainder from a division - - samples - - 12.6 mod 3 = 0.6 because 12.6 = 3*4 + 0.6 - - -12.6 mod 3 = -0.6 bacause -12.6 = 3*(-4) + (-0.6) - - 12.6 mod -3 = 0.6 - - -12.6 mod -3 = -0.6 - - in other words: this(old) = ss2 * q + this(new) - - return value: - - 0 - ok - - 1 - carry - - 2 - improper argument (ss2 is zero) - */ - uint Mod(const Big & ss2) - { - if( this == &ss2 ) - { - Big copy_ss2(ss2); - return ModRef(copy_ss2); - } - else - { - return ModRef(ss2); - } - } - - - /*! - this method returns: 'this' mod 2 - (either zero or one) - - this method is much faster than using Mod( object_with_value_two ) - */ - uint Mod2() const - { - if( exponent>sint(0) || exponent<=-sint(man*TTMATH_BITS_PER_UINT) ) - return 0; - - sint exp_int = exponent.ToInt(); - // 'exp_int' is negative (or zero), we set it as positive - exp_int = -exp_int; - - return mantissa.GetBit(exp_int); - } - - - /*! - power this = this ^ pow - (pow without a sign) - - binary algorithm (r-to-l) - - return values: - - 0 - ok - - 1 - carry - - 2 - incorrect arguments (0^0) - */ - template - uint Pow(UInt pow) - { - if( IsNan() ) - return 1; - - if( IsZero() ) - { - if( pow.IsZero() ) - { - // we don't define zero^zero - SetNan(); - return 2; - } - - // 0^(+something) is zero - return 0; - } - - Big start(*this); - Big result; - result.SetOne(); - uint c = 0; - - while( !c ) - { - if( pow.table[0] & 1 ) - c += result.Mul(start); - - pow.Rcr(1); - - if( pow.IsZero() ) - break; - - c += start.Mul(start); - } - - *this = result; - - return CheckCarry(c); - } - - - /*! - power this = this ^ pow - p can be negative - - return values: - - 0 - ok - - 1 - carry - - 2 - incorrect arguments 0^0 or 0^(-something) - */ - template - uint Pow(Int pow) - { - if( IsNan() ) - return 1; - - if( !pow.IsSign() ) - return Pow( UInt(pow) ); - - if( IsZero() ) - { - // if 'p' is negative then - // 'this' must be different from zero - SetNan(); - return 2; - } - - uint c = pow.ChangeSign(); - - Big t(*this); - c += t.Pow( UInt(pow) ); // here can only be a carry (return:1) - - SetOne(); - c += Div(t); - - return CheckCarry(c); - } - - - /*! - power this = this ^ abs([pow]) - pow is treated as a value without a sign and without a fraction - if pow has a sign then the method pow.Abs() is used - if pow has a fraction the fraction is skipped (not used in calculation) - - return values: - - 0 - ok - - 1 - carry - - 2 - incorrect arguments (0^0) - */ - uint PowUInt(Big pow) - { - if( IsNan() || pow.IsNan() ) - return CheckCarry(1); - - if( IsZero() ) - { - if( pow.IsZero() ) - { - SetNan(); - return 2; - } - - // 0^(+something) is zero - return 0; - } - - if( pow.IsSign() ) - pow.Abs(); - - Big start(*this); - Big result; - Big one; - uint c = 0; - one.SetOne(); - result = one; - - while( !c ) - { - if( pow.Mod2() ) - c += result.Mul(start); - - c += pow.exponent.SubOne(); - - if( pow < one ) - break; - - c += start.Mul(start); - } - - *this = result; - - return CheckCarry(c); - } - - - /*! - power this = this ^ [pow] - pow is treated as a value without a fraction - pow can be negative - - return values: - - 0 - ok - - 1 - carry - - 2 - incorrect arguments 0^0 or 0^(-something) - */ - uint PowInt(const Big & pow) - { - if( IsNan() || pow.IsNan() ) - return CheckCarry(1); - - if( !pow.IsSign() ) - return PowUInt(pow); - - if( IsZero() ) - { - // if 'pow' is negative then - // 'this' must be different from zero - SetNan(); - return 2; - } - - Big temp(*this); - uint c = temp.PowUInt(pow); // here can only be a carry (result:1) - - SetOne(); - c += Div(temp); - - return CheckCarry(c); - } - - - /*! - power this = this ^ pow - this must be greater than zero (this > 0) - pow can be negative and with fraction - - return values: - - 0 - ok - - 1 - carry - - 2 - incorrect argument ('this' <= 0) - */ - uint PowFrac(const Big & pow) - { - if( IsNan() || pow.IsNan() ) - return CheckCarry(1); - - Big temp; - uint c = temp.Ln(*this); - - if( c != 0 ) // can be 2 from Ln() - { - SetNan(); - return c; - } - - c += temp.Mul(pow); - c += Exp(temp); - - return CheckCarry(c); - } - - - /*! - power this = this ^ pow - pow can be negative and with fraction - - return values: - - 0 - ok - - 1 - carry - - 2 - incorrect argument ('this' or 'pow') - */ - uint Pow(const Big & pow) - { - if( IsNan() || pow.IsNan() ) - return CheckCarry(1); - - if( IsZero() ) - { - // 0^pow will be 0 only for pow>0 - if( pow.IsSign() || pow.IsZero() ) - { - SetNan(); - return 2; - } - - SetZero(); - - return 0; - } - - if( pow.exponent>-sint(man*TTMATH_BITS_PER_UINT) && pow.exponent<=0 ) - { - if( pow.IsInteger() ) - return PowInt( pow ); - } - - return PowFrac(pow); - } - - - /*! - this function calculates the square root - e.g. let this=9 then this.Sqrt() gives 3 - - return: - - 0 - ok - - 1 - carry - - 2 - improper argument (this<0 or NaN) - */ - uint Sqrt() - { - if( IsNan() || IsSign() ) - { - SetNan(); - return 2; - } - - if( IsZero() ) - return 0; - - Big old(*this); - Big ln; - uint c = 0; - - // we're using the formula: sqrt(x) = e ^ (ln(x) / 2) - c += ln.Ln(*this); - c += ln.exponent.SubOne(); // ln = ln / 2 - c += Exp(ln); - - // above formula doesn't give accurate results for some integers - // e.g. Sqrt(81) would not be 9 but a value very closed to 9 - // we're rounding the result, calculating result*result and comparing - // with the old value, if they are equal then the result is an integer too - - if( !c && old.IsInteger() && !IsInteger() ) - { - Big temp(*this); - c += temp.Round(); - - Big temp2(temp); - c += temp.Mul(temp2); - - if( temp == old ) - *this = temp2; - } - - return CheckCarry(c); - } - - -private: - -#ifdef TTMATH_CONSTANTSGENERATOR -public: -#endif - - /*! - Exponent this = exp(x) = e^x where x is in (-1,1) - - we're using the formula exp(x) = 1 + (x)/(1!) + (x^2)/(2!) + (x^3)/(3!) + ... - */ - void ExpSurrounding0(const Big & x, uint * steps = 0) - { - TTMATH_REFERENCE_ASSERT( x ) - - Big denominator, denominator_i; - Big one, old_value, next_part; - Big numerator = x; - - SetOne(); - one.SetOne(); - denominator.SetOne(); - denominator_i.SetOne(); - - uint i; - old_value = *this; - - // we begin from 1 in order to not test at the beginning - #ifdef TTMATH_CONSTANTSGENERATOR - for(i=1 ; true ; ++i) - #else - for(i=1 ; i<=TTMATH_ARITHMETIC_MAX_LOOP ; ++i) - #endif - { - bool testing = ((i & 3) == 0); // it means '(i % 4) == 0' - - next_part = numerator; - - if( next_part.Div( denominator ) ) - // if there is a carry here we only break the loop - // however the result we return as good - // it means there are too many parts of the formula - break; - - // there shouldn't be a carry here - Add( next_part ); - - if( testing ) - { - if( old_value == *this ) - // we've added next few parts of the formula but the result - // is still the same then we break the loop - break; - else - old_value = *this; - } - - // we set the denominator and the numerator for a next part of the formula - if( denominator_i.Add(one) ) - // if there is a carry here the result we return as good - break; - - if( denominator.Mul(denominator_i) ) - break; - - if( numerator.Mul(x) ) - break; - } - - if( steps ) - *steps = i; - } - -public: - - - /*! - Exponent this = exp(x) = e^x - - we're using the fact that our value is stored in form of: - - x = mantissa * 2^exponent - - then - - e^x = e^(mantissa* 2^exponent) or - e^x = (e^mantissa)^(2^exponent) - - 'Exp' returns a carry if we can't count the result ('x' is too big) - */ - uint Exp(const Big & x) - { - uint c = 0; - - if( x.IsNan() ) - return CheckCarry(1); - - if( x.IsZero() ) - { - SetOne(); - return 0; - } - - // m will be the value of the mantissa in range (-1,1) - Big m(x); - m.exponent = -sint(man*TTMATH_BITS_PER_UINT); - - // 'e_' will be the value of '2^exponent' - // e_.mantissa.table[man-1] = TTMATH_UINT_HIGHEST_BIT; and - // e_.exponent.Add(1) mean: - // e_.mantissa.table[0] = 1; - // e_.Standardizing(); - // e_.exponent.Add(man*TTMATH_BITS_PER_UINT) - // (we must add 'man*TTMATH_BITS_PER_UINT' because we've taken it from the mantissa) - Big e_(x); - e_.mantissa.SetZero(); - e_.mantissa.table[man-1] = TTMATH_UINT_HIGHEST_BIT; - c += e_.exponent.Add(1); - e_.Abs(); - - /* - now we've got: - m - the value of the mantissa in range (-1,1) - e_ - 2^exponent - - e_ can be as: - ...2^-2, 2^-1, 2^0, 2^1, 2^2 ... - ...1/4 , 1/2 , 1 , 2 , 4 ... - - above one e_ is integer - - if e_ is greater than 1 we calculate the exponent as: - e^(m * e_) = ExpSurrounding0(m) ^ e_ - and if e_ is smaller or equal one we calculate the exponent in this way: - e^(m * e_) = ExpSurrounding0(m* e_) - because if e_ is smaller or equal 1 then the product of m*e_ is smaller or equal m - */ - - if( e_ <= 1 ) - { - m.Mul(e_); - ExpSurrounding0(m); - } - else - { - ExpSurrounding0(m); - c += PowUInt(e_); - } - - return CheckCarry(c); - } - - - - -private: - -#ifdef TTMATH_CONSTANTSGENERATOR -public: -#endif - - /*! - Natural logarithm this = ln(x) where x in range <1,2) - - we're using the formula: - ln x = 2 * [ (x-1)/(x+1) + (1/3)((x-1)/(x+1))^3 + (1/5)((x-1)/(x+1))^5 + ... ] - */ - void LnSurrounding1(const Big & x, uint * steps = 0) - { - Big old_value, next_part, denominator, one, two, x1(x), x2(x); - - one.SetOne(); - - if( x == one ) - { - // LnSurrounding1(1) is 0 - SetZero(); - return; - } - - two = 2; - - x1.Sub(one); - x2.Add(one); - - x1.Div(x2); - x2 = x1; - x2.Mul(x1); - - denominator.SetOne(); - SetZero(); - - old_value = *this; - uint i; - - - #ifdef TTMATH_CONSTANTSGENERATOR - for(i=1 ; true ; ++i) - #else - // we begin from 1 in order to not test at the beginning - for(i=1 ; i<=TTMATH_ARITHMETIC_MAX_LOOP ; ++i) - #endif - { - bool testing = ((i & 3) == 0); // it means '(i % 4) == 0' - - next_part = x1; - - if( next_part.Div(denominator) ) - // if there is a carry here we only break the loop - // however the result we return as good - // it means there are too many parts of the formula - break; - - // there shouldn't be a carry here - Add(next_part); - - if( testing ) - { - if( old_value == *this ) - // we've added next (step_test) parts of the formula but the result - // is still the same then we break the loop - break; - else - old_value = *this; - } - - if( x1.Mul(x2) ) - // if there is a carry here the result we return as good - break; - - if( denominator.Add(two) ) - break; - } - - // this = this * 2 - // ( there can't be a carry here because we calculate the logarithm between <1,2) ) - exponent.AddOne(); - - if( steps ) - *steps = i; - } - - - - -public: - - - /*! - Natural logarithm this = ln(x) - (a logarithm with the base equal 'e') - - we're using the fact that our value is stored in form of: - - x = mantissa * 2^exponent - - then - - ln(x) = ln (mantissa * 2^exponent) = ln (mantissa) + (exponent * ln (2)) - - the mantissa we'll show as a value from range <1,2) because the logarithm - is decreasing too fast when 'x' is going to 0 - - return values: - - 0 - ok - - 1 - overflow (carry) - - 2 - incorrect argument (x<=0) - */ - uint Ln(const Big & x) - { - if( x.IsNan() ) - return CheckCarry(1); - - if( x.IsSign() || x.IsZero() ) - { - SetNan(); - return 2; - } - - Big exponent_temp; - exponent_temp.FromInt( x.exponent ); - - // m will be the value of the mantissa in range <1,2) - Big m(x); - m.exponent = -sint(man*TTMATH_BITS_PER_UINT - 1); - - // we must add 'man*TTMATH_BITS_PER_UINT-1' because we've taken it from the mantissa - uint c = exponent_temp.Add(man*TTMATH_BITS_PER_UINT-1); - - LnSurrounding1(m); - - Big ln2; - ln2.SetLn2(); - c += exponent_temp.Mul(ln2); - c += Add(exponent_temp); - - return CheckCarry(c); - } - - - /*! - Logarithm from 'x' with a 'base' - - we're using the formula: - - Log(x) with 'base' = ln(x) / ln(base) - - return values: - - 0 - ok - - 1 - overflow - - 2 - incorrect argument (x<=0) - - 3 - incorrect base (a<=0 or a=1) - */ - uint Log(const Big & x, const Big & base) - { - if( x.IsNan() || base.IsNan() ) - return CheckCarry(1); - - if( x.IsSign() || x.IsZero() ) - { - SetNan(); - return 2; - } - - Big denominator;; - denominator.SetOne(); - - if( base.IsSign() || base.IsZero() || base==denominator ) - { - SetNan(); - return 3; - } - - if( x == denominator ) // (this is: if x == 1) - { - // log(1) is 0 - SetZero(); - return 0; - } - - // another error values we've tested at the beginning - // there can only be a carry - uint c = Ln(x); - - c += denominator.Ln(base); - c += Div(denominator); - - return CheckCarry(c); - } - - - - - /*! - * - * converting methods - * - */ - - - /*! - converting from another type of a Big object - */ - template - uint FromBig(const Big & another) - { - info = another.info; - - if( IsNan() ) - return 1; - - if( exponent.FromInt(another.exponent) ) - { - SetNan(); - return 1; - } - - uint man_len_min = (man < another_man)? man : another_man; - uint i; - uint c = 0; - - for( i = 0 ; i another_man )' and 'if( man < another_man )' and there'll be no such situation here - #ifdef _MSC_VER - #pragma warning( disable: 4307 ) - #endif - - if( man > another_man ) - { - uint man_diff = (man - another_man) * TTMATH_BITS_PER_UINT; - c += exponent.SubInt(man_diff, 0); - } - else - if( man < another_man ) - { - uint man_diff = (another_man - man) * TTMATH_BITS_PER_UINT; - c += exponent.AddInt(man_diff, 0); - } - - #ifdef _MSC_VER - #pragma warning( default: 4307 ) - #endif - - // mantissa doesn't have to be standardized (either the highest bit is set or all bits are equal zero) - CorrectZero(); - - return CheckCarry(c); - } - - -private: - - /*! - an auxiliary method for converting 'this' into 'result' - if the value is too big this method returns a carry (1) - */ - uint ToUIntOrInt(uint & result) const - { - result = 0; - - if( IsZero() ) - return 0; - - sint maxbit = -sint(man*TTMATH_BITS_PER_UINT); - - if( exponent > maxbit + sint(TTMATH_BITS_PER_UINT) ) - // if exponent > (maxbit + sint(TTMATH_BITS_PER_UINT)) the value can't be passed - // into the 'sint' type (it's too big) - return 1; - - if( exponent <= maxbit ) - // our value is from the range of (-1,1) and we return zero - return 0; - - // exponent is from a range of (maxbit, maxbit + sint(TTMATH_BITS_PER_UINT) > - // and [maxbit + sint(TTMATH_BITS_PER_UINT] <= 0 - sint how_many_bits = exponent.ToInt(); - - // how_many_bits is negative, we'll make it positive - how_many_bits = -how_many_bits; - - result = (mantissa.table[man-1] >> (how_many_bits % TTMATH_BITS_PER_UINT)); - - return 0; - } - - -public: - - /*! - this method converts 'this' into uint - */ - uint ToUInt() const - { - uint result; - - ToUInt(result); - - return result; - } - - - /*! - this method converts 'this' into 'result' - - if the value is too big this method returns a carry (1) - */ - uint ToUInt(uint & result) const - { - if( ToUIntOrInt(result) ) - return 1; - - if( IsSign() ) - return 1; - - return 0; - } - - - /*! - this method converts 'this' into sint - */ - sint ToInt() const - { - sint result; - - ToInt(result); - - return result; - } - - - /*! - this method converts 'this' into 'result' - - if the value is too big this method returns a carry (1) - */ - uint ToInt(uint & result) const - { - return ToUInt(result); - } - - - /*! - this method converts 'this' into 'result' - - if the value is too big this method returns a carry (1) - */ - uint ToInt(sint & result) const - { - uint result_uint; - - uint c = ToUIntOrInt(result_uint); - result = sint(result_uint); - - if( c ) - return 1; - - uint mask = 0; - - if( IsSign() ) - { - mask = TTMATH_UINT_MAX_VALUE; - result = -result; - } - - return ((result & TTMATH_UINT_HIGHEST_BIT) == (mask & TTMATH_UINT_HIGHEST_BIT)) ? 0 : 1; - } - - -private: - - /*! - an auxiliary method for converting 'this' into 'result' - - if the value is too big this method returns a carry (1) - */ - template - uint ToUIntOrInt(UInt & result) const - { - result.SetZero(); - - if( IsZero() ) - return 0; - - sint maxbit = -sint(man*TTMATH_BITS_PER_UINT); - - if( exponent > maxbit + sint(int_size*TTMATH_BITS_PER_UINT) ) - // if exponent > (maxbit + sint(int_size*TTMATH_BITS_PER_UINT)) the value can't be passed - // into the 'UInt' type (it's too big) - return 1; - - if( exponent <= maxbit ) - // our value is from range (-1,1) and we return zero - return 0; - - sint how_many_bits = exponent.ToInt(); - - if( how_many_bits < 0 ) - { - how_many_bits = -how_many_bits; - uint index = how_many_bits / TTMATH_BITS_PER_UINT; - - UInt mantissa_temp(mantissa); - mantissa_temp.Rcr( how_many_bits % TTMATH_BITS_PER_UINT, 0 ); - - for(uint i=index, a=0 ; i maxbit + sint(int_size*TTMATH_BITS_PER_UINT) )" - // but gcc doesn't understand our types - exponent is Int<> - - for(uint i=0 ; i - uint ToUInt(UInt & result) const - { - uint c = ToUIntOrInt(result); - - if( c ) - return 1; - - if( IsSign() ) - return 1; - - return 0; - } - - - /*! - this method converts 'this' into 'result' - - if the value is too big this method returns a carry (1) - */ - template - uint ToInt(UInt & result) const - { - return ToUInt(result); - } - - - /*! - this method converts 'this' into 'result' - - if the value is too big this method returns a carry (1) - */ - template - uint ToInt(Int & result) const - { - uint c = ToUIntOrInt(result); - - if( c ) - return 1; - - uint mask = 0; - - if( IsSign() ) - { - result.ChangeSign(); - mask = TTMATH_UINT_MAX_VALUE; - } - - return ((result.table[int_size-1] & TTMATH_UINT_HIGHEST_BIT) == (mask & TTMATH_UINT_HIGHEST_BIT))? 0 : 1; - } - - - /*! - a method for converting 'uint' to this class - */ - uint FromUInt(uint value) - { - if( value == 0 ) - { - SetZero(); - return 0; - } - - info = 0; - - for(uint i=0 ; i> 20; - uint m1 = ((temp.u[1] & 0xFFFFFu) << 11) | (temp.u[0] >> 21); - uint m2 = temp.u[0] << 11; - - if( e == 2047 ) - { - // If E=2047 and F is nonzero, then V=NaN ("Not a number") - // If E=2047 and F is zero and S is 1, then V=-Infinity - // If E=2047 and F is zero and S is 0, then V=Infinity - - // we do not support -Infinity and +Infinity - // we assume that there is always NaN - - SetNan(); - } - else - if( e > 0 ) - { - // If 0 m; - m.table[1] = m1; - m.table[0] = m2; - uint moved = m.CompensationToLeft(); - - FromDouble_SetExpAndMan((temp.u[1] & 0x80000000u) != 0, - e - 1022 - man*TTMATH_BITS_PER_UINT + 1 - moved, 0, - m.table[1], m.table[0]); - } - else - { - // If E=0 and F is zero and S is 1, then V=-0 - // If E=0 and F is zero and S is 0, then V=0 - - // we do not support -0 or 0, only is one 0 - SetZero(); - } - } - - return 0; // never be a carry - } - - -private: - - void FromDouble_SetExpAndMan(bool is_sign, int e, uint mhighest, uint m1, uint m2) - { - exponent = e; - - if( man > 1 ) - { - mantissa.table[man-1] = m1 | mhighest; - mantissa.table[sint(man-2)] = m2; - // although man>1 we're using casting into sint - // to get rid from a warning which generates Microsoft Visual: - // warning C4307: '*' : integral constant overflow - - for(uint i=0 ; i> 52; - uint m = (temp.u & 0xFFFFFFFFFFFFFul) << 11; - - if( e == 2047 ) - { - // If E=2047 and F is nonzero, then V=NaN ("Not a number") - // If E=2047 and F is zero and S is 1, then V=-Infinity - // If E=2047 and F is zero and S is 0, then V=Infinity - - // we do not support -Infinity and +Infinity - // we assume that there is always NaN - - SetNan(); - } - else - if( e > 0 ) - { - // If 0> 23) & 0xff) == 0xff ) - { - if( (temp.u & 0x7FFFFF) == 0 ) - return true; // +/- infinity - } - - return false; - } - - -public: - - /*! - this method converts from this class into the 'float' - - if the value is too big: - 'result' will be +/-infinity (depending on the sign) - - if the value is too small: - 'result' will be 0 - */ - float ToFloat() const - { - float result; - - ToFloat(result); - - return result; - } - - - /*! - this method converts from this class into the 'float' - - if the value is too big: - - 'result' will be +/-infinity (depending on the sign) - - and the method returns 1 - - if the value is too small: - - 'result' will be 0 - - and the method returns 1 - */ - uint ToFloat(float & result) const - { - double result_double; - - uint c = ToDouble(result_double); - result = float(result_double); - - if( result == -0.0f ) - result = 0.0f; - - if( c ) - return 1; - - // although the result_double can have a correct value - // but after converting to float there can be infinity - - if( IsInf(result) ) - return 1; - - if( result == 0.0f && result_double != 0.0 ) - // result_double was too small for float - return 1; - - return 0; - } - - - /*! - this method converts from this class into the 'double' - - if the value is too big: - - 'result' will be +/-infinity (depending on the sign) - - and the method returns 1 - - if the value is too small: - - 'result' will be 0 - - and the method returns 1 - */ - uint ToDouble(double & result) const - { - if( IsZero() ) - { - result = 0.0; - return 0; - } - - if( IsNan() ) - { - result = ToDouble_SetDouble( false, 2047, 0, false, true); - - return 0; - } - - sint e_correction = sint(man*TTMATH_BITS_PER_UINT) - 1; - - if( exponent >= 1024 - e_correction ) - { - // +/- infinity - result = ToDouble_SetDouble( IsSign(), 2047, 0, true); - - return 1; - } - else - if( exponent <= -1023 - 52 - e_correction ) - { - // too small value - we assume that there'll be a zero - result = 0; - - // and return a carry - return 1; - } - - sint e = exponent.ToInt() + e_correction; - - if( e <= -1023 ) - { - // -1023-52 < e <= -1023 (unnormalized value) - result = ToDouble_SetDouble( IsSign(), 0, -(e + 1023)); - } - else - { - // -1023 < e < 1024 - result = ToDouble_SetDouble( IsSign(), e + 1023, -1); - } - - return 0; - } - -private: - -#ifdef TTMATH_PLATFORM32 - - // 32bit platforms - double ToDouble_SetDouble(bool is_sign, uint e, sint move, bool infinity = false, bool nan = false) const - { - union - { - double d; - uint u[2]; // two 32bit words - } temp; - - temp.u[0] = temp.u[1] = 0; - - if( is_sign ) - temp.u[1] |= 0x80000000u; - - temp.u[1] |= (e << 20) & 0x7FF00000u; - - if( nan ) - { - temp.u[0] |= 1; - return temp.d; - } - - if( infinity ) - return temp.d; - - UInt<2> m; - m.table[1] = mantissa.table[man-1]; - m.table[0] = ( man > 1 ) ? mantissa.table[sint(man-2)] : 0; - // although man>1 we're using casting into sint - // to get rid from a warning which generates Microsoft Visual: - // warning C4307: '*' : integral constant overflow - - m.Rcr( 12 + move ); - m.table[1] &= 0xFFFFFu; // cutting the 20 bit (when 'move' was -1) - - temp.u[1] |= m.table[1]; - temp.u[0] |= m.table[0]; - - return temp.d; - } - -#else - - // 64bit platforms - double ToDouble_SetDouble(bool is_sign, uint e, sint move, bool infinity = false, bool nan = false) const - { - union - { - double d; - uint u; // 64bit word - } temp; - - temp.u = 0; - - if( is_sign ) - temp.u |= 0x8000000000000000ul; - - temp.u |= (e << 52) & 0x7FF0000000000000ul; - - if( nan ) - { - temp.u |= 1; - return temp.d; - } - - if( infinity ) - return temp.d; - - uint m = mantissa.table[man-1]; - - m >>= ( 12 + move ); - m &= 0xFFFFFFFFFFFFFul; // cutting the 20 bit (when 'move' was -1) - temp.u |= m; - - return temp.d; - } - -#endif - - -public: - - - /*! - an operator= for converting 'sint' to this class - */ - Big & operator=(sint value) - { - FromInt(value); - - return *this; - } - - - /*! - an operator= for converting 'uint' to this class - */ - Big & operator=(uint value) - { - FromUInt(value); - - return *this; - } - - - /*! - an operator= for converting 'float' to this class - */ - Big & operator=(float value) - { - FromFloat(value); - - return *this; - } - - - /*! - an operator= for converting 'double' to this class - */ - Big & operator=(double value) - { - FromDouble(value); - - return *this; - } - - - /*! - a constructor for converting 'sint' to this class - */ - Big(sint value) - { - FromInt(value); - } - - /*! - a constructor for converting 'uint' to this class - */ - Big(uint value) - { - FromUInt(value); - } - - - /*! - a constructor for converting 'double' to this class - */ - Big(double value) - { - FromDouble(value); - } - - - /*! - a constructor for converting 'float' to this class - */ - Big(float value) - { - FromFloat(value); - } - - -#ifdef TTMATH_PLATFORM32 - - /*! - this method converts 'this' into 'result' (64 bit unsigned integer) - if the value is too big this method returns a carry (1) - */ - uint ToUInt(ulint & result) const - { - UInt<2> temp; // 64 bits container - - uint c = ToUInt(temp); - temp.ToUInt(result); - - return c; - } - - - /*! - this method converts 'this' into 'result' (64 bit unsigned integer) - if the value is too big this method returns a carry (1) - */ - uint ToInt(ulint & result) const - { - return ToUInt(result); - } - - - /*! - this method converts 'this' into 'result' (64 bit unsigned integer) - if the value is too big this method returns a carry (1) - */ - uint ToInt(slint & result) const - { - Int<2> temp; // 64 bits container - - uint c = ToInt(temp); - temp.ToInt(result); - - return c; - } - - - /*! - a method for converting 'ulint' (64bit unsigned integer) to this class - */ - uint FromUInt(ulint value) - { - if( value == 0 ) - { - SetZero(); - return 0; - } - - info = 0; - - if( man == 1 ) - { - sint bit = mantissa.FindLeadingBitInWord(uint(value >> TTMATH_BITS_PER_UINT)); - - if( bit != -1 ) - { - // the highest word from value is different from zero - bit += 1; - value >>= bit; - exponent = bit; - } - else - { - exponent.SetZero(); - } - - mantissa.table[0] = uint(value); - } - else - { - #ifdef _MSC_VER - //warning C4307: '*' : integral constant overflow - #pragma warning( disable: 4307 ) - #endif - - // man >= 2 - mantissa.table[man-1] = uint(value >> TTMATH_BITS_PER_UINT); - mantissa.table[man-2] = uint(value); - - #ifdef _MSC_VER - //warning C4307: '*' : integral constant overflow - #pragma warning( default: 4307 ) - #endif - - exponent = -sint(man-2) * sint(TTMATH_BITS_PER_UINT); - - for(uint i=0 ; i & operator=(ulint value) - { - FromUInt(value); - - return *this; - } - - - /*! - a constructor for converting 'slint' (64bit signed integer) to this class - */ - Big(slint value) - { - FromInt(value); - } - - - /*! - an operator for converting 'slint' (64bit signed integer) to this class - */ - Big & operator=(slint value) - { - FromInt(value); - - return *this; - } - -#endif - - - -#ifdef TTMATH_PLATFORM64 - - - /*! - this method converts 'this' into 'result' (32 bit unsigned integer) - ***this method is created only on a 64bit platform*** - if the value is too big this method returns a carry (1) - */ - uint ToUInt(unsigned int & result) const - { - uint result_uint; - - uint c = ToUInt(result_uint); - result = (unsigned int)result_uint; - - if( c || result_uint != uint(result) ) - return 1; - - return 0; - } - - - /*! - this method converts 'this' into 'result' (32 bit unsigned integer) - ***this method is created only on a 64bit platform*** - if the value is too big this method returns a carry (1) - */ - uint ToInt(unsigned int & result) const - { - return ToUInt(result); - } - - - /*! - this method converts 'this' into 'result' (32 bit signed integer) - ***this method is created only on a 64bit platform*** - if the value is too big this method returns a carry (1) - */ - uint ToInt(signed int & result) const - { - sint result_sint; - - uint c = ToInt(result_sint); - result = (signed int)result_sint; - - if( c || result_sint != sint(result) ) - return 1; - - return 0; - } - - - /* - this method converts 32 bit unsigned int to this class - ***this method is created only on a 64bit platform*** - */ - uint FromUInt(unsigned int value) - { - return FromUInt(uint(value)); - } - - - /* - this method converts 32 bit unsigned int to this class - ***this method is created only on a 64bit platform*** - */ - uint FromInt(unsigned int value) - { - return FromUInt(uint(value)); - } - - - /* - this method converts 32 bit signed int to this class - ***this method is created only on a 64bit platform*** - */ - uint FromInt(signed int value) - { - return FromInt(sint(value)); - } - - - /*! - an operator= for converting 32 bit unsigned int to this class - ***this operator is created only on a 64bit platform*** - */ - Big & operator=(unsigned int value) - { - FromUInt(value); - - return *this; - } - - - /*! - a constructor for converting 32 bit unsigned int to this class - ***this constructor is created only on a 64bit platform*** - */ - Big(unsigned int value) - { - FromUInt(value); - } - - - /*! - an operator for converting 32 bit signed int to this class - ***this operator is created only on a 64bit platform*** - */ - Big & operator=(signed int value) - { - FromInt(value); - - return *this; - } - - - /*! - a constructor for converting 32 bit signed int to this class - ***this constructor is created only on a 64bit platform*** - */ - Big(signed int value) - { - FromInt(value); - } - -#endif - - -private: - - /*! - an auxiliary method for converting from UInt and Int - - we assume that there'll never be a carry here - (we have an exponent and the value in Big can be bigger than - that one from the UInt) - */ - template - uint FromUIntOrInt(const UInt & value, sint compensation) - { - uint minimum_size = (int_size < man)? int_size : man; - exponent = (sint(int_size)-sint(man)) * sint(TTMATH_BITS_PER_UINT) - compensation; - - // copying the highest words - uint i; - for(i=1 ; i<=minimum_size ; ++i) - mantissa.table[man-i] = value.table[int_size-i]; - - // setting the rest of mantissa.table into zero (if some has left) - for( ; i<=man ; ++i) - mantissa.table[man-i] = 0; - - // the highest bit is either one or zero (when the whole mantissa is zero) - // we can only call CorrectZero() - CorrectZero(); - - return 0; - } - - -public: - - /*! - a method for converting from 'UInt' to this class - */ - template - uint FromUInt(UInt value) - { - info = 0; - sint compensation = (sint)value.CompensationToLeft(); - - return FromUIntOrInt(value, compensation); - } - - - /*! - a method for converting from 'UInt' to this class - */ - template - uint FromInt(const UInt & value) - { - return FromUInt(value); - } - - - /*! - a method for converting from 'Int' to this class - */ - template - uint FromInt(Int value) - { - info = 0; - bool is_sign = false; - - if( value.IsSign() ) - { - value.ChangeSign(); - is_sign = true; - } - - sint compensation = (sint)value.CompensationToLeft(); - FromUIntOrInt(value, compensation); - - if( is_sign ) - SetSign(); - - return 0; - } - - - /*! - an operator= for converting from 'Int' to this class - */ - template - Big & operator=(const Int & value) - { - FromInt(value); - - return *this; - } - - - /*! - a constructor for converting from 'Int' to this class - */ - template - Big(const Int & value) - { - FromInt(value); - } - - - /*! - an operator= for converting from 'UInt' to this class - */ - template - Big & operator=(const UInt & value) - { - FromUInt(value); - - return *this; - } - - - /*! - a constructor for converting from 'UInt' to this class - */ - template - Big(const UInt & value) - { - FromUInt(value); - } - - - /*! - an operator= for converting from 'Big' to this class - */ - template - Big & operator=(const Big & value) - { - FromBig(value); - - return *this; - } - - - /*! - a constructor for converting from 'Big' to this class - */ - template - Big(const Big & value) - { - FromBig(value); - } - - - /*! - a default constructor - - by default we don't set any of the members to zero - only NaN flag is set - - if you want the mantissa and exponent to be set to zero - define TTMATH_BIG_DEFAULT_CLEAR macro - (useful for debug purposes) - */ - Big() - { - #ifdef TTMATH_BIG_DEFAULT_CLEAR - - SetZeroNan(); - - #else - - info = TTMATH_BIG_NAN; - // we're directly setting 'info' (instead of calling SetNan()) - // in order to get rid of a warning saying that 'info' is uninitialized - - #endif - } - - - /*! - a destructor - */ - ~Big() - { - } - - - /*! - the default assignment operator - */ - Big & operator=(const Big & value) - { - info = value.info; - exponent = value.exponent; - mantissa = value.mantissa; - - return *this; - } - - - /*! - a constructor for copying from another object of this class - */ - - Big(const Big & value) - { - operator=(value); - } - - - - /*! - a method for converting into a string - struct Conv is defined in ttmathtypes.h, look there for more information about parameters - - return value: - - 0 - ok and 'result' will be an object of type std::string (or std::wstring) which holds the value - - 1 - if there is a carry (it shoudn't be in a normal situation - if it is that means there - is somewhere an error in the library) - */ - uint ToString( std::string & result, - uint base = 10, - bool scient = false, - sint scient_from = 15, - sint round = -1, - bool trim_zeroes = true, - char comma = '.' ) const - { - Conv conv; - - conv.base = base; - conv.scient = scient; - conv.scient_from = scient_from; - conv.round = round; - conv.trim_zeroes = trim_zeroes; - conv.comma = static_cast(comma); - - return ToStringBase(result, conv); - } - - - /*! - a method for converting into a string - struct Conv is defined in ttmathtypes.h, look there for more information about parameters - */ - uint ToString(std::string & result, const Conv & conv) const - { - return ToStringBase(result, conv); - } - - - /*! - a method for converting into a string - struct Conv is defined in ttmathtypes.h, look there for more information about parameters - */ - std::string ToString(const Conv & conv) const - { - std::string result; - ToStringBase(result, conv); - - return result; - } - - - /*! - a method for converting into a string - struct Conv is defined in ttmathtypes.h, look there for more information about parameters - */ - std::string ToString(uint base = 10) const - { - Conv conv; - conv.base = base; - - return ToString(conv); - } - - - -#ifndef TTMATH_DONT_USE_WCHAR - - - /*! - a method for converting into a string - struct Conv is defined in ttmathtypes.h, look there for more information about parameters - */ - uint ToString( std::wstring & result, - uint base = 10, - bool scient = false, - sint scient_from = 15, - sint round = -1, - bool trim_zeroes = true, - wchar_t comma = '.' ) const - { - Conv conv; - - conv.base = base; - conv.scient = scient; - conv.scient_from = scient_from; - conv.round = round; - conv.trim_zeroes = trim_zeroes; - conv.comma = static_cast(comma); - - return ToStringBase(result, conv); - } - - - /*! - a method for converting into a string - struct Conv is defined in ttmathtypes.h, look there for more information about parameters - */ - uint ToString(std::wstring & result, const Conv & conv) const - { - return ToStringBase(result, conv); - } - - - /*! - a method for converting into a string - struct Conv is defined in ttmathtypes.h, look there for more information about parameters - */ - std::wstring ToWString(const Conv & conv) const - { - std::wstring result; - ToStringBase(result, conv); - - return result; - } - - - /*! - a method for converting into a string - struct Conv is defined in ttmathtypes.h, look there for more information about parameters - */ - std::wstring ToWString(uint base = 10) const - { - Conv conv; - conv.base = base; - - return ToWString(conv); - } - -#endif - - - -private: - - - /*! - an auxiliary method for converting into the string - */ - template - uint ToStringBase(string_type & result, const Conv & conv) const - { - static char error_overflow_msg[] = "overflow"; - static char error_nan_msg[] = "NaN"; - result.erase(); - - if( IsNan() ) - { - Misc::AssignString(result, error_nan_msg); - return 0; - } - - if( conv.base<2 || conv.base>16 ) - { - Misc::AssignString(result, error_overflow_msg); - return 1; - } - - if( IsZero() ) - { - result = '0'; - - return 0; - } - - /* - since 'base' is greater or equal 2 that 'new_exp' of type 'Int' should - hold the new value of exponent but we're using 'Int' because - if the value for example would be 'max()' then we couldn't show it - - max() -> 11111111 * 2 ^ 11111111111 (bin)(the mantissa and exponent have all bits set) - if we were using 'Int' we couldn't show it in this format: - 1,1111111 * 2 ^ 11111111111 (bin) - because we have to add something to the mantissa and because - mantissa is full we can't do it and it'll be a carry - (look at ToString_SetCommaAndExponent(...)) - - when the base would be greater than two (for example 10) - we could use 'Int' here - */ - Int new_exp; - - if( ToString_CreateNewMantissaAndExponent(result, conv, new_exp) ) - { - Misc::AssignString(result, error_overflow_msg); - return 1; - } - - - if( ToString_SetCommaAndExponent(result, conv, new_exp) ) - { - Misc::AssignString(result, error_overflow_msg); - return 1; - } - - if( IsSign() ) - result.insert(result.begin(), '-'); - - - // converted successfully - return 0; - } - - - - /*! - in the method 'ToString_CreateNewMantissaAndExponent()' we're using - type 'Big' and we should have the ability to use some - necessary methods from that class (methods which are private here) - */ - friend class Big; - - - /*! - an auxiliary method for converting into the string - - input: - base - the base in range <2,16> - - output: - return values: - 0 - ok - 1 - if there was a carry - new_man - the new mantissa for 'base' - new_exp - the new exponent for 'base' - - mathematic part: - - the value is stored as: - value = mantissa * 2^exponent - we want to show 'value' as: - value = new_man * base^new_exp - - then 'new_man' we'll print using the standard method from UInt<> type for printing - and 'new_exp' is the offset of the comma operator in a system of a base 'base' - - value = mantissa * 2^exponent - value = mantissa * 2^exponent * (base^new_exp / base^new_exp) - value = mantissa * (2^exponent / base^new_exp) * base^new_exp - - look at the part (2^exponent / base^new_exp), there'll be good if we take - a 'new_exp' equal that value when the (2^exponent / base^new_exp) will be equal one - - on account of the 'base' is not as power of 2 (can be from 2 to 16), - this formula will not be true for integer 'new_exp' then in our case we take - 'base^new_exp' _greater_ than '2^exponent' - - if 'base^new_exp' were smaller than '2^exponent' the new mantissa could be - greater than the max value of the container UInt - - value = mantissa * (2^exponent / base^new_exp) * base^new_exp - let M = mantissa * (2^exponent / base^new_exp) then - value = M * base^new_exp - - in our calculation we treat M as floating value showing it as: - M = mm * 2^ee where ee will be <= 0 - - next we'll move all bits of mm into the right when ee is equal zero - abs(ee) must not be too big that only few bits from mm we can leave - - then we'll have: - M = mmm * 2^0 - 'mmm' is the new_man which we're looking for - - - new_exp we calculate in this way: - 2^exponent <= base^new_exp - new_exp >= log base (2^exponent) <- logarithm with the base 'base' from (2^exponent) - - but we need new_exp as integer then we test: - if new_exp is greater than zero and with fraction we add one to new_exp - new_exp = new_exp + 1 (if new_exp>0 and with fraction) - and at the end we take the integer part: - new_exp = int(new_exp) - */ - template - uint ToString_CreateNewMantissaAndExponent( string_type & new_man, const Conv & conv, - Int & new_exp) const - { - uint c = 0; - - if( conv.base<2 || conv.base>16 ) - return 1; - - // special method for base equal 2 - if( conv.base == 2 ) - return ToString_CreateNewMantissaAndExponent_Base2(new_man, new_exp); - - // special method for base equal 4 - if( conv.base == 4 ) - return ToString_CreateNewMantissaAndExponent_BasePow2(new_man, new_exp, 2); - - // special method for base equal 8 - if( conv.base == 8 ) - return ToString_CreateNewMantissaAndExponent_BasePow2(new_man, new_exp, 3); - - // special method for base equal 16 - if( conv.base == 16 ) - return ToString_CreateNewMantissaAndExponent_BasePow2(new_man, new_exp, 4); - - - // this = mantissa * 2^exponent - - // temp = +1 * 2^exponent - // we're using a bigger type than 'big' (look below) - Big temp; - temp.info = 0; - temp.exponent = exponent; - temp.mantissa.SetOne(); - c += temp.Standardizing(); - - // new_exp_ = log base (2^exponent) - // if new_exp_ is positive and with fraction then we add one - Big new_exp_; - c += new_exp_.ToString_Log(temp, conv.base); // this logarithm isn't very complicated - - // rounding up to the nearest integer - if( !new_exp_.IsInteger() ) - { - if( !new_exp_.IsSign() ) - c += new_exp_.AddOne(); // new_exp_ > 0 and with fraction - - new_exp_.SkipFraction(); - } - - if( ToString_CreateNewMantissaTryExponent(new_man, conv, new_exp_, new_exp) ) - { - // in very rare cases there can be an overflow from ToString_CreateNewMantissaTryExponent - // it means that new_exp_ was too small (the problem comes from floating point numbers precision) - // so we increse new_exp_ and try again - new_exp_.AddOne(); - c += ToString_CreateNewMantissaTryExponent(new_man, conv, new_exp_, new_exp); - } - - return (c==0)? 0 : 1; - } - - - - /*! - an auxiliary method for converting into the string - - trying to calculate new_man for given exponent (new_exp_) - if there is a carry it can mean that new_exp_ is too small - */ - template - uint ToString_CreateNewMantissaTryExponent( string_type & new_man, const Conv & conv, - const Big & new_exp_, Int & new_exp) const - { - uint c = 0; - - // because 'base^new_exp' is >= '2^exponent' then - // because base is >= 2 then we've got: - // 'new_exp_' must be smaller or equal 'new_exp' - // and we can pass it into the Int type - // (in fact we're using a greater type then it'll be ok) - c += new_exp_.ToInt(new_exp); - - // base_ = base - Big base_(conv.base); - - // base_ = base_ ^ new_exp_ - c += base_.Pow( new_exp_ ); // use new_exp_ so Pow(Big<> &) version will be used - // if we hadn't used a bigger type than 'Big' then the result - // of this formula 'Pow(...)' would have been with an overflow - - // temp = mantissa * 2^exponent / base_^new_exp_ - Big temp; - temp.info = 0; - temp.mantissa = mantissa; - temp.exponent = exponent; - c += temp.Div(base_); - - // moving all bits of the mantissa into the right - // (how many times to move depend on the exponent) - c += temp.ToString_MoveMantissaIntoRight(); - - // because we took 'new_exp' as small as it was - // possible ([log base (2^exponent)] + 1) that after the division - // (temp.Div( base_ )) the value of exponent should be equal zero or - // minimum smaller than zero then we've got the mantissa which has - // maximum valid bits - temp.mantissa.ToString(new_man, conv.base); - - if( IsInteger() ) - { - // making sure the new mantissa will be without fraction (integer) - ToString_CheckMantissaInteger(new_man, new_exp); - } - else - if( conv.base_round ) - { - c += ToString_BaseRound(new_man, conv, new_exp); - } - - return (c==0)? 0 : 1; - } - - - /*! - this method calculates the logarithm - it is used by ToString_CreateNewMantissaAndExponent() method - - it's not too complicated - because x=+1*2^exponent (mantissa is one) then during the calculation - the Ln(x) will not be making the long formula from LnSurrounding1() - and only we have to calculate 'Ln(base)' but it'll be calculated - only once, the next time we will get it from the 'history' - - x is greater than 0 - base is in <2,16> range - */ - uint ToString_Log(const Big & x, uint base) - { - TTMATH_REFERENCE_ASSERT( x ) - TTMATH_ASSERT( base>=2 && base<=16 ) - - Big temp; - temp.SetOne(); - - if( x == temp ) - { - // log(1) is 0 - SetZero(); - - return 0; - } - - // there can be only a carry - // because the 'x' is in '1+2*exponent' form then - // the long formula from LnSurrounding1() will not be calculated - // (LnSurrounding1() will return one immediately) - uint c = Ln(x); - - if( base==10 && man<=TTMATH_BUILTIN_VARIABLES_SIZE ) - { - // for the base equal 10 we're using SetLn10() instead of calculating it - // (only if we have the constant sufficient big) - temp.SetLn10(); - } - else - { - c += ToString_LogBase(base, temp); - } - - c += Div( temp ); - - return (c==0)? 0 : 1; - } - - -#ifndef TTMATH_MULTITHREADS - - /*! - this method calculates the logarithm of 'base' - it's used in single thread environment - */ - uint ToString_LogBase(uint base, Big & result) - { - TTMATH_ASSERT( base>=2 && base<=16 ) - - // this guardians are initialized before the program runs (static POD types) - static int guardians[15] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; - static Big log_history[15]; - uint index = base - 2; - uint c = 0; - - if( guardians[index] == 0 ) - { - Big base_(base); - c += log_history[index].Ln(base_); - guardians[index] = 1; - } - - result = log_history[index]; - - return (c==0)? 0 : 1; - } - -#else - - /*! - this method calculates the logarithm of 'base' - it's used in multi-thread environment - */ - uint ToString_LogBase(uint base, Big & result) - { - TTMATH_ASSERT( base>=2 && base<=16 ) - - // this guardians are initialized before the program runs (static POD types) - volatile static sig_atomic_t guardians[15] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; - static Big * plog_history; - uint index = base - 2; - uint c = 0; - - // double-checked locking - if( guardians[index] == 0 ) - { - ThreadLock thread_lock; - - // locking - if( thread_lock.Lock() ) - { - static Big log_history[15]; - - if( guardians[index] == 0 ) - { - plog_history = log_history; - - Big base_(base); - c += log_history[index].Ln(base_); - guardians[index] = 1; - } - } - else - { - // there was a problem with locking, we store the result directly in 'result' object - Big base_(base); - c += result.Ln(base_); - - return (c==0)? 0 : 1; - } - - // automatically unlocking - } - - result = plog_history[index]; - - return (c==0)? 0 : 1; - } - -#endif - - /*! - an auxiliary method for converting into the string (private) - - this method moving all bits from mantissa into the right side - the exponent tell us how many times moving (the exponent is <=0) - */ - uint ToString_MoveMantissaIntoRight() - { - if( exponent.IsZero() ) - return 0; - - // exponent can't be greater than zero - // because we would cat the highest bits of the mantissa - if( !exponent.IsSign() ) - return 1; - - - if( exponent <= -sint(man*TTMATH_BITS_PER_UINT) ) - { - // if 'exponent' is <= than '-sint(man*TTMATH_BITS_PER_UINT)' - // it means that we must cut the whole mantissa - // (there'll not be any of the valid bits) - return 1; - } - - // e will be from (-man*TTMATH_BITS_PER_UINT, 0> - sint e = -( exponent.ToInt() ); - mantissa.Rcr(e,0); - - return 0; - } - - - /*! - a special method similar to the 'ToString_CreateNewMantissaAndExponent' - when the 'base' is equal 2 - - we use it because if base is equal 2 we don't have to make those - complicated calculations and the output is directly from the source - (there will not be any small distortions) - */ - template - uint ToString_CreateNewMantissaAndExponent_Base2( string_type & new_man, - Int & new_exp ) const - { - for( sint i=man-1 ; i>=0 ; --i ) - { - uint value = mantissa.table[i]; - - for( uint bit=0 ; bit - uint ToString_CreateNewMantissaAndExponent_BasePow2( string_type & new_man, - Int & new_exp, - uint bits) const - { - sint move; // how many times move the mantissa - UInt man_temp(mantissa); // man+1 for moving - new_exp = exponent; - new_exp.DivInt((sint)bits, move); - - if( move != 0 ) - { - // we're moving the man_temp to left-hand side - if( move < 0 ) - { - move = sint(bits) + move; - new_exp.SubOne(); // when move is < than 0 then new_exp is < 0 too - } - - man_temp.Rcl(move); - } - - - if( bits == 3 ) - { - // base 8 - // now 'move' is greater than or equal 0 - uint len = man*TTMATH_BITS_PER_UINT + move; - return ToString_CreateNewMantissaAndExponent_Base8(new_man, man_temp, len, bits); - } - else - { - // base 4 or 16 - return ToString_CreateNewMantissaAndExponent_Base4or16(new_man, man_temp, bits); - } - } - - - /*! - a special method used to calculate the new mantissa - when the 'base' is equal 8 - - bits is always 3 - - we can use this algorithm when the base is 4 or 16 too - but we have a faster method ToString_CreateNewMantissaAndExponent_Base4or16() - */ - template - uint ToString_CreateNewMantissaAndExponent_Base8( string_type & new_man, - UInt & man_temp, - uint len, - uint bits) const - { - uint shift = TTMATH_BITS_PER_UINT - bits; - uint mask = TTMATH_UINT_MAX_VALUE >> shift; - uint i; - - for( i=0 ; i(Misc::DigitToChar(digit))); - - man_temp.Rcr(bits); - } - - TTMATH_ASSERT( man_temp.IsZero() ) - - return 0; - } - - - /*! - a special method used to calculate the new mantissa - when the 'base' is equal 4 or 16 - - when the base is equal 4 or 16 the bits is 2 or 4 - and because TTMATH_BITS_PER_UINT (32 or 64) is divisible by 2 (or 4) - then we can get digits from the end of our mantissa - */ - template - uint ToString_CreateNewMantissaAndExponent_Base4or16( string_type & new_man, - UInt & man_temp, - uint bits) const - { - TTMATH_ASSERT( TTMATH_BITS_PER_UINT % 2 == 0 ) - TTMATH_ASSERT( TTMATH_BITS_PER_UINT % 4 == 0 ) - - uint shift = TTMATH_BITS_PER_UINT - bits; - uint mask = TTMATH_UINT_MAX_VALUE << shift; - uint digit; - - // table[man] - last word - is different from zero if we moved man_temp - digit = man_temp.table[man]; - - if( digit != 0 ) - new_man += static_cast(Misc::DigitToChar(digit)); - - - for( int i=man-1 ; i>=0 ; --i ) - { - uint shift_local = shift; - uint mask_local = mask; - - while( mask_local != 0 ) - { - digit = man_temp.table[i] & mask_local; - - if( shift_local != 0 ) - digit = digit >> shift_local; - - new_man += static_cast(Misc::DigitToChar(digit)); - mask_local = mask_local >> bits; - shift_local = shift_local - bits; - } - } - - return 0; - } - - - /*! - an auxiliary method for converting into the string - */ - template - bool ToString_RoundMantissaWouldBeInteger(string_type & new_man, const Conv & conv, Int & new_exp) const - { - // if new_exp is greater or equal to zero then we have an integer value, - // if new_exp is equal -1 then we have only one digit after the comma - // and after rounding it would be an integer value - if( !new_exp.IsSign() || new_exp == -1 ) - return true; - - if( new_man.size() >= TTMATH_UINT_HIGHEST_BIT || new_man.size() < 2 ) - return true; // oops, the mantissa is too large for calculating (or too small) - we are not doing the base rounding - - uint i = 0; - char_type digit; - - if( new_exp >= -sint(new_man.size()) ) - { - uint new_exp_abs = -new_exp.ToInt(); - i = new_man.size() - new_exp_abs; // start from the first digit after the comma operator - } - - if( Misc::CharToDigit(new_man[new_man.size()-1]) >= conv.base/2 ) - { - if( new_exp < -sint(new_man.size()) ) - { - // there are some zeroes after the comma operator - // (between the comma and the first digit from the mantissa) - // and the result value will never be an integer - return false; - } - - digit = static_cast( Misc::DigitToChar(conv.base-1) ); - } - else - { - digit = '0'; - } - - for( ; i < new_man.size()-1 ; ++i) - if( new_man[i] != digit ) - return false; // it will not be an integer - - return true; // it will be integer after rounding - } - - - /*! - an auxiliary method for converting into the string - (when this is integer) - - after floating point calculating the new mantissa can consist of some fraction - so if our value is integer we should check the new mantissa - (after the decimal point there should be only zeroes) - - often this is a last digit different from zero - ToString_BaseRound would not get rid of it because the method make a test against - an integer value (ToString_RoundMantissaWouldBeInteger) and returns immediately - */ - template - void ToString_CheckMantissaInteger(string_type & new_man, const Int & new_exp) const - { - if( !new_exp.IsSign() ) - return; // return if new_exp >= 0 - - uint i = 0; - uint man_size = new_man.size(); - - if( man_size >= TTMATH_UINT_HIGHEST_BIT ) - return; // ops, the mantissa is too long - - sint sman_size = -sint(man_size); - - if( new_exp >= sman_size ) - { - sint e = new_exp.ToInt(); - e = -e; - // now e means how many last digits from the mantissa should be equal zero - - i = man_size - uint(e); - } - - for( ; i - uint ToString_BaseRound(string_type & new_man, const Conv & conv, Int & new_exp) const - { - // we must have minimum two characters - if( new_man.size() < 2 ) - return 0; - - // assert that there will not be an integer after rounding - if( ToString_RoundMantissaWouldBeInteger(new_man, conv, new_exp) ) - return 0; - - typename string_type::size_type i = new_man.length() - 1; - - // we're erasing the last character - uint digit = Misc::CharToDigit( new_man[i] ); - new_man.erase(i, 1); - uint c = new_exp.AddOne(); - - // if the last character is greater or equal 'base/2' - // we are adding one into the new mantissa - if( digit >= conv.base / 2 ) - ToString_RoundMantissa_AddOneIntoMantissa(new_man, conv); - - return c; - } - - - /*! - an auxiliary method for converting into the string - - this method addes one into the new mantissa - */ - template - void ToString_RoundMantissa_AddOneIntoMantissa(string_type & new_man, const Conv & conv) const - { - if( new_man.empty() ) - return; - - sint i = sint( new_man.length() ) - 1; - bool was_carry = true; - - for( ; i>=0 && was_carry ; --i ) - { - // we can have the comma as well because - // we're using this method later in ToString_CorrectDigitsAfterComma_Round() - // (we're only ignoring it) - if( new_man[i] == static_cast(conv.comma) ) - continue; - - // we're adding one - uint digit = Misc::CharToDigit( new_man[i] ) + 1; - - if( digit == conv.base ) - digit = 0; - else - was_carry = false; - - new_man[i] = static_cast( Misc::DigitToChar(digit) ); - } - - if( i<0 && was_carry ) - new_man.insert( new_man.begin() , '1' ); - } - - - - /*! - an auxiliary method for converting into the string - - this method sets the comma operator and/or puts the exponent - into the string - */ - template - uint ToString_SetCommaAndExponent(string_type & new_man, const Conv & conv, Int & new_exp) const - { - uint carry = 0; - - if( new_man.empty() ) - return carry; - - Int scientific_exp( new_exp ); - - // 'new_exp' depends on the 'new_man' which is stored like this e.g: - // 32342343234 (the comma is at the end) - // we'd like to show it in this way: - // 3.2342343234 (the 'scientific_exp' is connected with this example) - - sint offset = sint( new_man.length() ) - 1; - carry += scientific_exp.Add( offset ); - // there shouldn't have been a carry because we're using - // a greater type -- 'Int' instead of 'Int' - - bool print_scientific = conv.scient; - - if( !print_scientific ) - { - if( scientific_exp > conv.scient_from || scientific_exp < -sint(conv.scient_from) ) - print_scientific = true; - } - - if( !print_scientific ) - ToString_SetCommaAndExponent_Normal(new_man, conv, new_exp); - else - // we're passing the 'scientific_exp' instead of 'new_exp' here - ToString_SetCommaAndExponent_Scientific(new_man, conv, scientific_exp); - - return (carry==0)? 0 : 1; - } - - - /*! - an auxiliary method for converting into the string - */ - template - void ToString_SetCommaAndExponent_Normal(string_type & new_man, const Conv & conv, Int & new_exp ) const - { - if( !new_exp.IsSign() ) // it means: if( new_exp >= 0 ) - ToString_SetCommaAndExponent_Normal_AddingZero(new_man, new_exp); - else - ToString_SetCommaAndExponent_Normal_SetCommaInside(new_man, conv, new_exp); - - - ToString_Group_man(new_man, conv); - } - - - /*! - an auxiliary method for converting into the string - */ - template - void ToString_SetCommaAndExponent_Normal_AddingZero(string_type & new_man, - Int & new_exp) const - { - // we're adding zero characters at the end - // 'i' will be smaller than 'when_scientific' (or equal) - uint i = new_exp.ToInt(); - - if( new_man.length() + i > new_man.capacity() ) - // about 6 characters more (we'll need it for the comma or something) - new_man.reserve( new_man.length() + i + 6 ); - - for( ; i>0 ; --i) - new_man += '0'; - } - - - /*! - an auxiliary method for converting into the string - */ - template - void ToString_SetCommaAndExponent_Normal_SetCommaInside( - string_type & new_man, - const Conv & conv, - Int & new_exp ) const - { - // new_exp is < 0 - - sint new_man_len = sint(new_man.length()); // 'new_man_len' with a sign - sint e = -( new_exp.ToInt() ); // 'e' will be positive - - if( new_exp > -new_man_len ) - { - // we're setting the comma within the mantissa - - sint index = new_man_len - e; - new_man.insert( new_man.begin() + index, static_cast(conv.comma)); - } - else - { - // we're adding zero characters before the mantissa - - uint how_many = e - new_man_len; - string_type man_temp(how_many+1, '0'); - - man_temp.insert( man_temp.begin()+1, static_cast(conv.comma)); - new_man.insert(0, man_temp); - } - - ToString_CorrectDigitsAfterComma(new_man, conv); - } - - - /*! - an auxiliary method for converting into the string - */ - template - void ToString_SetCommaAndExponent_Scientific( string_type & new_man, - const Conv & conv, - Int & scientific_exp ) const - { - if( new_man.empty() ) - return; - - if( new_man.size() > 1 ) - { - new_man.insert( new_man.begin()+1, static_cast(conv.comma) ); - ToString_CorrectDigitsAfterComma(new_man, conv); - } - - ToString_Group_man(new_man, conv); - - if( conv.base == 10 ) - { - new_man += 'e'; - - if( !scientific_exp.IsSign() ) - new_man += '+'; - } - else - { - // the 10 here is meant as the base 'base' - // (no matter which 'base' we're using there'll always be 10 here) - Misc::AddString(new_man, "*10^"); - } - - string_type temp_exp; - scientific_exp.ToString( temp_exp, conv.base ); - - new_man += temp_exp; - } - - - /*! - an auxiliary method for converting into the string - */ - template - void ToString_Group_man(string_type & new_man, const Conv & conv) const - { - typedef typename string_type::size_type StrSize; - - if( conv.group == 0 ) - return; - - // first we're looking for the comma operator - StrSize index = new_man.find(static_cast(conv.comma), 0); - - if( index == string_type::npos ) - index = new_man.size(); - - ToString_Group_man_before_comma(new_man, conv, index); - ToString_Group_man_after_comma(new_man, conv, index+1); - } - - - - /*! - an auxiliary method for converting into the string - */ - template - void ToString_Group_man_before_comma( string_type & new_man, const Conv & conv, - typename string_type::size_type & index) const - { - typedef typename string_type::size_type StrSize; - - uint group = 0; - StrSize i = index; - uint group_digits = conv.group_digits; - - if( group_digits < 1 ) - group_digits = 1; - - // adding group characters before the comma operator - // i>0 because on the first position we don't put any additional grouping characters - for( ; i>0 ; --i, ++group) - { - if( group >= group_digits ) - { - group = 0; - new_man.insert(i, 1, static_cast(conv.group)); - ++index; - } - } - } - - - /*! - an auxiliary method for converting into the string - */ - template - void ToString_Group_man_after_comma(string_type & new_man, const Conv & conv, - typename string_type::size_type index) const - { - uint group = 0; - uint group_digits = conv.group_digits; - - if( group_digits < 1 ) - group_digits = 1; - - for( ; index= group_digits ) - { - group = 0; - new_man.insert(index, 1, static_cast(conv.group)); - ++index; - } - } - } - - - /*! - an auxiliary method for converting into the string - */ - template - void ToString_CorrectDigitsAfterComma( string_type & new_man, - const Conv & conv ) const - { - if( conv.round >= 0 ) - ToString_CorrectDigitsAfterComma_Round(new_man, conv); - - if( conv.trim_zeroes ) - ToString_CorrectDigitsAfterComma_CutOffZeroCharacters(new_man, conv); - } - - - /*! - an auxiliary method for converting into the string - */ - template - void ToString_CorrectDigitsAfterComma_CutOffZeroCharacters( - string_type & new_man, - const Conv & conv) const - { - // minimum two characters - if( new_man.length() < 2 ) - return; - - // we're looking for the index of the last character which is not zero - uint i = uint( new_man.length() ) - 1; - for( ; i>0 && new_man[i]=='0' ; --i ); - - // if there is another character than zero at the end - // we're finishing - if( i == new_man.length() - 1 ) - return; - - // we must have a comma - // (the comma can be removed by ToString_CorrectDigitsAfterComma_Round - // which is called before) - if( new_man.find_last_of(static_cast(conv.comma), i) == string_type::npos ) - return; - - // if directly before the first zero is the comma operator - // we're cutting it as well - if( i>0 && new_man[i]==static_cast(conv.comma) ) - --i; - - new_man.erase(i+1, new_man.length()-i-1); - } - - - /*! - an auxiliary method for converting into the string - */ - template - void ToString_CorrectDigitsAfterComma_Round( - string_type & new_man, - const Conv & conv ) const - { - typedef typename string_type::size_type StrSize; - - // first we're looking for the comma operator - StrSize index = new_man.find(static_cast(conv.comma), 0); - - if( index == string_type::npos ) - // nothing was found (actually there can't be this situation) - return; - - // we're calculating how many digits there are at the end (after the comma) - // 'after_comma' will be greater than zero because at the end - // we have at least one digit - StrSize after_comma = new_man.length() - index - 1; - - // if 'max_digit_after_comma' is greater than 'after_comma' (or equal) - // we don't have anything for cutting - if( static_cast(conv.round) >= after_comma ) - return; - - uint last_digit = Misc::CharToDigit( new_man[ index + conv.round + 1 ], conv.base ); - - // we're cutting the rest of the string - new_man.erase(index + conv.round + 1, after_comma - conv.round); - - if( conv.round == 0 ) - { - // we're cutting the comma operator as well - // (it's not needed now because we've cut the whole rest after the comma) - new_man.erase(index, 1); - } - - if( last_digit >= conv.base / 2 ) - // we must round here - ToString_RoundMantissa_AddOneIntoMantissa(new_man, conv); - } - - - -public: - - /*! - a method for converting a string into its value - - it returns 1 if the value is too big -- we cannot pass it into the range - of our class Big (or if the base is incorrect) - - that means only digits before the comma operator can make this value too big, - all digits after the comma we can ignore - - 'source' - pointer to the string for parsing - - if 'after_source' is set that when this method finishes - it sets the pointer to the new first character after parsed value - - 'value_read' - if the pointer is provided that means the value_read will be true - only when a value has been actually read, there can be situation where only such - a string '-' or '+' will be parsed -- 'after_source' will be different from 'source' but - no value has been read (there are no digits) - on other words if 'value_read' is true -- there is at least one digit in the string - */ - uint FromString(const char * source, uint base = 10, const char ** after_source = 0, bool * value_read = 0) - { - Conv conv; - conv.base = base; - - return FromStringBase(source, conv, after_source, value_read); - } - - - /*! - a method for converting a string into its value - */ - uint FromString(const char * source, const Conv & conv, const char ** after_source = 0, bool * value_read = 0) - { - return FromStringBase(source, conv, after_source, value_read); - } - - - /*! - a method for converting a string into its value - */ - uint FromString(const std::string & string, uint base = 10, const char ** after_source = 0, bool * value_read = 0) - { - return FromString(string.c_str(), base, after_source, value_read); - } - - - /*! - a method for converting a string into its value - */ - uint FromString(const std::string & string, const Conv & conv, const char ** after_source = 0, bool * value_read = 0) - { - return FromString(string.c_str(), conv, after_source, value_read); - } - - -#ifndef TTMATH_DONT_USE_WCHAR - - /*! - a method for converting a string into its value - */ - uint FromString(const wchar_t * source, uint base = 10, const wchar_t ** after_source = 0, bool * value_read = 0) - { - Conv conv; - conv.base = base; - - return FromStringBase(source, conv, after_source, value_read); - } - - - /*! - a method for converting a string into its value - */ - uint FromString(const wchar_t * source, const Conv & conv, const wchar_t ** after_source = 0, bool * value_read = 0) - { - return FromStringBase(source, conv, after_source, value_read); - } - - - /*! - a method for converting a string into its value - */ - uint FromString(const std::wstring & string, uint base = 10, const wchar_t ** after_source = 0, bool * value_read = 0) - { - return FromString(string.c_str(), base, after_source, value_read); - } - - - /*! - a method for converting a string into its value - */ - uint FromString(const std::wstring & string, const Conv & conv, const wchar_t ** after_source = 0, bool * value_read = 0) - { - return FromString(string.c_str(), conv, after_source, value_read); - } - -#endif - - -private: - - - /*! - an auxiliary method for converting from a string - */ - template - uint FromStringBase(const char_type * source, const Conv & conv, const char_type ** after_source = 0, bool * value_read = 0) - { - bool is_sign; - bool value_read_temp = false; - - if( conv.base<2 || conv.base>16 ) - { - SetNan(); - - if( after_source ) - *after_source = source; - - if( value_read ) - *value_read = value_read_temp; - - return 1; - } - - SetZero(); - FromString_TestSign( source, is_sign ); - - uint c = FromString_ReadPartBeforeComma( source, conv, value_read_temp ); - - if( FromString_TestCommaOperator(source, conv) ) - c += FromString_ReadPartAfterComma( source, conv, value_read_temp ); - - if( value_read_temp && conv.base == 10 ) - c += FromString_ReadScientificIfExists( source ); - - if( is_sign && !IsZero() ) - ChangeSign(); - - if( after_source ) - *after_source = source; - - if( value_read ) - *value_read = value_read_temp; - - return CheckCarry(c); - } - - - /*! - we're testing whether the value is with the sign - - (this method is used from 'FromString_ReadPartScientific' too) - */ - template - void FromString_TestSign( const char_type * & source, bool & is_sign ) - { - Misc::SkipWhiteCharacters(source); - - is_sign = false; - - if( *source == '-' ) - { - is_sign = true; - ++source; - } - else - if( *source == '+' ) - { - ++source; - } - } - - - /*! - we're testing whether there's a comma operator - */ - template - bool FromString_TestCommaOperator(const char_type * & source, const Conv & conv) - { - if( (*source == static_cast(conv.comma)) || - (*source == static_cast(conv.comma2) && conv.comma2 != 0 ) ) - { - ++source; - - return true; - } - - return false; - } - - - /*! - this method reads the first part of a string - (before the comma operator) - */ - template - uint FromString_ReadPartBeforeComma( const char_type * & source, const Conv & conv, bool & value_read ) - { - sint character; - Big temp; - Big base_( conv.base ); - - Misc::SkipWhiteCharacters( source ); - - for( ; true ; ++source ) - { - if( conv.group!=0 && *source==static_cast(conv.group) ) - continue; - - character = Misc::CharToDigit(*source, conv.base); - - if( character == -1 ) - break; - - value_read = true; - temp = character; - - if( Mul(base_) ) - return 1; - - if( Add(temp) ) - return 1; - } - - return 0; - } - - - /*! - this method reads the second part of a string - (after the comma operator) - */ - template - uint FromString_ReadPartAfterComma( const char_type * & source, const Conv & conv, bool & value_read ) - { - sint character; - uint c = 0, power = 0; - UInt<1> power_; - Big sum, base_(conv.base); - - // we don't remove any white characters here - sum.SetZero(); - - for( ; sum.exponent.IsSign() || sum.exponent.IsZero() ; ++source ) - { - if( conv.group!=0 && *source==static_cast(conv.group) ) - continue; - - character = Misc::CharToDigit(*source, conv.base); - - if( character == -1 ) - break; - - value_read = true; - - // there actually shouldn't be a carry here - c += sum.Mul(base_); - c += sum.Add(character); - power += 1; - - if( power == 0 ) - c += 1; - } - - // we could break the parsing somewhere in the middle of the string, - // but the result (value) still can be good - // we should set a correct value of 'source' now - while( Misc::CharToDigit(*source, conv.base) != -1 ) - { - ++source; - } - - power_ = power; - c += base_.Pow(power_); - c += sum.Div(base_); - c += Add(sum); - - return (c==0)? 0 : 1; - } - - - /*! - this method checks whether there is a scientific part: [e|E][-|+]value - - it is called when the base is 10 and some digits were read before - */ - template - uint FromString_ReadScientificIfExists(const char_type * & source) - { - uint c = 0; - - bool scientific_read = false; - const char_type * before_scientific = source; - - if( FromString_TestScientific(source) ) - c += FromString_ReadPartScientific( source, scientific_read ); - - if( !scientific_read ) - source = before_scientific; - - return (c==0)? 0 : 1; - } - - - - /*! - we're testing whether is there the character 'e' - - this character is only allowed when we're using the base equals 10 - */ - template - bool FromString_TestScientific(const char_type * & source) - { - Misc::SkipWhiteCharacters(source); - - if( *source=='e' || *source=='E' ) - { - ++source; - - return true; - } - - return false; - } - - - /*! - this method reads the exponent (after 'e' character) when there's a scientific - format of value and only when we're using the base equals 10 - */ - template - uint FromString_ReadPartScientific( const char_type * & source, bool & scientific_read ) - { - uint c = 0; - Big new_exponent, temp; - bool was_sign = false; - - FromString_TestSign( source, was_sign ); - c += FromString_ReadPartScientific_ReadExponent( source, new_exponent, scientific_read ); - - if( scientific_read ) - { - if( was_sign ) - new_exponent.ChangeSign(); - - temp = 10; - c += temp.Pow( new_exponent ); - c += Mul(temp); - } - - return (c==0)? 0 : 1; - } - - - /*! - this method reads the value of the extra exponent when scientific format is used - (only when base == 10) - */ - template - uint FromString_ReadPartScientific_ReadExponent( const char_type * & source, Big & new_exponent, bool & scientific_read ) - { - sint character; - Big base, temp; - - Misc::SkipWhiteCharacters(source); - - new_exponent.SetZero(); - base = 10; - - for( ; (character=Misc::CharToDigit(*source, 10)) != -1 ; ++source ) - { - scientific_read = true; - - temp = character; - - if( new_exponent.Mul(base) ) - return 1; - - if( new_exponent.Add(temp) ) - return 1; - } - - return 0; - } - - -public: - - - /*! - a constructor for converting a string into this class - */ - Big(const char * string) - { - FromString( string ); - } - - - /*! - a constructor for converting a string into this class - */ - Big(const std::string & string) - { - FromString( string.c_str() ); - } - - - /*! - an operator= for converting a string into its value - */ - Big & operator=(const char * string) - { - FromString( string ); - - return *this; - } - - - /*! - an operator= for converting a string into its value - */ - Big & operator=(const std::string & string) - { - FromString( string.c_str() ); - - return *this; - } - - - -#ifndef TTMATH_DONT_USE_WCHAR - - /*! - a constructor for converting a string into this class - */ - Big(const wchar_t * string) - { - FromString( string ); - } - - - /*! - a constructor for converting a string into this class - */ - Big(const std::wstring & string) - { - FromString( string.c_str() ); - } - - - /*! - an operator= for converting a string into its value - */ - Big & operator=(const wchar_t * string) - { - FromString( string ); - - return *this; - } - - - /*! - an operator= for converting a string into its value - */ - Big & operator=(const std::wstring & string) - { - FromString( string.c_str() ); - - return *this; - } - - -#endif - - - - /*! - * - * methods for comparing - * - */ - - - /*! - this method performs the formula 'abs(this) < abs(ss2)' - and returns the result - - (in other words it treats 'this' and 'ss2' as values without a sign) - we don't check the NaN flag - */ - bool SmallerWithoutSignThan(const Big & ss2) const - { - if( IsZero() ) - { - if( ss2.IsZero() ) - // we've got two zeroes - return false; - else - // this==0 and ss2!=0 - return true; - } - - if( ss2.IsZero() ) - { - // this!=0 and ss2==0 - return false; - } - - // we're using the fact that all bits in mantissa are pushed - // into the left side -- Standardizing() - if( exponent == ss2.exponent ) - return mantissa < ss2.mantissa; - - return exponent < ss2.exponent; - } - - - /*! - this method performs the formula 'abs(this) > abs(ss2)' - and returns the result - - (in other words it treats 'this' and 'ss2' as values without a sign) - we don't check the NaN flag - */ - bool GreaterWithoutSignThan(const Big & ss2) const - { - if( IsZero() ) - { - if( ss2.IsZero() ) - { - // we've got two zeroes - return false; - } - else - { - // this==0 and ss2!=0 - return false; - } - } - - if( ss2.IsZero() ) - { - // this!=0 and ss2==0 - return true; - } - - // we're using the fact that all bits in mantissa are pushed - // into the left side -- Standardizing() - if( exponent == ss2.exponent ) - return mantissa > ss2.mantissa; - - return exponent > ss2.exponent; - } - - - /*! - this method performs the formula 'abs(this) == abs(ss2)' - and returns the result - - (in other words it treats 'this' and 'ss2' as values without a sign) - we don't check the NaN flag - */ - bool EqualWithoutSign(const Big & ss2) const - { - if( IsZero() ) - { - if( ss2.IsZero() ) - { - // we've got two zeroes - return true; - } - else - { - // this==0 and ss2!=0 - return false; - } - } - - if( ss2.IsZero() ) - { - // this!=0 and ss2==0 - return false; - } - - if( exponent==ss2.exponent && mantissa==ss2.mantissa ) - return true; - - return false; - } - - - bool operator<(const Big & ss2) const - { - if( IsSign() && !ss2.IsSign() ) - { - // this<0 and ss2>=0 - return true; - } - - if( !IsSign() && ss2.IsSign() ) - { - // this>=0 and ss2<0 - return false; - } - - // both signs are the same - - if( IsSign() ) - return ss2.SmallerWithoutSignThan( *this ); - - return SmallerWithoutSignThan( ss2 ); - } - - - bool operator==(const Big & ss2) const - { - if( IsSign() != ss2.IsSign() ) - return false; - - return EqualWithoutSign( ss2 ); - } - - - bool operator>(const Big & ss2) const - { - if( IsSign() && !ss2.IsSign() ) - { - // this<0 and ss2>=0 - return false; - } - - if( !IsSign() && ss2.IsSign() ) - { - // this>=0 and ss2<0 - return true; - } - - // both signs are the same - - if( IsSign() ) - return ss2.GreaterWithoutSignThan( *this ); - - return GreaterWithoutSignThan( ss2 ); - } - - - bool operator>=(const Big & ss2) const - { - return !operator<( ss2 ); - } - - - bool operator<=(const Big & ss2) const - { - return !operator>( ss2 ); - } - - - bool operator!=(const Big & ss2) const - { - return !operator==(ss2); - } - - - - - - /*! - * - * standard mathematical operators - * - */ - - - /*! - an operator for changing the sign - - this method is not changing 'this' but the changed value is returned - */ - Big operator-() const - { - Big temp(*this); - - temp.ChangeSign(); - - return temp; - } - - - Big operator-(const Big & ss2) const - { - Big temp(*this); - - temp.Sub(ss2); - - return temp; - } - - Big & operator-=(const Big & ss2) - { - Sub(ss2); - - return *this; - } - - - Big operator+(const Big & ss2) const - { - Big temp(*this); - - temp.Add(ss2); - - return temp; - } - - - Big & operator+=(const Big & ss2) - { - Add(ss2); - - return *this; - } - - - Big operator*(const Big & ss2) const - { - Big temp(*this); - - temp.Mul(ss2); - - return temp; - } - - - Big & operator*=(const Big & ss2) - { - Mul(ss2); - - return *this; - } - - - Big operator/(const Big & ss2) const - { - Big temp(*this); - - temp.Div(ss2); - - return temp; - } - - - Big & operator/=(const Big & ss2) - { - Div(ss2); - - return *this; - } - - - /*! - Prefix operator e.g ++variable - */ - Big & operator++() - { - AddOne(); - - return *this; - } - - - /*! - Postfix operator e.g variable++ - */ - Big operator++(int) - { - Big temp( *this ); - - AddOne(); - - return temp; - } - - - Big & operator--() - { - SubOne(); - - return *this; - } - - - Big operator--(int) - { - Big temp( *this ); - - SubOne(); - - return temp; - } - - - - /*! - * - * bitwise operators - * (we do not define bitwise not) - */ - - - Big operator&(const Big & p2) const - { - Big temp( *this ); - - temp.BitAnd(p2); - - return temp; - } - - - Big & operator&=(const Big & p2) - { - BitAnd(p2); - - return *this; - } - - - Big operator|(const Big & p2) const - { - Big temp( *this ); - - temp.BitOr(p2); - - return temp; - } - - - Big & operator|=(const Big & p2) - { - BitOr(p2); - - return *this; - } - - - Big operator^(const Big & p2) const - { - Big temp( *this ); - - temp.BitXor(p2); - - return temp; - } - - - Big & operator^=(const Big & p2) - { - BitXor(p2); - - return *this; - } - - - - - - - /*! - this method makes an integer value by skipping any fractions - - samples: - - 10.7 will be 10 - - 12.1 -- 12 - - -20.2 -- 20 - - -20.9 -- 20 - - -0.7 -- 0 - - 0.8 -- 0 - */ - void SkipFraction() - { - if( IsNan() || IsZero() ) - return; - - if( !exponent.IsSign() ) - // exponent >=0 -- the value don't have any fractions - return; - - if( exponent <= -sint(man*TTMATH_BITS_PER_UINT) ) - { - // the value is from (-1,1), we return zero - SetZero(); - return; - } - - // exponent is in range (-man*TTMATH_BITS_PER_UINT, 0) - sint e = exponent.ToInt(); - - mantissa.ClearFirstBits( -e ); - - // we don't have to standardize 'Standardizing()' the value because - // there's at least one bit in the mantissa - // (the highest bit which we didn't touch) - } - - - /*! - this method remains only a fraction from the value - - samples: - - 30.56 will be 0.56 - - -12.67 will be -0.67 - */ - void RemainFraction() - { - if( IsNan() || IsZero() ) - return; - - if( !exponent.IsSign() ) - { - // exponent >= 0 -- the value doesn't have any fractions - // we return zero - SetZero(); - return; - } - - if( exponent <= -sint(man*TTMATH_BITS_PER_UINT) ) - { - // the value is from (-1,1) - // we don't make anything with the value - return; - } - - // e will be from (-man*TTMATH_BITS_PER_UINT, 0) - sint e = exponent.ToInt(); - - sint how_many_bits_leave = sint(man*TTMATH_BITS_PER_UINT) + e; // there'll be a subtraction -- e is negative - mantissa.Rcl( how_many_bits_leave, 0); - - // there'll not be a carry because the exponent is too small - exponent.Sub( how_many_bits_leave ); - - // we must call Standardizing() here - Standardizing(); - } - - - - /*! - this method returns true if the value is integer - (there is no a fraction) - - (we don't check NaN) - */ - bool IsInteger() const - { - if( IsZero() ) - return true; - - if( !exponent.IsSign() ) - // exponent >=0 -- the value don't have any fractions - return true; - - if( exponent <= -sint(man*TTMATH_BITS_PER_UINT) ) - // the value is from (-1,1) - return false; - - // exponent is in range (-man*TTMATH_BITS_PER_UINT, 0) - sint e = exponent.ToInt(); - e = -e; // e means how many bits we must check - - uint len = e / TTMATH_BITS_PER_UINT; - uint rest = e % TTMATH_BITS_PER_UINT; - uint i = 0; - - for( ; i 0 ) - { - uint rest_mask = TTMATH_UINT_MAX_VALUE >> (TTMATH_BITS_PER_UINT - rest); - if( (mantissa.table[i] & rest_mask) != 0 ) - return false; - } - - return true; - } - - - /*! - this method rounds to the nearest integer value - (it returns a carry if it was) - - samples: - - 2.3 = 2 - - 2.8 = 3 - - -2.3 = -2 - - -2.8 = 3 - */ - uint Round() - { - Big half; - uint c; - - if( IsNan() ) - return 1; - - if( IsZero() ) - return 0; - - half.Set05(); - - if( IsSign() ) - { - // 'this' is < 0 - c = Sub( half ); - } - else - { - // 'this' is > 0 - c = Add( half ); - } - - SkipFraction(); - - return CheckCarry(c); - } - - - - /*! - * - * input/output operators for standard streams - * - */ - -private: - - /*! - an auxiliary method for outputing to standard streams - */ - template - static ostream_type & OutputToStream(ostream_type & s, const Big & l) - { - string_type ss; - - l.ToString(ss); - s << ss; - - return s; - } - - -public: - - - /*! - output to standard streams - */ - friend std::ostream & operator<<(std::ostream & s, const Big & l) - { - return OutputToStream(s, l); - } - - -#ifndef TTMATH_DONT_USE_WCHAR - - /*! - output to standard streams - */ - friend std::wostream & operator<<(std::wostream & s, const Big & l) - { - return OutputToStream(s, l); - } - -#endif - - - -private: - - /*! - an auxiliary method for converting from a string - */ - template - static istream_type & InputFromStream(istream_type & s, Big & l) - { - string_type ss; - - // char or wchar_t for operator>> - char_type z, old_z; - bool was_comma = false; - bool was_e = false; - - - // operator>> omits white characters if they're set for ommiting - s >> z; - - if( z=='-' || z=='+' ) - { - ss += z; - s >> z; // we're reading a next character (white characters can be ommited) - } - - old_z = 0; - - // we're reading only digits (base=10) and only one comma operator - for( ; s.good() ; z=static_cast(s.get()) ) - { - if( z=='.' || z==',' ) - { - if( was_comma || was_e ) - // second comma operator or comma operator after 'e' character - break; - - was_comma = true; - } - else - if( z == 'e' || z == 'E' ) - { - if( was_e ) - // second 'e' character - break; - - was_e = true; - } - else - if( z == '+' || z == '-' ) - { - if( old_z != 'e' && old_z != 'E' ) - // '+' or '-' is allowed only after 'e' character - break; - } - else - if( Misc::CharToDigit(z, 10) < 0 ) - break; - - - ss += z; - old_z = z; - } - - // we're leaving the last read character - // (it's not belonging to the value) - s.unget(); - - l.FromString( ss ); - - return s; - } - - - -public: - - /*! - input from standard streams - */ - friend std::istream & operator>>(std::istream & s, Big & l) - { - return InputFromStream(s, l); - } - - -#ifndef TTMATH_DONT_USE_WCHAR - - /*! - input from standard streams - */ - friend std::wistream & operator>>(std::wistream & s, Big & l) - { - return InputFromStream(s, l); - } - -#endif - -}; - - -} // namespace - -#endif diff --git a/include/geos/algorithm/ttmath/ttmathdec.h b/include/geos/algorithm/ttmath/ttmathdec.h deleted file mode 100644 index ec2c753242..0000000000 --- a/include/geos/algorithm/ttmath/ttmathdec.h +++ /dev/null @@ -1,419 +0,0 @@ -/* - * This file is a part of TTMath Bignum Library - * and is distributed under the 3-Clause BSD Licence. - * Author: Tomasz Sowa - */ - -/* - * Copyright (c) 2012, Tomasz Sowa - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * * Neither the name Tomasz Sowa nor the names of contributors to this - * project may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef headerfilettmathdec -#define headerfilettmathdec - -#include "ttmathtypes.h" -#include "ttmaththreads.h" -#include "ttmathuint.h" - - - -namespace ttmath -{ - -template -class Dec -{ -public: - - UInt value; - unsigned char info; - - - /*! - Sign - the mask of a bit from 'info' which means that there is a sign - (when the bit is set) - */ - #define TTMATH_DEC_SIGN 128 - - - /*! - Not a number - if this bit is set that there is not a valid number - */ - #define TTMATH_DEC_NAN 64 - - - - - Dec() - { - info = TTMATH_DEC_NAN; - } - - - Dec(const char * s) - { - info = TTMATH_DEC_NAN; - FromString(s); - } - - - Dec & operator=(const char * s) - { - FromString(s); - - return *this; - } - - - uint FromString(const char * s, const char ** after_source = 0, bool * value_read = 0) - { - return FromStringBase(s, after_source, value_read); - } - - - void ToString(std::string & result) const - { - ToStringBase(result); - } - - - /*! - this method clears a specific bit in the 'info' variable - - bit is one of: - */ - void ClearInfoBit(unsigned char bit) - { - info = info & (~bit); - } - - - /*! - this method sets a specific bit in the 'info' variable - - bit is one of: - - */ - void SetInfoBit(unsigned char bit) - { - info = info | bit; - } - - - /*! - this method returns true if a specific bit in the 'info' variable is set - - bit is one of: - */ - bool IsInfoBit(unsigned char bit) const - { - return (info & bit) != 0; - } - - - bool IsNan() const - { - return IsInfoBit(TTMATH_DEC_NAN); - } - - - bool IsSign() const - { - return IsInfoBit(TTMATH_DEC_SIGN); - } - - - /*! - this method sets the sign - - e.g. - -1 -> -1 - 2 -> -2 - - we do not check whether there is a zero or not, if you're using this method - you must be sure that the value is (or will be afterwards) different from zero - */ - void SetSign() - { - SetInfoBit(TTMATH_DEC_SIGN); - } - - - void SetNaN() - { - SetInfoBit(TTMATH_DEC_NAN); - } - - - void Abs() - { - ClearInfoBit(TTMATH_DEC_SIGN); - } - - - - uint Add(const Dec & arg) - { - uint c = 0; - - if( IsSign() == arg.IsSign() ) - { - c += value.Add(arg.value); - } - else - { - bool is_sign; - - if( value > arg.value ) - { - is_sign = IsSign(); - value.Sub(arg.value); - } - else - { - is_sign = arg.IsSign(); - UInt temp(this->value); - value = arg.value; - value.Sub(temp); - } - - is_sign ? SetSign() : Abs(); - } - - if( c ) - SetNaN(); - - return (c==0)? 0 : 1; - } - -/* - uint Sub(const Dec & arg) - { - } -*/ - -private: - - - - - - -#ifndef TTMATH_MULTITHREADS - - /*! - */ - void SetMultipler(UInt & result) - { - // this guardian is initialized before the program runs (static POD type) - static int guardian = 0; - static UInt multipler; - - if( guardian == 0 ) - { - multipler = 10; - multipler.Pow(dec_digits); - guardian = 1; - } - - result = multipler; - } - -#else - - /*! - */ - void SetMultipler(UInt & result) - { - // this guardian is initialized before the program runs (static POD type) - volatile static sig_atomic_t guardian = 0; - static UInt * pmultipler; - - // double-checked locking - if( guardian == 0 ) - { - ThreadLock thread_lock; - - // locking - if( thread_lock.Lock() ) - { - static UInt multipler; - - if( guardian == 0 ) - { - pmultipler = &multipler; - multipler = 10; - multipler.Pow(dec_digits); - guardian = 1; - } - } - else - { - // there was a problem with locking, we store the result directly in 'result' object - result = 10; - result.Pow(dec_digits); - - return; - } - - // automatically unlocking - } - - result = *pmultipler; - } - -#endif - - - - /*! - an auxiliary method for converting from a string - */ - template - uint FromStringBase(const char_type * s, const char_type ** after_source = 0, bool * value_read = 0) - { - UInt multipler; - const char_type * after; - uint c = 0; - info = 0; - - Misc::SkipWhiteCharacters(s); - - if( *s == '-' ) - { - s += 1; - SetSign(); - } - else - if( *s == '+' ) - { - s += 1; - } - - c += value.FromString(s, 10, &after, value_read); - - if( after_source ) - *after_source = after; - - SetMultipler(multipler); - c += value.Mul(multipler); - - if( *after == '.' ) - c += FromStringBaseAfterComma(after+1, after_source); - - if( c ) - SetInfoBit(TTMATH_DEC_NAN); - - return (c==0)? 0 : 1; - } - - - template - uint FromStringBaseAfterComma(const char_type * s, const char_type ** after_source = 0, bool * value_read = 0) - { - UInt temp; - UInt multipler; - sint z; - uint c = 0; - size_t i = dec_digits; - - SetMultipler(multipler); - - for( ; i>0 && (z=Misc::CharToDigit(*s, 10)) != -1 ; --i, ++s ) - { - multipler.DivInt(10); - temp.SetZero(); - - if( value_read ) - *value_read = true; - - if( c == 0 ) - { - temp.table[0] = z; - c += temp.Mul(multipler); - c += value.Add(temp); - } - } - - if( i == 0 && (z=Misc::CharToDigit(*s, 10)) != -1 && z >= 5 ) - c += value.AddOne(); - - if( after_source ) - { - while( (z=Misc::CharToDigit(*s, 10)) != -1 ) - s += 1; - - *after_source = s; - } - - return c; - } - - - - template - void ToStringBase(string_type & result) const - { - if( IsNan() ) - { - result = "NaN"; - return; - } - - value.ToStringBase(result, 10, IsSign()); - - if( dec_digits > 0 ) - { - size_t size = result.size(); - - if( IsSign() && size > 0 ) - size -= 1; - - if( dec_digits >= size ) - { - size_t zeroes = dec_digits - size + 1; - size_t start = IsSign() ? 1 : 0; - result.insert(start, zeroes, '0'); - } - - result.insert(result.end() - dec_digits, '.'); - } - } - - - -}; - - -} // namespace - -#endif diff --git a/include/geos/algorithm/ttmath/ttmathint.h b/include/geos/algorithm/ttmath/ttmathint.h deleted file mode 100644 index 7188184a3c..0000000000 --- a/include/geos/algorithm/ttmath/ttmathint.h +++ /dev/null @@ -1,1923 +0,0 @@ -/* - * This file is a part of TTMath Bignum Library - * and is distributed under the 3-Clause BSD Licence. - * Author: Tomasz Sowa - */ - -/* - * Copyright (c) 2006-2017, Tomasz Sowa - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * * Neither the name Tomasz Sowa nor the names of contributors to this - * project may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#ifndef headerfilettmathint -#define headerfilettmathint - -/*! - \file ttmathint.h - \brief template class Int -*/ - -#include "ttmathuint.h" - -namespace ttmath -{ - - -/*! - \brief Int implements a big integer value with a sign - - value_size - how many bytes specify our value - - on 32bit platforms: value_size=1 -> 4 bytes -> 32 bits - - on 64bit platforms: value_size=1 -> 8 bytes -> 64 bits - value_size = 1,2,3,4,5,6.... -*/ -template -class Int : public UInt -{ -public: - - /*! - this method sets the max value which this class can hold - (all bits will be one besides the last one) - */ - void SetMax() - { - UInt::SetMax(); - UInt::table[value_size-1] = ~ TTMATH_UINT_HIGHEST_BIT; - } - - - /*! - this method sets the min value which this class can hold - (all bits will be zero besides the last one which is one) - */ - void SetMin() - { - UInt::SetZero(); - UInt::table[value_size-1] = TTMATH_UINT_HIGHEST_BIT; - } - - - /*! - this method sets -1 as the value - (-1 is equal the max value in an unsigned type) - */ - void SetSignOne() - { - UInt::SetMax(); - } - - - /*! - we change the sign of the value - - if it isn't possible to change the sign this method returns 1 - else return 0 and changing the sign - */ - uint ChangeSign() - { - /* - if the value is equal that one which has been returned from SetMin - (only the highest bit is set) that means we can't change sign - because the value is too big (bigger about one) - - e.g. when value_size = 1 and value is -2147483648 we can't change it to the - 2147483648 because the max value which can be held is 2147483647 - - we don't change the value and we're using this fact somewhere in some methods - (if we look on our value without the sign we get the correct value - eg. -2147483648 in Int<1> will be 2147483648 on the UInt<1> type) - */ - if( UInt::IsOnlyTheHighestBitSet() ) - return 1; - - UInt temp(*this); - UInt::SetZero(); - UInt::Sub(temp); - - return 0; - } - - - - /*! - this method sets the sign - - samples - - 1 -> -1 - - -2 -> -2 - - from a positive value we make a negative value, - if the value is negative we do nothing - */ - void SetSign() - { - if( IsSign() ) - return; - - ChangeSign(); - } - - - - /*! - this method returns true if there's the sign - - (the highest bit will be converted to the bool) - */ - bool IsSign() const - { - return UInt::IsTheHighestBitSet(); - } - - - - /*! - it sets an absolute value - - it can return carry (1) (look on ChangeSign() for details) - */ - uint Abs() - { - if( !IsSign() ) - return 0; - - return ChangeSign(); - } - - - - - /*! - * - * basic mathematic functions - * - */ - -private: - - uint CorrectCarryAfterAdding(bool p1_is_sign, bool p2_is_sign) - { - if( !p1_is_sign && !p2_is_sign ) - { - if( UInt::IsTheHighestBitSet() ) - return 1; - } - - if( p1_is_sign && p2_is_sign ) - { - if( ! UInt::IsTheHighestBitSet() ) - return 1; - } - - return 0; - } - - -public: - - /*! - this method adds two value with a sign and returns a carry - - we're using methods from the base class because values are stored with U2 - we must only make the carry correction - - this = p1(=this) + p2 - - when p1>=0 i p2>=0 carry is set when the highest bit of value is set - when p1<0 i p2<0 carry is set when the highest bit of value is clear - when p1>=0 i p2<0 carry will never be set - when p1<0 i p2>=0 carry will never be set - */ - uint Add(const Int & ss2) - { - bool p1_is_sign = IsSign(); - bool p2_is_sign = ss2.IsSign(); - - UInt::Add(ss2); - - return CorrectCarryAfterAdding(p1_is_sign, p2_is_sign); - } - - - /*! - this method adds one *unsigned* word (at a specific position) - and returns a carry (if it was) - - look at a description in UInt<>::AddInt(...) - */ - uint AddInt(uint value, uint index = 0) - { - bool p1_is_sign = IsSign(); - - UInt::AddInt(value, index); - - return CorrectCarryAfterAdding(p1_is_sign, false); - } - - - /*! - this method adds two *unsigned* words to the existing value - and these words begin on the 'index' position - - index should be equal or smaller than value_size-2 (index <= value_size-2) - x1 - lower word, x2 - higher word - - look at a description in UInt<>::AddTwoInts(...) - */ - uint AddTwoInts(uint x2, uint x1, uint index) - { - bool p1_is_sign = IsSign(); - - UInt::AddTwoInts(x2, x1, index); - - return CorrectCarryAfterAdding(p1_is_sign, false); - } - -private: - - uint CorrectCarryAfterSubtracting(bool p1_is_sign, bool p2_is_sign) - { - if( !p1_is_sign && p2_is_sign ) - { - if( UInt::IsTheHighestBitSet() ) - return 1; - } - - if( p1_is_sign && !p2_is_sign ) - { - if( ! UInt::IsTheHighestBitSet() ) - return 1; - } - - return 0; - } - -public: - - /*! - this method subtracts two values with a sign - - we don't use the previous Add because the method ChangeSign can - sometimes return carry - - this = p1(=this) - p2 - - - when p1>=0 i p2>=0 carry will never be set - - when p1<0 i p2<0 carry will never be set - - when p1>=0 i p2<0 carry is set when the highest bit of value is set - - when p1<0 i p2>=0 carry is set when the highest bit of value is clear - */ - uint Sub(const Int & ss2) - { - bool p1_is_sign = IsSign(); - bool p2_is_sign = ss2.IsSign(); - - UInt::Sub(ss2); - - return CorrectCarryAfterSubtracting(p1_is_sign, p2_is_sign); - } - - - /*! - this method subtracts one *unsigned* word (at a specific position) - and returns a carry (if it was) - */ - uint SubInt(uint value, uint index = 0) - { - bool p1_is_sign = IsSign(); - - UInt::SubInt(value, index); - - return CorrectCarryAfterSubtracting(p1_is_sign, false); - } - - - /*! - this method adds one to the value and returns carry - */ - uint AddOne() - { - bool p1_is_sign = IsSign(); - - UInt::AddOne(); - - return CorrectCarryAfterAdding(p1_is_sign, false); - } - - - /*! - this method subtracts one from the value and returns carry - */ - uint SubOne() - { - bool p1_is_sign = IsSign(); - - UInt::SubOne(); - - return CorrectCarryAfterSubtracting(p1_is_sign, false); - } - - -private: - - - uint CheckMinCarry(bool ss1_is_sign, bool ss2_is_sign) - { - /* - we have to examine the sign of the result now - but if the result is with the sign then: - 1. if the signs were the same that means the result is too big - (the result must be without a sign) - 2. if the signs were different that means if the result - is different from that one which has been returned from SetMin() - that is carry (result too big) but if the result is equal SetMin() - there'll be ok (and the next SetSign will has no effect because - the value is actually negative -- look at description of that case - in ChangeSign()) - */ - if( IsSign() ) - { - if( ss1_is_sign != ss2_is_sign ) - { - /* - there can be one case where signs are different and - the result will be equal the value from SetMin() (only the highest bit is set) - (this situation is ok) - */ - if( !UInt::IsOnlyTheHighestBitSet() ) - return 1; - } - else - { - // signs were the same - return 1; - } - } - - return 0; - } - - -public: - - - /*! - multiplication: this = this * ss2 - - it can return a carry - */ - uint MulInt(sint ss2) - { - bool ss1_is_sign, ss2_is_sign; - uint c; - - ss1_is_sign = IsSign(); - - /* - we don't have to check the carry from Abs (values will be correct - because next we're using the method MulInt from the base class UInt - which is without a sign) - */ - Abs(); - - if( ss2 < 0 ) - { - ss2 = -ss2; - ss2_is_sign = true; - } - else - { - ss2_is_sign = false; - } - - c = UInt::MulInt((uint)ss2); - c += CheckMinCarry(ss1_is_sign, ss2_is_sign); - - if( ss1_is_sign != ss2_is_sign ) - SetSign(); - - return c; - } - - - - /*! - multiplication this = this * ss2 - - it returns carry if the result is too big - (we're using the method from the base class but we have to make - one correction in account of signs) - */ - uint Mul(Int ss2) - { - bool ss1_is_sign, ss2_is_sign; - uint c; - - ss1_is_sign = IsSign(); - ss2_is_sign = ss2.IsSign(); - - /* - we don't have to check the carry from Abs (values will be correct - because next we're using the method Mul from the base class UInt - which is without a sign) - */ - Abs(); - ss2.Abs(); - - c = UInt::Mul(ss2); - c += CheckMinCarry(ss1_is_sign, ss2_is_sign); - - if( ss1_is_sign != ss2_is_sign ) - SetSign(); - - return c; - } - - - /*! - division this = this / ss2 - returned values: - - 0 - ok - - 1 - division by zero - - for example: (result means 'this') - - 20 / 3 --> result: 6 remainder: 2 - - -20 / 3 --> result: -6 remainder: -2 - - 20 / -3 --> result: -6 remainder: 2 - - -20 / -3 --> result: 6 remainder: -2 - - in other words: this(old) = ss2 * this(new)(result) + remainder - */ - uint Div(Int ss2, Int * remainder = 0) - { - bool ss1_is_sign, ss2_is_sign; - - ss1_is_sign = IsSign(); - ss2_is_sign = ss2.IsSign(); - - /* - we don't have to test the carry from Abs as well as in Mul - */ - Abs(); - ss2.Abs(); - - uint c = UInt::Div(ss2, remainder); - - if( ss1_is_sign != ss2_is_sign ) - SetSign(); - - if( ss1_is_sign && remainder ) - remainder->SetSign(); - - return c; - } - - uint Div(const Int & ss2, Int & remainder) - { - return Div(ss2, &remainder); - } - - - /*! - division this = this / ss2 (ss2 is int) - returned values: - - 0 - ok - - 1 - division by zero - - for example: (result means 'this') - - 20 / 3 --> result: 6 remainder: 2 - - -20 / 3 --> result: -6 remainder: -2 - - 20 / -3 --> result: -6 remainder: 2 - - -20 / -3 --> result: 6 remainder: -2 - - in other words: this(old) = ss2 * this(new)(result) + remainder - */ - uint DivInt(sint ss2, sint * remainder = 0) - { - bool ss1_is_sign, ss2_is_sign; - - ss1_is_sign = IsSign(); - - /* - we don't have to test the carry from Abs as well as in Mul - */ - Abs(); - - if( ss2 < 0 ) - { - ss2 = -ss2; - ss2_is_sign = true; - } - else - { - ss2_is_sign = false; - } - - uint rem; - uint c = UInt::DivInt((uint)ss2, &rem); - - if( ss1_is_sign != ss2_is_sign ) - SetSign(); - - if( remainder ) - { - if( ss1_is_sign ) - *remainder = -sint(rem); - else - *remainder = sint(rem); - } - - return c; - } - - - uint DivInt(sint ss2, sint & remainder) - { - return DivInt(ss2, &remainder); - } - - -private: - - - /*! - power this = this ^ pow - this can be negative - pow is >= 0 - */ - uint Pow2(const Int & pow) - { - bool was_sign = IsSign(); - uint c = 0; - - if( was_sign ) - c += Abs(); - - uint c_temp = UInt::Pow(pow); - if( c_temp > 0 ) - return c_temp; // c_temp can be: 0, 1 or 2 - - if( was_sign && (pow.table[0] & 1) == 1 ) - // negative value to the power of odd number is negative - c += ChangeSign(); - - return (c==0)? 0 : 1; - } - - -public: - - - /*! - power this = this ^ pow - - return values: - - 0 - ok - - 1 - carry - - 2 - incorrect arguments 0^0 or 0^(-something) - */ - uint Pow(Int pow) - { - if( !pow.IsSign() ) - return Pow2(pow); - - if( UInt::IsZero() ) - // if 'pow' is negative then - // 'this' must be different from zero - return 2; - - if( pow.ChangeSign() ) - return 1; - - Int t(*this); - uint c_temp = t.Pow2(pow); - if( c_temp > 0 ) - return c_temp; - - UInt::SetOne(); - if( Div(t) ) - return 1; - - return 0; - } - - - - /*! - * - * convertion methods - * - */ -private: - - - /*! - an auxiliary method for converting both from UInt and Int - */ - template - uint FromUIntOrInt(const UInt & p, bool UInt_type) - { - uint min_size = (value_size < argument_size)? value_size : argument_size; - uint i; - - for(i=0 ; i::table[i] = p.table[i]; - - - if( value_size > argument_size ) - { - uint fill; - - if( UInt_type ) - fill = 0; - else - fill = (p.table[argument_size-1] & TTMATH_UINT_HIGHEST_BIT)? - TTMATH_UINT_MAX_VALUE : 0; - - // 'this' is longer than 'p' - for( ; i::table[i] = fill; - } - else - { - uint test = (UInt::table[value_size-1] & TTMATH_UINT_HIGHEST_BIT)? - TTMATH_UINT_MAX_VALUE : 0; - - if( UInt_type && test!=0 ) - return 1; - - for( ; i type into this class - - this operation has mainly sense if the value from p - can be held in this type - - it returns a carry if the value 'p' is too big - */ - template - uint FromInt(const Int & p) - { - return FromUIntOrInt(p, false); - } - - - /*! - this method converts the sint type into this class - */ - uint FromInt(sint value) - { - uint fill = ( value<0 ) ? TTMATH_UINT_MAX_VALUE : 0; - - for(uint i=1 ; i::table[i] = fill; - - UInt::table[0] = uint(value); - - // there'll never be a carry here - return 0; - } - - - /*! - this method converts UInt into this class - */ - template - uint FromUInt(const UInt & p) - { - return FromUIntOrInt(p, true); - } - - - /*! - this method converts UInt into this class - */ - template - uint FromInt(const UInt & p) - { - return FromUIntOrInt(p, true); - } - - - /*! - this method converts the uint type into this class - */ - uint FromUInt(uint value) - { - for(uint i=1 ; i::table[i] = 0; - - UInt::table[0] = value; - - // there can be a carry here when the size of this value is equal one word - // and the 'value' has the highest bit set - if( value_size==1 && (value & TTMATH_UINT_HIGHEST_BIT)!=0 ) - return 1; - - return 0; - } - - - /*! - this method converts the uint type into this class - */ - uint FromInt(uint value) - { - return FromUInt(value); - } - - - /*! - the default assignment operator - */ - Int & operator=(const Int & p) - { - FromInt(p); - - return *this; - } - - - /*! - this operator converts an Int type to this class - - it doesn't return a carry - */ - template - Int & operator=(const Int & p) - { - FromInt(p); - - return *this; - } - - - /*! - this method converts the sint type to this class - */ - Int & operator=(sint i) - { - FromInt(i); - - return *this; - } - - - /*! - a constructor for converting the uint to this class - */ - Int(sint i) - { - FromInt(i); - } - - - /*! - a copy constructor - */ - Int(const Int & u) : UInt() - { - FromInt(u); - } - - - /*! - a constructor for copying from another types - */ - template - Int(const Int & u) - { - // look that 'size' we still set as 'value_size' and not as u.value_size - FromInt(u); - } - - - - /*! - this operator converts an UInt type to this class - - it doesn't return a carry - */ - template - Int & operator=(const UInt & p) - { - FromUInt(p); - - return *this; - } - - - /*! - this method converts the Uint type to this class - */ - Int & operator=(uint i) - { - FromUInt(i); - - return *this; - } - - - /*! - a constructor for converting the uint to this class - */ - Int(uint i) - { - FromUInt(i); - } - - - /*! - a constructor for copying from another types - */ - template - Int(const UInt & u) - { - // look that 'size' we still set as 'value_size' and not as u.value_size - FromUInt(u); - } - - - -#ifdef TTMATH_PLATFORM32 - - - /*! - this method converts unsigned 64 bit int type to this class - ***this method is created only on a 32bit platform*** - */ - uint FromUInt(ulint n) - { - uint c = UInt::FromUInt(n); - - if( c ) - return 1; - - if( value_size == 1 ) - return ((UInt::table[0] & TTMATH_UINT_HIGHEST_BIT) == 0) ? 0 : 1; - - if( value_size == 2 ) - return ((UInt::table[1] & TTMATH_UINT_HIGHEST_BIT) == 0) ? 0 : 1; - - return 0; - } - - - /*! - this method converts unsigned 64 bit int type to this class - ***this method is created only on a 32bit platform*** - */ - uint FromInt(ulint n) - { - return FromUInt(n); - } - - - /*! - this method converts signed 64 bit int type to this class - ***this method is created only on a 32bit platform*** - */ - uint FromInt(slint n) - { - uint mask = (n < 0) ? TTMATH_UINT_MAX_VALUE : 0; - - UInt::table[0] = (uint)(ulint)n; - - if( value_size == 1 ) - { - if( uint(ulint(n) >> 32) != mask ) - return 1; - - return ((UInt::table[0] & TTMATH_UINT_HIGHEST_BIT) == (mask & TTMATH_UINT_HIGHEST_BIT)) ? 0 : 1; - } - - UInt::table[1] = (uint)(ulint(n) >> 32); - - for(uint i=2 ; i::table[i] = mask; - - return 0; - } - - - /*! - this operator converts unsigned 64 bit int type to this class - ***this operator is created only on a 32bit platform*** - */ - Int & operator=(ulint n) - { - FromUInt(n); - - return *this; - } - - - /*! - a constructor for converting unsigned 64 bit int to this class - ***this constructor is created only on a 32bit platform*** - */ - Int(ulint n) - { - FromUInt(n); - } - - - /*! - this operator converts signed 64 bit int type to this class - ***this operator is created only on a 32bit platform*** - */ - Int & operator=(slint n) - { - FromInt(n); - - return *this; - } - - - /*! - a constructor for converting signed 64 bit int to this class - ***this constructor is created only on a 32bit platform*** - */ - Int(slint n) - { - FromInt(n); - } - -#endif - - - - -#ifdef TTMATH_PLATFORM64 - - /*! - this method converts 32 bit unsigned int type to this class - ***this operator is created only on a 64bit platform*** - */ - uint FromUInt(unsigned int i) - { - return FromUInt(uint(i)); - } - - - /*! - this method converts 32 bit unsigned int type to this class - ***this operator is created only on a 64bit platform*** - */ - uint FromInt(unsigned int i) - { - return FromUInt(i); - } - - - /*! - this method converts 32 bit signed int type to this class - ***this operator is created only on a 64bit platform*** - */ - uint FromInt(signed int i) - { - return FromInt(sint(i)); - } - - - /*! - this method converts 32 bit unsigned int type to this class - ***this operator is created only on a 64bit platform*** - */ - Int & operator=(unsigned int i) - { - FromUInt(i); - - return *this; - } - - - /*! - a constructor for converting 32 bit unsigned int to this class - ***this constructor is created only on a 64bit platform*** - */ - Int(unsigned int i) - { - FromUInt(i); - } - - - /*! - this operator converts 32 bit signed int type to this class - ***this operator is created only on a 64bit platform*** - */ - Int & operator=(signed int i) - { - FromInt(i); - - return *this; - } - - - /*! - a constructor for converting 32 bit signed int to this class - ***this constructor is created only on a 64bit platform*** - */ - Int(signed int i) - { - FromInt(i); - } - -#endif - - - - /*! - a constructor for converting string to this class (with the base=10) - */ - Int(const char * s) - { - FromString(s); - } - - - /*! - a constructor for converting a string to this class (with the base=10) - */ - Int(const std::string & s) - { - FromString( s.c_str() ); - } - - -#ifndef TTMATH_DONT_USE_WCHAR - - /*! - a constructor for converting string to this class (with the base=10) - */ - Int(const wchar_t * s) - { - FromString(s); - } - - - /*! - a constructor for converting a string to this class (with the base=10) - */ - Int(const std::wstring & s) - { - FromString( s.c_str() ); - } - -#endif - - - /*! - a default constructor - - we don't clear table etc. - */ - Int() - { - } - - - /*! - the destructor - */ - ~Int() - { - } - - - /*! - this method returns the lowest value from table with a sign - - we must be sure when we using this method whether the value - will hold in an sint type or not (the rest value from table must be zero or -1) - */ - sint ToInt() const - { - return sint( UInt::table[0] ); - } - - - /*! - this method converts the value to uint type - can return a carry if the value is too long to store it in uint type - */ - uint ToUInt(uint & result) const - { - uint c = UInt::ToUInt(result); - - if( value_size == 1 ) - return (result & TTMATH_UINT_HIGHEST_BIT) == 0 ? 0 : 1; - - return c; - } - - - /*! - this method converts the value to uint type - can return a carry if the value is too long to store it in uint type - */ - uint ToInt(uint & result) const - { - return ToUInt(result); - } - - - /*! - this method converts the value to sint type - can return a carry if the value is too long to store it in sint type - */ - uint ToInt(sint & result) const - { - result = sint( UInt::table[0] ); - uint mask = IsSign() ? TTMATH_UINT_MAX_VALUE : 0; - - if( (result & TTMATH_UINT_HIGHEST_BIT) != (mask & TTMATH_UINT_HIGHEST_BIT) ) - return 1; - - for(uint i=1 ; i::table[i] != mask ) - return 1; - - return 0; - } - - -#ifdef TTMATH_PLATFORM32 - - /*! - this method converts the value to ulint type (64 bit unsigned integer) - can return a carry if the value is too long to store it in ulint type - *** this method is created only on a 32 bit platform *** - */ - uint ToUInt(ulint & result) const - { - uint c = UInt::ToUInt(result); - - if( value_size == 1 ) - return (UInt::table[0] & TTMATH_UINT_HIGHEST_BIT) == 0 ? 0 : 1; - - if( value_size == 2 ) - return (UInt::table[1] & TTMATH_UINT_HIGHEST_BIT) == 0 ? 0 : 1; - - return c; - } - - - /*! - this method converts the value to ulint type (64 bit unsigned integer) - can return a carry if the value is too long to store it in ulint type - *** this method is created only on a 32 bit platform *** - */ - uint ToInt(ulint & result) const - { - return ToUInt(result); - } - - - /*! - this method converts the value to slint type (64 bit signed integer) - can return a carry if the value is too long to store it in slint type - *** this method is created only on a 32 bit platform *** - */ - uint ToInt(slint & result) const - { - if( value_size == 1 ) - { - result = slint(sint(UInt::table[0])); - } - else - { - uint low = UInt::table[0]; - uint high = UInt::table[1]; - - result = low; - result |= (ulint(high) << TTMATH_BITS_PER_UINT); - - uint mask = IsSign() ? TTMATH_UINT_MAX_VALUE : 0; - - if( (high & TTMATH_UINT_HIGHEST_BIT) != (mask & TTMATH_UINT_HIGHEST_BIT) ) - return 1; - - for(uint i=2 ; i::table[i] != mask ) - return 1; - } - - return 0; - } - -#endif - - - -#ifdef TTMATH_PLATFORM64 - - /*! - this method converts the value to a 32 bit unsigned integer - can return a carry if the value is too long to store it in this type - *** this method is created only on a 64 bit platform *** - */ - uint ToUInt(unsigned int & result) const - { - uint c = UInt::ToUInt(result); - - if( c || IsSign() ) - return 1; - - return 0; - } - - - /*! - this method converts the value to a 32 bit unsigned integer - can return a carry if the value is too long to store it in this type - *** this method is created only on a 64 bit platform *** - */ - uint ToInt(unsigned int & result) const - { - return ToUInt(result); - } - - - /*! - this method converts the value to a 32 bit signed integer - can return a carry if the value is too long to store it in this type - *** this method is created only on a 64 bit platform *** - */ - uint ToInt(int & result) const - { - uint first = UInt::table[0]; - - result = int(first); - uint mask = IsSign() ? TTMATH_UINT_MAX_VALUE : 0; - - if( (first >> 31) != (mask >> 31) ) - return 1; - - for(uint i=1 ; i::table[i] != mask ) - return 1; - - return 0; - } - -#endif - - - - -private: - - /*! - an auxiliary method for converting to a string - */ - template - void ToStringBase(string_type & result, uint b = 10) const - { - if( IsSign() ) - { - Int temp(*this); - temp.Abs(); - temp.UInt::ToStringBase(result, b, true); - } - else - { - UInt::ToStringBase(result, b, false); - } - } - -public: - - /*! - this method converts the value to a string with a base equal 'b' - */ - void ToString(std::string & result, uint b = 10) const - { - return ToStringBase(result, b); - } - - - /*! - this method converts the value to a string with a base equal 'b' - */ - std::string ToString(uint b = 10) const - { - std::string result; - ToStringBase(result, b); - - return result; - } - - -#ifndef TTMATH_DONT_USE_WCHAR - - /*! - this method converts the value to a string with a base equal 'b' - */ - void ToString(std::wstring & result, uint b = 10) const - { - return ToStringBase(result, b); - } - - - /*! - this method converts the value to a string with a base equal 'b' - */ - std::wstring ToWString(uint b = 10) const - { - std::wstring result; - ToStringBase(result, b); - - return result; - } - -#endif - - - -private: - - /*! - an auxiliary method for converting from a string - */ - template - uint FromStringBase(const char_type * s, uint b = 10, const char_type ** after_source = 0, bool * value_read = 0) - { - bool is_sign = false; - - Misc::SkipWhiteCharacters(s); - - if( *s == '-' ) - { - is_sign = true; - Misc::SkipWhiteCharacters(++s); - } - else - if( *s == '+' ) - { - Misc::SkipWhiteCharacters(++s); - } - - if( UInt::FromString(s,b,after_source,value_read) ) - return 1; - - if( is_sign ) - { - Int mmin; - - mmin.SetMin(); - - /* - the reference to mmin will be automatically converted to the reference - to UInt type - (this value can be equal mmin -- look at a description in ChangeSign()) - */ - if( UInt::operator>( mmin ) ) - return 1; - - /* - if the value is equal mmin the method ChangeSign() does nothing (only returns 1 but we ignore it) - */ - ChangeSign(); - } - else - { - Int mmax; - - mmax.SetMax(); - - if( UInt::operator>( mmax ) ) - return 1; - } - - return 0; - } - - -public: - - /*! - this method converts a string into its value - it returns carry=1 if the value will be too big or an incorrect base 'b' is given - - string is ended with a non-digit value, for example: - "-12" will be translated to -12 - as well as: - "- 12foo" will be translated to -12 too - - existing first white characters will be ommited - (between '-' and a first digit can be white characters too) - - after_source (if exists) is pointing at the end of the parsed string - - value_read (if exists) tells whether something has actually been read (at least one digit) - */ - uint FromString(const char * s, uint b = 10, const char ** after_source = 0, bool * value_read = 0) - { - return FromStringBase(s, b, after_source, value_read); - } - - - /*! - this method converts a string into its value - */ - uint FromString(const wchar_t * s, uint b = 10, const wchar_t ** after_source = 0, bool * value_read = 0) - { - return FromStringBase(s, b, after_source, value_read); - } - - - /*! - this method converts a string into its value - it returns carry=1 if the value will be too big or an incorrect base 'b' is given - */ - uint FromString(const std::string & s, uint b = 10) - { - return FromString( s.c_str(), b ); - } - - - /*! - this operator converts a string into its value (with base = 10) - */ - Int & operator=(const char * s) - { - FromString(s); - - return *this; - } - - -#ifndef TTMATH_DONT_USE_WCHAR - - - /*! - this method converts a string into its value - it returns carry=1 if the value will be too big or an incorrect base 'b' is given - */ - uint FromString(const std::wstring & s, uint b = 10) - { - return FromString( s.c_str(), b ); - } - - - /*! - this operator converts a string into its value (with base = 10) - */ - Int & operator=(const wchar_t * s) - { - FromString(s); - - return *this; - } - - - /*! - this operator converts a string into its value (with base = 10) - */ - Int & operator=(const std::wstring & s) - { - FromString( s.c_str() ); - - return *this; - } - -#endif - - - /*! - this operator converts a string into its value (with base = 10) - */ - Int & operator=(const std::string & s) - { - FromString( s.c_str() ); - - return *this; - } - - - - /*! - * - * methods for comparing - * - * - */ - - bool operator==(const Int & l) const - { - return UInt::operator==(l); - } - - bool operator!=(const Int & l) const - { - return UInt::operator!=(l); - } - - bool operator<(const Int & l) const - { - sint i=value_size-1; - - sint a1 = sint(UInt::table[i]); - sint a2 = sint(l.table[i]); - - if( a1 != a2 ) - return a1 < a2; - - - for(--i ; i>=0 ; --i) - { - if( UInt::table[i] != l.table[i] ) - // comparison as unsigned int - return UInt::table[i] < l.table[i]; - } - - // they're equal - return false; - } - - - bool operator>(const Int & l) const - { - sint i=value_size-1; - - sint a1 = sint(UInt::table[i]); - sint a2 = sint(l.table[i]); - - if( a1 != a2 ) - return a1 > a2; - - - for(--i ; i>=0 ; --i) - { - if( UInt::table[i] != l.table[i] ) - // comparison as unsigned int - return UInt::table[i] > l.table[i]; - } - - // they're equal - return false; - } - - - bool operator<=(const Int & l) const - { - sint i=value_size-1; - - sint a1 = sint(UInt::table[i]); - sint a2 = sint(l.table[i]); - - if( a1 != a2 ) - return a1 < a2; - - - for(--i ; i>=0 ; --i) - { - if( UInt::table[i] != l.table[i] ) - // comparison as unsigned int - return UInt::table[i] < l.table[i]; - } - - // they're equal - return true; - } - - - bool operator>=(const Int & l) const - { - sint i=value_size-1; - - sint a1 = sint(UInt::table[i]); - sint a2 = sint(l.table[i]); - - if( a1 != a2 ) - return a1 > a2; - - - for(--i ; i>=0 ; --i) - { - if( UInt::table[i] != l.table[i] ) - // comparison as unsigned int - return UInt::table[i] > l.table[i]; - } - - // they're equal - return true; - } - - - - /*! - * - * standard mathematical operators - * - */ - - - /*! - an operator for changing the sign - - it's not changing 'this' but the changed value will be returned - */ - Int operator-() const - { - Int temp(*this); - - temp.ChangeSign(); - - return temp; - } - - - Int operator-(const Int & p2) const - { - Int temp(*this); - - temp.Sub(p2); - - return temp; - } - - - Int & operator-=(const Int & p2) - { - Sub(p2); - - return *this; - } - - - Int operator+(const Int & p2) const - { - Int temp(*this); - - temp.Add(p2); - - return temp; - } - - - Int & operator+=(const Int & p2) - { - Add(p2); - - return *this; - } - - - Int operator*(const Int & p2) const - { - Int temp(*this); - - temp.Mul(p2); - - return temp; - } - - - Int & operator*=(const Int & p2) - { - Mul(p2); - - return *this; - } - - - Int operator/(const Int & p2) const - { - Int temp(*this); - - temp.Div(p2); - - return temp; - } - - - Int & operator/=(const Int & p2) - { - Div(p2); - - return *this; - } - - - Int operator%(const Int & p2) const - { - Int temp(*this); - Int remainder; - - temp.Div(p2, remainder); - - return remainder; - } - - - Int & operator%=(const Int & p2) - { - Int remainder; - - Div(p2, remainder); - operator=(remainder); - - return *this; - } - - - /*! - Prefix operator e.g. ++variable - */ - UInt & operator++() - { - AddOne(); - - return *this; - } - - - /*! - Postfix operator e.g. variable++ - */ - UInt operator++(int) - { - UInt temp( *this ); - - AddOne(); - - return temp; - } - - - UInt & operator--() - { - SubOne(); - - return *this; - } - - - UInt operator--(int) - { - UInt temp( *this ); - - SubOne(); - - return temp; - } - - - - /*! - * - * input/output operators for standard streams - * - */ - -private: - - /*! - an auxiliary method for outputing to standard streams - */ - template - static ostream_type & OutputToStream(ostream_type & s, const Int & l) - { - string_type ss; - - l.ToString(ss); - s << ss; - - return s; - } - - - -public: - - - /*! - output to standard streams - */ - friend std::ostream & operator<<(std::ostream & s, const Int & l) - { - return OutputToStream(s, l); - } - - -#ifndef TTMATH_DONT_USE_WCHAR - - /*! - output to standard streams - */ - friend std::wostream & operator<<(std::wostream & s, const Int & l) - { - return OutputToStream(s, l); - } - -#endif - - - -private: - - /*! - an auxiliary method for converting from a string - */ - template - static istream_type & InputFromStream(istream_type & s, Int & l) - { - string_type ss; - - // char or wchar_t for operator>> - char_type z; - - // operator>> omits white characters if they're set for ommiting - s >> z; - - if( z=='-' || z=='+' ) - { - ss += z; - s >> z; // we're reading a next character (white characters can be ommited) - } - - // we're reading only digits (base=10) - while( s.good() && Misc::CharToDigit(z, 10)>=0 ) - { - ss += z; - z = static_cast(s.get()); - } - - // we're leaving the last readed character - // (it's not belonging to the value) - s.unget(); - - l.FromString(ss); - - return s; - } - - -public: - - /*! - input from standard streams - */ - friend std::istream & operator>>(std::istream & s, Int & l) - { - return InputFromStream(s, l); - } - - -#ifndef TTMATH_DONT_USE_WCHAR - - /*! - input from standard streams - */ - friend std::wistream & operator>>(std::wistream & s, Int & l) - { - return InputFromStream(s, l); - } -#endif - - -}; - -} // namespace - -#endif diff --git a/include/geos/algorithm/ttmath/ttmathmisc.h b/include/geos/algorithm/ttmath/ttmathmisc.h deleted file mode 100644 index c9e1560637..0000000000 --- a/include/geos/algorithm/ttmath/ttmathmisc.h +++ /dev/null @@ -1,250 +0,0 @@ -/* - * This file is a part of TTMath Bignum Library - * and is distributed under the 3-Clause BSD Licence. - * Author: Tomasz Sowa - */ - -/* - * Copyright (c) 2006-2010, Tomasz Sowa - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * * Neither the name Tomasz Sowa nor the names of contributors to this - * project may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef headerfilettmathmisc -#define headerfilettmathmisc - - -/*! - \file ttmathmisc.h - \brief some helpful functions -*/ - - -#include - - -namespace ttmath -{ - -/*! - some helpful functions -*/ -class Misc -{ -public: - - -/* - * - * AssignString(result, str) - * result = str - * - */ - -/*! - result = str -*/ -static void AssignString(std::string & result, const char * str) -{ - result = str; -} - - -#ifndef TTMATH_DONT_USE_WCHAR - -/*! - result = str -*/ -static void AssignString(std::wstring & result, const char * str) -{ - result.clear(); - - for( ; *str ; ++str ) - result += *str; -} - - -/*! - result = str -*/ -static void AssignString(std::wstring & result, const std::string & str) -{ - return AssignString(result, str.c_str()); -} - - -/*! - result = str -*/ -static void AssignString(std::string & result, const wchar_t * str) -{ - result.clear(); - - for( ; *str ; ++str ) - result += static_cast(*str); -} - - -/*! - result = str -*/ -static void AssignString(std::string & result, const std::wstring & str) -{ - return AssignString(result, str.c_str()); -} - -#endif - - -/* - * - * AddString(result, str) - * result += str - * - */ - - -/*! - result += str -*/ -static void AddString(std::string & result, const char * str) -{ - result += str; -} - - -#ifndef TTMATH_DONT_USE_WCHAR - -/*! - result += str -*/ -static void AddString(std::wstring & result, const char * str) -{ - for( ; *str ; ++str ) - result += *str; -} - -#endif - - -/* - this method omits any white characters from the string - char_type is char or wchar_t -*/ -template -static void SkipWhiteCharacters(const char_type * & c) -{ - // 13 is at the end in a DOS text file (\r\n) - while( (*c==' ' ) || (*c=='\t') || (*c==13 ) || (*c=='\n') ) - ++c; -} - - - - -/*! - this static method converts one character into its value - - for example: - - 1 -> 1 - - 8 -> 8 - - A -> 10 - - f -> 15 - - this method don't check whether c is correct or not -*/ -static uint CharToDigit(uint c) -{ - if(c>='0' && c<='9') - return c-'0'; - - if(c>='a' && c<='z') - return c-'a'+10; - -return c-'A'+10; -} - - -/*! - this method changes a character 'c' into its value - (if there can't be a correct value it returns -1) - - for example: - - c=2, base=10 -> function returns 2 - - c=A, base=10 -> function returns -1 - - c=A, base=16 -> function returns 10 -*/ -static sint CharToDigit(uint c, uint base) -{ - if( c>='0' && c<='9' ) - c=c-'0'; - else - if( c>='a' && c<='z' ) - c=c-'a'+10; - else - if( c>='A' && c<='Z' ) - c=c-'A'+10; - else - return -1; - - - if( c >= base ) - return -1; - - -return sint(c); -} - - - -/*! - this method converts a digit into a char - digit should be from <0,F> - (we don't have to get a base) - - for example: - - 1 -> 1 - - 8 -> 8 - - 10 -> A - - 15 -> F -*/ -static uint DigitToChar(uint digit) -{ - if( digit < 10 ) - return digit + '0'; - -return digit - 10 + 'A'; -} - - -}; // struct Misc - -} - - -#endif diff --git a/include/geos/algorithm/ttmath/ttmathobjects.h b/include/geos/algorithm/ttmath/ttmathobjects.h deleted file mode 100644 index 2902c9a19a..0000000000 --- a/include/geos/algorithm/ttmath/ttmathobjects.h +++ /dev/null @@ -1,812 +0,0 @@ -/* - * This file is a part of TTMath Mathematical Library - * and is distributed under the 3-Clause BSD Licence. - * Author: Tomasz Sowa - */ - -/* - * Copyright (c) 2006-2017, Tomasz Sowa - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * * Neither the name Tomasz Sowa nor the names of contributors to this - * project may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - - -#ifndef headerfilettmathobject -#define headerfilettmathobject - -/*! - \file ttmathobjects.h - \brief Mathematic functions. -*/ - -#include -#include -#include -#include - -#include "ttmathtypes.h" -#include "ttmathmisc.h" - - -namespace ttmath -{ - -/*! - objects of this class are used with the mathematical parser - they hold variables or functions defined by a user - - each object has its own table in which we're keeping variables or functions -*/ -class Objects -{ -public: - - - /*! - one item (variable or function) - 'items' will be on the table - */ - struct Item - { - // name of a variable of a function - // internally we store variables and funcions as std::string (not std::wstring even when wide characters are used) - std::string value; - - // number of parameters required by the function - // (if there's a variable this 'param' is ignored) - int param; - - Item() { param = 0; } - Item(const std::string & v, int p) : value(v), param(p) {} - }; - - // 'Table' is the type of our table - typedef std::map Table; - typedef Table::iterator Iterator; - typedef Table::const_iterator CIterator; - - - - /*! - this method returns true if a character 'c' is a character - which can be in a name - - if 'can_be_digit' is true that means when the 'c' is a digit this - method returns true otherwise it returns false - */ - static bool CorrectCharacter(int c, bool can_be_digit) - { - if( (c>='a' && c<='z') || (c>='A' && c<='Z') ) - return true; - - if( can_be_digit && ((c>='0' && c<='9') || c=='_') ) - return true; - - return false; - } - - - /*! - this method returns true if the name can be as a name of an object - */ - template - static bool IsNameCorrect(const string_type & name) - { - if( name.empty() ) - return false; - - if( !CorrectCharacter(name[0], false) ) - return false; - - typename string_type::const_iterator i = name.begin(); - - for(++i ; i!=name.end() ; ++i) - if( !CorrectCharacter(*i, true) ) - return false; - - return true; - } - - - /*! - this method returns true if such an object is defined (name exists) - */ - bool IsDefined(const std::string & name) - { - Iterator i = table.find(name); - - if( i != table.end() ) - // we have this object in our table - return true; - - return false; - } - - - -#ifndef TTMATH_DONT_USE_WCHAR - - /*! - this method returns true if such an object is defined (name exists) - */ - bool IsDefined(const std::wstring & name) - { - // we should check whether the name (in wide characters) are correct - // before calling AssignString() function - if( !IsNameCorrect(name) ) - return false; - - Misc::AssignString(str_tmp1, name); - - return IsDefined(str_tmp1); - } - -#endif - - - /*! - this method adds one object (variable of function) into the table - */ - ErrorCode Add(const std::string & name, const std::string & value, int param = 0) - { - if( !IsNameCorrect(name) ) - return err_incorrect_name; - - Iterator i = table.find(name); - - if( i != table.end() ) - // we have this object in our table - return err_object_exists; - - table.insert( std::make_pair(name, Item(value, param)) ); - - return err_ok; - } - - -#ifndef TTMATH_DONT_USE_WCHAR - - /*! - this method adds one object (variable of function) into the table - */ - ErrorCode Add(const std::wstring & name, const std::wstring & value, int param = 0) - { - // we should check whether the name (in wide characters) are correct - // before calling AssignString() function - if( !IsNameCorrect(name) ) - return err_incorrect_name; - - Misc::AssignString(str_tmp1, name); - Misc::AssignString(str_tmp2, value); - - return Add(str_tmp1, str_tmp2, param); - } - -#endif - - - /*! - this method returns 'true' if the table is empty - */ - bool Empty() const - { - return table.empty(); - } - - - /*! - this method clears the table - */ - void Clear() - { - return table.clear(); - } - - - /*! - this method returns 'const_iterator' on the first item on the table - */ - CIterator Begin() const - { - return table.begin(); - } - - - /*! - this method returns 'const_iterator' pointing at the space after last item - (returns table.end()) - */ - CIterator End() const - { - return table.end(); - } - - - /*! - this method changes the value and the number of parameters for a specific object - */ - ErrorCode EditValue(const std::string & name, const std::string & value, int param = 0) - { - if( !IsNameCorrect(name) ) - return err_incorrect_name; - - Iterator i = table.find(name); - - if( i == table.end() ) - return err_unknown_object; - - i->second.value = value; - i->second.param = param; - - return err_ok; - } - - -#ifndef TTMATH_DONT_USE_WCHAR - - - /*! - this method changes the value and the number of parameters for a specific object - */ - ErrorCode EditValue(const std::wstring & name, const std::wstring & value, int param = 0) - { - // we should check whether the name (in wide characters) are correct - // before calling AssignString() function - if( !IsNameCorrect(name) ) - return err_incorrect_name; - - Misc::AssignString(str_tmp1, name); - Misc::AssignString(str_tmp2, value); - - return EditValue(str_tmp1, str_tmp2, param); - } - -#endif - - - /*! - this method changes the name of a specific object - */ - ErrorCode EditName(const std::string & old_name, const std::string & new_name) - { - if( !IsNameCorrect(old_name) || !IsNameCorrect(new_name) ) - return err_incorrect_name; - - Iterator old_i = table.find(old_name); - if( old_i == table.end() ) - return err_unknown_object; - - if( old_name == new_name ) - // the new name is the same as the old one - // we treat it as a normal situation - return err_ok; - - ErrorCode err = Add(new_name, old_i->second.value, old_i->second.param); - - if( err == err_ok ) - { - old_i = table.find(old_name); - TTMATH_ASSERT( old_i != table.end() ) - - table.erase(old_i); - } - - return err; - } - - - -#ifndef TTMATH_DONT_USE_WCHAR - - - /*! - this method changes the name of a specific object - */ - ErrorCode EditName(const std::wstring & old_name, const std::wstring & new_name) - { - // we should check whether the name (in wide characters) are correct - // before calling AssignString() function - if( !IsNameCorrect(old_name) || !IsNameCorrect(new_name) ) - return err_incorrect_name; - - Misc::AssignString(str_tmp1, old_name); - Misc::AssignString(str_tmp2, new_name); - - return EditName(str_tmp1, str_tmp2); - } - -#endif - - - /*! - this method deletes an object - */ - ErrorCode Delete(const std::string & name) - { - if( !IsNameCorrect(name) ) - return err_incorrect_name; - - Iterator i = table.find(name); - - if( i == table.end() ) - return err_unknown_object; - - table.erase( i ); - - return err_ok; - } - - -#ifndef TTMATH_DONT_USE_WCHAR - - - /*! - this method deletes an object - */ - ErrorCode Delete(const std::wstring & name) - { - // we should check whether the name (in wide characters) are correct - // before calling AssignString() function - if( !IsNameCorrect(name) ) - return err_incorrect_name; - - Misc::AssignString(str_tmp1, name); - - return Delete(str_tmp1); - } - -#endif - - - /*! - this method gets the value of a specific object - */ - ErrorCode GetValue(const std::string & name, std::string & value) const - { - if( !IsNameCorrect(name) ) - return err_incorrect_name; - - CIterator i = table.find(name); - - if( i == table.end() ) - { - value.clear(); - return err_unknown_object; - } - - value = i->second.value; - - return err_ok; - } - - -#ifndef TTMATH_DONT_USE_WCHAR - - /*! - this method gets the value of a specific object - */ - ErrorCode GetValue(const std::wstring & name, std::wstring & value) - { - // we should check whether the name (in wide characters) are correct - // before calling AssignString() function - if( !IsNameCorrect(name) ) - return err_incorrect_name; - - Misc::AssignString(str_tmp1, name); - ErrorCode err = GetValue(str_tmp1, str_tmp2); - Misc::AssignString(value, str_tmp2); - - return err; - } - -#endif - - - /*! - this method gets the value of a specific object - (this version is used for not copying the whole string) - */ - ErrorCode GetValue(const std::string & name, const char ** value) const - { - if( !IsNameCorrect(name) ) - return err_incorrect_name; - - CIterator i = table.find(name); - - if( i == table.end() ) - { - *value = 0; - return err_unknown_object; - } - - *value = i->second.value.c_str(); - - return err_ok; - } - - -#ifndef TTMATH_DONT_USE_WCHAR - - /*! - this method gets the value of a specific object - (this version is used for not copying the whole string) - */ - ErrorCode GetValue(const std::wstring & name, const char ** value) - { - // we should check whether the name (in wide characters) are correct - // before calling AssignString() function - if( !IsNameCorrect(name) ) - return err_incorrect_name; - - Misc::AssignString(str_tmp1, name); - - return GetValue(str_tmp1, value); - } - -#endif - - - /*! - this method gets the value and the number of parameters - of a specific object - */ - ErrorCode GetValueAndParam(const std::string & name, std::string & value, int * param) const - { - if( !IsNameCorrect(name) ) - return err_incorrect_name; - - CIterator i = table.find(name); - - if( i == table.end() ) - { - value.clear(); - *param = 0; - return err_unknown_object; - } - - value = i->second.value; - *param = i->second.param; - - return err_ok; - } - - -#ifndef TTMATH_DONT_USE_WCHAR - - /*! - this method gets the value and the number of parameters - of a specific object - */ - ErrorCode GetValueAndParam(const std::wstring & name, std::wstring & value, int * param) - { - // we should check whether the name (in wide characters) are correct - // before calling AssignString() function - if( !IsNameCorrect(name) ) - return err_incorrect_name; - - Misc::AssignString(str_tmp1, name); - ErrorCode err = GetValueAndParam(str_tmp1, str_tmp2, param); - Misc::AssignString(value, str_tmp2); - - return err; - } - -#endif - - - /*! - this method sets the value and the number of parameters - of a specific object - (this version is used for not copying the whole string) - */ - ErrorCode GetValueAndParam(const std::string & name, const char ** value, int * param) const - { - if( !IsNameCorrect(name) ) - return err_incorrect_name; - - CIterator i = table.find(name); - - if( i == table.end() ) - { - *value = 0; - *param = 0; - return err_unknown_object; - } - - *value = i->second.value.c_str(); - *param = i->second.param; - - return err_ok; - } - - -#ifndef TTMATH_DONT_USE_WCHAR - - - /*! - this method sets the value and the number of parameters - of a specific object - (this version is used for not copying the whole string - but in fact we make one copying during AssignString()) - */ - ErrorCode GetValueAndParam(const std::wstring & name, const char ** value, int * param) - { - // we should check whether the name (in wide characters) are correct - // before calling AssignString() function - if( !IsNameCorrect(name) ) - return err_incorrect_name; - - Misc::AssignString(str_tmp1, name); - - return GetValueAndParam(str_tmp1, value, param); - } - - -#endif - - - /*! - this method returns a pointer into the table - */ - Table * GetTable() - { - return &table; - } - - -private: - - Table table; - std::string str_tmp1, str_tmp2; - -}; // end of class Objects - - - - - - - -/*! - objects of the class History are used to keep values in functions - which take a lot of time during calculating, for instance in the - function Factorial(x) - - it means that when we're calculating e.g. Factorial(1000) and the - Factorial finds that we have calculated it before, the value (result) - is taken from the history -*/ -template -class History -{ - /*! - one item in the History's object holds a key, a value for the key - and a corresponding error code - */ - struct Item - { - ValueType key, value; - ErrorCode err; - }; - - - /*! - we use std::list for simply deleting the first item - but because we're searching through the whole container - (in the method Get) the container should not be too big - (linear time of searching) - */ - typedef std::list buffer_type; - buffer_type buffer; - typename buffer_type::size_type buffer_max_size; - -public: - - /*! - default constructor - default max size of the History's container is 15 items - */ - History() - { - buffer_max_size = 15; - } - - - /*! - a constructor which takes another value of the max size - of the History's container - */ - History(typename buffer_type::size_type new_size) - { - buffer_max_size = new_size; - } - - - /*! - this method adds one item into the History - if the size of the container is greater than buffer_max_size - the first item will be removed - */ - void Add(const ValueType & key, const ValueType & value, ErrorCode err) - { - Item item; - item.key = key; - item.value = value; - item.err = err; - - buffer.insert( buffer.end(), item ); - - if( buffer.size() > buffer_max_size ) - buffer.erase(buffer.begin()); - } - - - /*! - this method checks whether we have an item which has the key equal 'key' - - if there's such item the method sets the 'value' and the 'err' - and returns true otherwise it returns false and 'value' and 'err' - remain unchanged - */ - bool Get(const ValueType & key, ValueType & value, ErrorCode & err) - { - typename buffer_type::iterator i = buffer.begin(); - - for( ; i != buffer.end() ; ++i ) - { - if( i->key == key ) - { - value = i->value; - err = i->err; - return true; - } - } - - return false; - } - - - /*! - this methods deletes an item - - we assume that there is only one item with the 'key' - (this methods removes the first one) - */ - bool Remove(const ValueType & key) - { - typename buffer_type::iterator i = buffer.begin(); - - for( ; i != buffer.end() ; ++i ) - { - if( i->key == key ) - { - buffer.erase(i); - return true; - } - } - - return false; - } - - -}; // end of class History - - - -/*! - this is an auxiliary class used when calculating Gamma() or Factorial() - - in multithreaded environment you can provide an object of this class to - the Gamma() or Factorial() function, e.g; - - typedef Big<1, 3> MyBig; - MyBig x = 123456; - CGamma cgamma; - std::cout << Gamma(x, cgamma); - - each thread should have its own CGamma<> object - - in a single-thread environment a CGamma<> object is a static variable - and you don't have to explicitly use it, e.g. - - typedef Big<1, 3> MyBig; - MyBig x = 123456; - std::cout << Gamma(x); -*/ -template -struct CGamma -{ - /*! - this table holds factorials - 1 - 1 - 2 - 6 - 24 - 120 - 720 - ....... - */ - std::vector fact; - - - /*! - this table holds Bernoulli numbers - 1 - -0.5 - 0.166666666666666666666666667 - 0 - -0.0333333333333333333333333333 - 0 - 0.0238095238095238095238095238 - 0 - -0.0333333333333333333333333333 - 0 - 0.075757575757575757575757576 - ..... - */ - std::vector bern; - - - /*! - here we store some calculated values - (this is for speeding up, if the next argument of Gamma() or Factorial() - is in the 'history' then the result we are not calculating but simply - return from the 'history' object) - */ - History history; - - - /*! - this method prepares some coefficients: factorials and Bernoulli numbers - stored in 'fact' and 'bern' objects - - how many values should be depends on the size of the mantissa - if - the mantissa is larger then we must calculate more values - for a mantissa which consists of 256 bits (8 words on a 32bit platform) - we have to calculate about 30 values (the size of fact and bern will be 30), - and for a 2048 bits mantissa we have to calculate 306 coefficients - - you don't have to call this method, these coefficients will be automatically calculated - when they are needed - - you must note that calculating these coefficients is a little time-consuming operation, - (especially when the mantissa is large) and first call to Gamma() or Factorial() - can take more time than next calls, and in the end this is the point when InitAll() - comes in handy: you can call this method somewhere at the beginning of your program - */ - void InitAll(); - // definition is in ttmath.h -}; - - - - -} // namespace - -#endif diff --git a/include/geos/algorithm/ttmath/ttmathparser.h b/include/geos/algorithm/ttmath/ttmathparser.h deleted file mode 100644 index d9b7ce7570..0000000000 --- a/include/geos/algorithm/ttmath/ttmathparser.h +++ /dev/null @@ -1,2777 +0,0 @@ -/* - * This file is a part of TTMath Bignum Library - * and is distributed under the 3-Clause BSD Licence. - * Author: Tomasz Sowa - */ - -/* - * Copyright (c) 2006-2017, Tomasz Sowa - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * * Neither the name Tomasz Sowa nor the names of contributors to this - * project may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#ifndef headerfilettmathparser -#define headerfilettmathparser - -/*! - \file ttmathparser.h - \brief A mathematical parser -*/ - -#include -#include -#include -#include - -#include "ttmath.h" -#include "ttmathobjects.h" -#include "ttmathmisc.h" - - - -namespace ttmath -{ - -/*! - \brief Mathematical parser - - let x will be an input string meaning an expression for converting: - - x = [+|-]Value[operator[+|-]Value][operator[+|-]Value]... - where: - an operator can be: - ^ (pow) (the heighest priority) - - * (mul) (or multiplication without an operator -- short mul) - / (div) (* and / have the same priority) - - + (add) - - (sub) (+ and - have the same priority) - - < (lower than) - > (greater than) - <= (lower or equal than) - >= (greater or equal than) - == (equal) - != (not equal) (all above logical operators have the same priority) - - && (logical and) - - || (logical or) (the lowest priority) - - short mul: - if the second Value (Var below) is either a variable or function there might not be - an operator between them, e.g. - "[+|-]Value Var" is treated as "[+|-]Value * Var" and the multiplication - has the same priority as a normal multiplication: - 4x = 4 * x - 2^3m = (2^3)* m - 6h^3 = 6 * (h^3) - 2sin(pi) = 2 * sin(pi) - etc. - - Value can be: - constant e.g. 100, can be preceded by operators for changing the base (radix): [#|&] - # - hex - & - bin - sample: #10 = 16 - &10 = 2 - variable e.g. pi - another expression between brackets e.g (x) - function e.g. sin(x) - - for example a correct input string can be: - "1" - "2.1234" - "2,1234" (they are the same, by default we can either use a comma or a dot) - "1 + 2" - "(1 + 2) * 3" - "pi" - "sin(pi)" - "(1+2)*(2+3)" - "log(2;1234)" there's a semicolon here (not a comma), we use it in functions - for separating parameters - "1 < 2" (the result will be: 1) - "4 < 3" (the result will be: 0) - "2+x" (of course if the variable 'x' is defined) - "4x+10" - "#20+10" = 32 + 10 = 42 - "10 ^ -&101" = 10 ^ -5 = 0.00001 - "8 * -&10" = 8 * -2 = -16 - etc. - - we can also use a semicolon for separating any 'x' input strings - for example: - "1+2;4+5" - the result will be on the stack as follows: - stack[0].value=3 - stack[1].value=9 -*/ -template -class Parser -{ -private: - -/*! - there are 5 mathematical operators as follows (with their standard priorities): - add (+) - sub (-) - mul (*) - div (/) - pow (^) - and 'shortmul' used when there is no any operators between - a first parameter and a variable or function - (the 'shortmul' has the same priority as the normal multiplication ) -*/ - class MatOperator - { - public: - - enum Type - { - none,add,sub,mul,div,pow,lt,gt,let,get,eq,neq,lor,land,shortmul - }; - - enum Assoc - { - right, // right-associative - non_right // associative or left-associative - }; - - Type GetType() const { return type; } - int GetPriority() const { return priority; } - Assoc GetAssoc() const { return assoc; } - - void SetType(Type t) - { - type = t; - assoc = non_right; - - switch( type ) - { - case lor: - priority = 4; - break; - - case land: - priority = 5; - break; - - case eq: - case neq: - case lt: - case gt: - case let: - case get: - priority = 7; - break; - - case add: - case sub: - priority = 10; - break; - - case mul: - case shortmul: - case div: - priority = 12; - break; - - case pow: - priority = 14; - assoc = right; - break; - - default: - Error( err_internal_error ); - break; - } - } - - MatOperator(): type(none), priority(0), assoc(non_right) - { - } - - private: - - Type type; - int priority; - Assoc assoc; - }; // end of MatOperator class - - - -public: - - - - /*! - Objects of type 'Item' we are keeping on our stack - */ - struct Item - { - enum Type - { - none, numerical_value, mat_operator, first_bracket, - last_bracket, variable, semicolon - }; - - // The kind of type which we're keeping - Type type; - - // if type == numerical_value - ValueType value; - - // if type == mat_operator - MatOperator moperator; - - /* - if type == first_bracket - - if 'function' is set to true it means that the first recognized bracket - was the bracket from function in other words we must call a function when - we'll find the 'last' bracket - */ - bool function; - - // if function is true - std::string function_name; - - /* - the sign of value - - it can be for type==numerical_value or type==first_bracket - when it's true it means e.g. that value is equal -value - */ - bool sign; - - Item(): type(none), function(false), sign(false) - { - } - - }; // end of Item struct - - -/*! - stack on which we're keeping the Items - - at the end of parsing we'll have the result here - the result don't have to be one value, it can be - more than one if we have used a semicolon in the global space - e.g. such input string "1+2;3+4" will generate a result: - stack[0].value=3 - stack[1].value=7 - - you should check if the stack is not empty, because if there was - a syntax error in the input string then we do not have any results - on the stack -*/ -std::vector stack; - - -private: - - -/*! - size of the stack when we're starting parsing of the string - - if it's to small while parsing the stack will be automatically resized -*/ -const int default_stack_size; - - - -/*! - index of an object in our stack - it's pointing on the place behind the last element - for example at the beginning of parsing its value is zero -*/ -unsigned int stack_index; - - -/*! - code of the last error -*/ -ErrorCode error; - - -/*! - pointer to the currently reading char - when an error has occured it may be used to count the index of the wrong character -*/ -const char * pstring; - - -/*! - the base (radix) of the mathematic system (for example it may be '10') -*/ -int base; - - -/*! - the unit of angles used in: sin,cos,tan,cot,asin,acos,atan,acot - 0 - deg - 1 - rad (default) - 2 - grad -*/ -int deg_rad_grad; - - - -/*! - a pointer to an object which tell us whether we should stop calculating or not -*/ -const volatile StopCalculating * pstop_calculating; - - - -/*! - a pointer to the user-defined variables' table -*/ -const Objects * puser_variables; - -/*! - a pointer to the user-defined functions' table -*/ -const Objects * puser_functions; - - -typedef std::map FunctionLocalVariables; - -/*! - a pointer to the local variables of a function -*/ -const FunctionLocalVariables * pfunction_local_variables; - - -/*! - a temporary set using during parsing user defined variables -*/ -std::set visited_variables; - - -/*! - a temporary set using during parsing user defined functions -*/ -std::set visited_functions; - - - - -/*! - pfunction is the type of pointer to a mathematic function - - these mathematic functions are private members of this class, - they are the wrappers for standard mathematics function - - 'pstack' is the pointer to the first argument on our stack - 'amount_of_arg' tell us how many argument there are in our stack - 'result' is the reference for result of function -*/ -typedef void (Parser::*pfunction)(int pstack, int amount_of_arg, ValueType & result); - - -/*! - pfunction is the type of pointer to a method which returns value of variable -*/ -typedef void (ValueType::*pfunction_var)(); - - -/*! - table of mathematic functions - - this map consists of: - std::string - function's name - pfunction - pointer to specific function -*/ -typedef std::map FunctionsTable; -FunctionsTable functions_table; - - -/*! - table of mathematic operators - - this map consists of: - std::string - operators's name - MatOperator::Type - type of the operator -*/ -typedef std::map OperatorsTable; -OperatorsTable operators_table; - - -/*! - table of mathematic variables - - this map consists of: - std::string - variable's name - pfunction_var - pointer to specific function which returns value of variable -*/ -typedef std::map VariablesTable; -VariablesTable variables_table; - - -/*! - some coefficients used when calculating the gamma (or factorial) function -*/ -CGamma cgamma; - - -/*! - temporary object for a whole string when Parse(std::wstring) is used -*/ -std::string wide_to_ansi; - - -/*! - group character (used when parsing) - default zero (not used) -*/ -int group; - - -/*! - characters used as a comma - default: '.' and ',' - comma2 can be zero (it means it is not used) -*/ -int comma, comma2; - - -/*! - an additional character used as a separator between function parameters - (semicolon is used always) -*/ -int param_sep; - - -/*! - true if something was calculated (at least one mathematical operator was used or a function or a variable) -*/ -bool calculated; - - - -/*! - we're using this method for reporting an error -*/ -static void Error(ErrorCode code) -{ - throw code; -} - - -/*! - this method skips the white character from the string - - it's moving the 'pstring' to the first no-white character -*/ -void SkipWhiteCharacters() -{ - while( (*pstring==' ' ) || (*pstring=='\t') ) - ++pstring; -} - - -/*! - an auxiliary method for RecurrenceParsingVariablesOrFunction(...) -*/ -void RecurrenceParsingVariablesOrFunction_CheckStopCondition(bool variable, const std::string & name) -{ - if( variable ) - { - if( visited_variables.find(name) != visited_variables.end() ) - Error( err_variable_loop ); - } - else - { - if( visited_functions.find(name) != visited_functions.end() ) - Error( err_functions_loop ); - } -} - - -/*! - an auxiliary method for RecurrenceParsingVariablesOrFunction(...) -*/ -void RecurrenceParsingVariablesOrFunction_AddName(bool variable, const std::string & name) -{ - if( variable ) - visited_variables.insert( name ); - else - visited_functions.insert( name ); -} - - -/*! - an auxiliary method for RecurrenceParsingVariablesOrFunction(...) -*/ -void RecurrenceParsingVariablesOrFunction_DeleteName(bool variable, const std::string & name) -{ - if( variable ) - visited_variables.erase( name ); - else - visited_functions.erase( name ); -} - - -/*! - this method returns the value of a variable or function - by creating a new instance of the mathematical parser - and making the standard parsing algorithm on the given string - - this method is used only during parsing user defined variables or functions - - (there can be a recurrence here therefore we're using 'visited_variables' - and 'visited_functions' sets to make a stop condition) -*/ -ValueType RecurrenceParsingVariablesOrFunction(bool variable, const std::string & name, const char * new_string, - FunctionLocalVariables * local_variables = 0) -{ - RecurrenceParsingVariablesOrFunction_CheckStopCondition(variable, name); - RecurrenceParsingVariablesOrFunction_AddName(variable, name); - - Parser NewParser(*this); - ErrorCode err; - - NewParser.pfunction_local_variables = local_variables; - - try - { - err = NewParser.Parse(new_string); - } - catch(...) - { - RecurrenceParsingVariablesOrFunction_DeleteName(variable, name); - - throw; - } - - RecurrenceParsingVariablesOrFunction_DeleteName(variable, name); - - if( err != err_ok ) - Error( err ); - - if( NewParser.stack.size() != 1 ) - Error( err_must_be_only_one_value ); - - if( NewParser.stack[0].type != Item::numerical_value ) - // I think there shouldn't be this error here - Error( err_incorrect_value ); - -return NewParser.stack[0].value; -} - - -public: - - -/*! - this method returns the user-defined value of a variable -*/ -bool GetValueOfUserDefinedVariable(const std::string & variable_name,ValueType & result) -{ - if( !puser_variables ) - return false; - - const char * string_value; - - if( puser_variables->GetValue(variable_name, &string_value) != err_ok ) - return false; - - result = RecurrenceParsingVariablesOrFunction(true, variable_name, string_value); - calculated = true; - -return true; -} - - -/*! - this method returns the value of a local variable of a function -*/ -bool GetValueOfFunctionLocalVariable(const std::string & variable_name, ValueType & result) -{ - if( !pfunction_local_variables ) - return false; - - typename FunctionLocalVariables::const_iterator i = pfunction_local_variables->find(variable_name); - - if( i == pfunction_local_variables->end() ) - return false; - - result = i->second; - -return true; -} - - -/*! - this method returns the value of a variable from variables' table - - we make an object of type ValueType then call a method which - sets the correct value in it and finally we'll return the object -*/ -ValueType GetValueOfVariable(const std::string & variable_name) -{ -ValueType result; - - if( GetValueOfFunctionLocalVariable(variable_name, result) ) - return result; - - if( GetValueOfUserDefinedVariable(variable_name, result) ) - return result; - - - typename std::map::iterator i = - variables_table.find(variable_name); - - if( i == variables_table.end() ) - Error( err_unknown_variable ); - - (result.*(i->second))(); - calculated = true; - -return result; -} - - -private: - -/*! - wrappers for mathematic functions - - 'sindex' is pointing on the first argument on our stack - (the second argument has 'sindex+2' - because 'sindex+1' is guaranted for the 'semicolon' operator) - the third artument has of course 'sindex+4' etc. - - 'result' will be the result of the function - - (we're using exceptions here for example when function gets an improper argument) -*/ - - -/*! - used by: sin,cos,tan,cot -*/ -ValueType ConvertAngleToRad(const ValueType & input) -{ - if( deg_rad_grad == 1 ) // rad - return input; - - ValueType result; - ErrorCode err; - - if( deg_rad_grad == 0 ) // deg - result = ttmath::DegToRad(input, &err); - else // grad - result = ttmath::GradToRad(input, &err); - - if( err != err_ok ) - Error( err ); - -return result; -} - - -/*! - used by: asin,acos,atan,acot -*/ -ValueType ConvertRadToAngle(const ValueType & input) -{ - if( deg_rad_grad == 1 ) // rad - return input; - - ValueType result; - ErrorCode err; - - if( deg_rad_grad == 0 ) // deg - result = ttmath::RadToDeg(input, &err); - else // grad - result = ttmath::RadToGrad(input, &err); - - if( err != err_ok ) - Error( err ); - -return result; -} - - -void Gamma(int sindex, int amount_of_args, ValueType & result) -{ - if( amount_of_args != 1 ) - Error( err_improper_amount_of_arguments ); - - ErrorCode err; - - result = ttmath::Gamma(stack[sindex].value, cgamma, &err, pstop_calculating); - - if(err != err_ok) - Error( err ); -} - - -/*! - factorial - result = 1 * 2 * 3 * 4 * .... * x -*/ -void Factorial(int sindex, int amount_of_args, ValueType & result) -{ - if( amount_of_args != 1 ) - Error( err_improper_amount_of_arguments ); - - ErrorCode err; - - result = ttmath::Factorial(stack[sindex].value, cgamma, &err, pstop_calculating); - - if(err != err_ok) - Error( err ); -} - - -void Abs(int sindex, int amount_of_args, ValueType & result) -{ - if( amount_of_args != 1 ) - Error( err_improper_amount_of_arguments ); - - result = ttmath::Abs(stack[sindex].value); -} - -void Sin(int sindex, int amount_of_args, ValueType & result) -{ - if( amount_of_args != 1 ) - Error( err_improper_amount_of_arguments ); - - ErrorCode err; - result = ttmath::Sin( ConvertAngleToRad(stack[sindex].value), &err ); - - if(err != err_ok) - Error( err ); -} - -void Cos(int sindex, int amount_of_args, ValueType & result) -{ - if( amount_of_args != 1 ) - Error( err_improper_amount_of_arguments ); - - ErrorCode err; - result = ttmath::Cos( ConvertAngleToRad(stack[sindex].value), &err ); - - if(err != err_ok) - Error( err ); -} - -void Tan(int sindex, int amount_of_args, ValueType & result) -{ - if( amount_of_args != 1 ) - Error( err_improper_amount_of_arguments ); - - ErrorCode err; - result = ttmath::Tan(ConvertAngleToRad(stack[sindex].value), &err); - - if(err != err_ok) - Error( err ); -} - -void Cot(int sindex, int amount_of_args, ValueType & result) -{ - if( amount_of_args != 1 ) - Error( err_improper_amount_of_arguments ); - - ErrorCode err; - result = ttmath::Cot(ConvertAngleToRad(stack[sindex].value), &err); - - if(err != err_ok) - Error( err ); -} - -void Int(int sindex, int amount_of_args, ValueType & result) -{ - if( amount_of_args != 1 ) - Error( err_improper_amount_of_arguments ); - - result = ttmath::SkipFraction(stack[sindex].value); -} - - -void Round(int sindex, int amount_of_args, ValueType & result) -{ - if( amount_of_args != 1 ) - Error( err_improper_amount_of_arguments ); - - result = stack[sindex].value; - - if( result.Round() ) - Error( err_overflow ); -} - - -void Ln(int sindex, int amount_of_args, ValueType & result) -{ - if( amount_of_args != 1 ) - Error( err_improper_amount_of_arguments ); - - ErrorCode err; - result = ttmath::Ln(stack[sindex].value, &err); - - if(err != err_ok) - Error( err ); -} - -void Log(int sindex, int amount_of_args, ValueType & result) -{ - if( amount_of_args != 2 ) - Error( err_improper_amount_of_arguments ); - - ErrorCode err; - result = ttmath::Log(stack[sindex].value, stack[sindex+2].value, &err); - - if(err != err_ok) - Error( err ); -} - -void Exp(int sindex, int amount_of_args, ValueType & result) -{ - if( amount_of_args != 1 ) - Error( err_improper_amount_of_arguments ); - - ErrorCode err; - result = ttmath::Exp(stack[sindex].value, &err); - - if(err != err_ok) - Error( err ); -} - - -void Max(int sindex, int amount_of_args, ValueType & result) -{ - if( amount_of_args == 0 ) - { - result.SetMax(); - - return; - } - - result = stack[sindex].value; - - for(int i=1 ; i stack[sindex + i*2].value ) - result = stack[sindex + i*2].value; - } -} - - -void ASin(int sindex, int amount_of_args, ValueType & result) -{ - if( amount_of_args != 1 ) - Error( err_improper_amount_of_arguments ); - - ErrorCode err; - ValueType temp = ttmath::ASin(stack[sindex].value, &err); - - if(err != err_ok) - Error( err ); - - result = ConvertRadToAngle(temp); -} - - -void ACos(int sindex, int amount_of_args, ValueType & result) -{ - if( amount_of_args != 1 ) - Error( err_improper_amount_of_arguments ); - - ErrorCode err; - ValueType temp = ttmath::ACos(stack[sindex].value, &err); - - if(err != err_ok) - Error( err ); - - result = ConvertRadToAngle(temp); -} - - -void ATan(int sindex, int amount_of_args, ValueType & result) -{ - if( amount_of_args != 1 ) - Error( err_improper_amount_of_arguments ); - - result = ConvertRadToAngle(ttmath::ATan(stack[sindex].value)); -} - - -void ACot(int sindex, int amount_of_args, ValueType & result) -{ - if( amount_of_args != 1 ) - Error( err_improper_amount_of_arguments ); - - result = ConvertRadToAngle(ttmath::ACot(stack[sindex].value)); -} - - -void Sgn(int sindex, int amount_of_args, ValueType & result) -{ - if( amount_of_args != 1 ) - Error( err_improper_amount_of_arguments ); - - result = ttmath::Sgn(stack[sindex].value); -} - - -void Mod(int sindex, int amount_of_args, ValueType & result) -{ - if( amount_of_args != 2 ) - Error( err_improper_amount_of_arguments ); - - if( stack[sindex+2].value.IsZero() ) - Error( err_improper_argument ); - - result = stack[sindex].value; - uint c = result.Mod(stack[sindex+2].value); - - if( c ) - Error( err_overflow ); -} - - -void If(int sindex, int amount_of_args, ValueType & result) -{ - if( amount_of_args != 3 ) - Error( err_improper_amount_of_arguments ); - - - if( !stack[sindex].value.IsZero() ) - result = stack[sindex+2].value; - else - result = stack[sindex+4].value; -} - - -void Or(int sindex, int amount_of_args, ValueType & result) -{ - if( amount_of_args < 2 ) - Error( err_improper_amount_of_arguments ); - - for(int i=0 ; iGetValueAndParam(function_name, &string_value, ¶m) != err_ok ) - return false; - - if( param != amount_of_args ) - Error( err_improper_amount_of_arguments ); - - - FunctionLocalVariables local_variables; - - if( amount_of_args > 0 ) - { - char buffer[30]; - - // x = x1 - buffer[0] = 'x'; - buffer[1] = 0; - local_variables.insert( std::make_pair(buffer, stack[sindex].value) ); - - for(int i=0 ; i*(i->second))(sindex, amount_of_args, stack[sindex-1].value); - calculated = true; -} - - - - - -/*! - inserting a function to the functions' table - - function_name - name of the function - pf - pointer to the function (to the wrapper) -*/ -void InsertFunctionToTable(const char * function_name, pfunction pf) -{ - std::string str; - Misc::AssignString(str, function_name); - - functions_table.insert( std::make_pair(str, pf) ); -} - - - -/*! - inserting a function to the variables' table - (this function returns value of variable) - - variable_name - name of the function - pf - pointer to the function -*/ -void InsertVariableToTable(const char * variable_name, pfunction_var pf) -{ - std::string str; - Misc::AssignString(str, variable_name); - - variables_table.insert( std::make_pair(str, pf) ); -} - - -/*! - this method creates the table of functions -*/ -void CreateFunctionsTable() -{ - InsertFunctionToTable("gamma", &Parser::Gamma); - InsertFunctionToTable("factorial", &Parser::Factorial); - InsertFunctionToTable("abs", &Parser::Abs); - InsertFunctionToTable("sin", &Parser::Sin); - InsertFunctionToTable("cos", &Parser::Cos); - InsertFunctionToTable("tan", &Parser::Tan); - InsertFunctionToTable("tg", &Parser::Tan); - InsertFunctionToTable("cot", &Parser::Cot); - InsertFunctionToTable("ctg", &Parser::Cot); - InsertFunctionToTable("int", &Parser::Int); - InsertFunctionToTable("round", &Parser::Round); - InsertFunctionToTable("ln", &Parser::Ln); - InsertFunctionToTable("log", &Parser::Log); - InsertFunctionToTable("exp", &Parser::Exp); - InsertFunctionToTable("max", &Parser::Max); - InsertFunctionToTable("min", &Parser::Min); - InsertFunctionToTable("asin", &Parser::ASin); - InsertFunctionToTable("acos", &Parser::ACos); - InsertFunctionToTable("atan", &Parser::ATan); - InsertFunctionToTable("atg", &Parser::ATan); - InsertFunctionToTable("acot", &Parser::ACot); - InsertFunctionToTable("actg", &Parser::ACot); - InsertFunctionToTable("sgn", &Parser::Sgn); - InsertFunctionToTable("mod", &Parser::Mod); - InsertFunctionToTable("if", &Parser::If); - InsertFunctionToTable("or", &Parser::Or); - InsertFunctionToTable("and", &Parser::And); - InsertFunctionToTable("not", &Parser::Not); - InsertFunctionToTable("degtorad", &Parser::DegToRad); - InsertFunctionToTable("radtodeg", &Parser::RadToDeg); - InsertFunctionToTable("degtodeg", &Parser::DegToDeg); - InsertFunctionToTable("gradtorad", &Parser::GradToRad); - InsertFunctionToTable("radtograd", &Parser::RadToGrad); - InsertFunctionToTable("degtograd", &Parser::DegToGrad); - InsertFunctionToTable("gradtodeg", &Parser::GradToDeg); - InsertFunctionToTable("ceil", &Parser::Ceil); - InsertFunctionToTable("floor", &Parser::Floor); - InsertFunctionToTable("sqrt", &Parser::Sqrt); - InsertFunctionToTable("sinh", &Parser::Sinh); - InsertFunctionToTable("cosh", &Parser::Cosh); - InsertFunctionToTable("tanh", &Parser::Tanh); - InsertFunctionToTable("tgh", &Parser::Tanh); - InsertFunctionToTable("coth", &Parser::Coth); - InsertFunctionToTable("ctgh", &Parser::Coth); - InsertFunctionToTable("root", &Parser::Root); - InsertFunctionToTable("asinh", &Parser::ASinh); - InsertFunctionToTable("acosh", &Parser::ACosh); - InsertFunctionToTable("atanh", &Parser::ATanh); - InsertFunctionToTable("atgh", &Parser::ATanh); - InsertFunctionToTable("acoth", &Parser::ACoth); - InsertFunctionToTable("actgh", &Parser::ACoth); - InsertFunctionToTable("bitand", &Parser::BitAnd); - InsertFunctionToTable("bitor", &Parser::BitOr); - InsertFunctionToTable("bitxor", &Parser::BitXor); - InsertFunctionToTable("band", &Parser::BitAnd); - InsertFunctionToTable("bor", &Parser::BitOr); - InsertFunctionToTable("bxor", &Parser::BitXor); - InsertFunctionToTable("sum", &Parser::Sum); - InsertFunctionToTable("avg", &Parser::Avg); - InsertFunctionToTable("frac", &Parser::Frac); -} - - -/*! - this method creates the table of variables -*/ -void CreateVariablesTable() -{ - InsertVariableToTable("pi", &ValueType::SetPi); - InsertVariableToTable("e", &ValueType::SetE); -} - - -/*! - converting from a big letter to a small one -*/ -int ToLowerCase(int c) -{ - if( c>='A' && c<='Z' ) - return c - 'A' + 'a'; - -return c; -} - - -/*! - this method read the name of a variable or a function - - 'result' will be the name of a variable or a function - function return 'false' if this name is the name of a variable - or function return 'true' if this name is the name of a function - - what should be returned is tested just by a '(' character that means if there's - a '(' character after a name that function returns 'true' -*/ -bool ReadName(std::string & result) -{ -int character; - - - result.erase(); - character = *pstring; - - /* - the first letter must be from range 'a' - 'z' or 'A' - 'Z' - */ - if( ! (( character>='a' && character<='z' ) || ( character>='A' && character<='Z' )) ) - Error( err_unknown_character ); - - - do - { - result += static_cast( character ); - character = * ++pstring; - } - while( (character>='a' && character<='z') || - (character>='A' && character<='Z') || - (character>='0' && character<='9') || - character=='_' ); - - - SkipWhiteCharacters(); - - - /* - if there's a character '(' that means this name is a name of a function - */ - if( *pstring == '(' ) - { - ++pstring; - return true; - } - - -return false; -} - - -/*! - we're checking whether the first character is '-' or '+' - if it is we'll return 'true' and if it is equally '-' we'll set the 'sign' member of 'result' -*/ -bool TestSign(Item & result) -{ - SkipWhiteCharacters(); - result.sign = false; - - if( *pstring == '-' || *pstring == '+' ) - { - if( *pstring == '-' ) - result.sign = true; - - ++pstring; - - return true; - } - -return false; -} - - -/*! - we're reading the name of a variable or a function - if is there a function we'll return 'true' -*/ -bool ReadVariableOrFunction(Item & result) -{ -std::string name; -bool is_it_name_of_function = ReadName(name); - - if( is_it_name_of_function ) - { - /* - we've read the name of a function - */ - result.function_name = name; - result.type = Item::first_bracket; - result.function = true; - } - else - { - /* - we've read the name of a variable and we're getting its value now - */ - result.value = GetValueOfVariable( name ); - } - -return is_it_name_of_function; -} - - - - -/*! - we're reading a numerical value directly from the string -*/ -void ReadValue(Item & result, int reading_base) -{ -const char * new_stack_pointer; -bool value_read; -Conv conv; - - conv.base = reading_base; - conv.comma = comma; - conv.comma2 = comma2; - conv.group = group; - - uint carry = result.value.FromString(pstring, conv, &new_stack_pointer, &value_read); - pstring = new_stack_pointer; - - if( carry ) - Error( err_overflow ); - - if( !value_read ) - Error( err_unknown_character ); -} - - -/*! - this method returns true if 'character' is a proper first digit for the value (or a comma -- can be first too) -*/ -bool ValueStarts(int character, int character_base) -{ - if( character == comma ) - return true; - - if( comma2!=0 && character==comma2 ) - return true; - - if( Misc::CharToDigit(character, character_base) != -1 ) - return true; - -return false; -} - - -/*! - we're reading the item - - return values: - 0 - all ok, the item is successfully read - 1 - the end of the string (the item is not read) - 2 - the final bracket ')' -*/ -int ReadValueVariableOrFunction(Item & result) -{ -bool it_was_sign = false; -int character; - - - if( TestSign(result) ) - // 'result.sign' was set as well - it_was_sign = true; - - SkipWhiteCharacters(); - character = ToLowerCase( *pstring ); - - - if( character == 0 ) - { - if( it_was_sign ) - // at the end of the string a character like '-' or '+' has left - Error( err_unexpected_end ); - - // there's the end of the string here - return 1; - } - else - if( character == '(' ) - { - // we've got a normal bracket (not a function) - result.type = Item::first_bracket; - result.function = false; - ++pstring; - - return 0; - } - else - if( character == ')' ) - { - // we've got a final bracket - // (in this place we can find a final bracket only when there are empty brackets - // without any values inside or with a sign '-' or '+' inside) - - if( it_was_sign ) - Error( err_unexpected_final_bracket ); - - result.type = Item::last_bracket; - - // we don't increment 'pstring', this final bracket will be read next by the - // 'ReadOperatorAndCheckFinalBracket(...)' method - - return 2; - } - else - if( character == '#' ) - { - ++pstring; - SkipWhiteCharacters(); - - // after '#' character we do not allow '-' or '+' (can be white characters) - if( ValueStarts(*pstring, 16) ) - ReadValue( result, 16 ); - else - Error( err_unknown_character ); - } - else - if( character == '&' ) - { - ++pstring; - SkipWhiteCharacters(); - - // after '&' character we do not allow '-' or '+' (can be white characters) - if( ValueStarts(*pstring, 2) ) - ReadValue( result, 2 ); - else - Error( err_unknown_character ); - } - else - if( ValueStarts(character, base) ) - { - ReadValue( result, base ); - } - else - if( character>='a' && character<='z' ) - { - if( ReadVariableOrFunction(result) ) - // we've read the name of a function - return 0; - } - else - Error( err_unknown_character ); - - - - /* - we've got a value in the 'result' - this value is from a variable or directly from the string - */ - result.type = Item::numerical_value; - - if( result.sign ) - { - result.value.ChangeSign(); - result.sign = false; - } - - -return 0; -} - - -void InsertOperatorToTable(const char * name, typename MatOperator::Type type) -{ - operators_table.insert( std::make_pair(std::string(name), type) ); -} - - -/*! - this method creates the table of operators -*/ -void CreateMathematicalOperatorsTable() -{ - InsertOperatorToTable("||", MatOperator::lor); - InsertOperatorToTable("&&", MatOperator::land); - InsertOperatorToTable("!=", MatOperator::neq); - InsertOperatorToTable("==", MatOperator::eq); - InsertOperatorToTable(">=", MatOperator::get); - InsertOperatorToTable("<=", MatOperator::let); - InsertOperatorToTable(">", MatOperator::gt); - InsertOperatorToTable("<", MatOperator::lt); - InsertOperatorToTable("-", MatOperator::sub); - InsertOperatorToTable("+", MatOperator::add); - InsertOperatorToTable("/", MatOperator::div); - InsertOperatorToTable("*", MatOperator::mul); - InsertOperatorToTable("^", MatOperator::pow); -} - - -/*! - returns true if 'str2' is the substring of str1 - - e.g. - true when str1="test" and str2="te" -*/ -bool IsSubstring(const std::string & str1, const std::string & str2) -{ - if( str2.length() > str1.length() ) - return false; - - for(typename std::string::size_type i=0 ; ifirst, oper) ) - { - oper.erase(oper.begin() + oper.size() - 1); // we've got mininum one element - - if( iter_old != operators_table.end() && iter_old->first == oper ) - { - result.type = Item::mat_operator; - result.moperator.SetType( iter_old->second ); - break; - } - - Error( err_unknown_operator ); - } - - iter_old = iter_new; - } -} - - -/*! - this method makes a calculation for the percentage operator - e.g. - 1000-50% = 1000-(1000*0,5) = 500 -*/ -void OperatorPercentage() -{ - if( stack_index < 3 || - stack[stack_index-1].type != Item::numerical_value || - stack[stack_index-2].type != Item::mat_operator || - stack[stack_index-3].type != Item::numerical_value ) - Error(err_percent_from); - - ++pstring; - SkipWhiteCharacters(); - - uint c = 0; - c += stack[stack_index-1].value.Div(100); - c += stack[stack_index-1].value.Mul(stack[stack_index-3].value); - - if( c ) - Error(err_overflow); -} - - -/*! - this method reads a mathematic operators - or the final bracket or the semicolon operator - - return values: - 0 - ok - 1 - the string is finished -*/ -int ReadOperator(Item & result) -{ - SkipWhiteCharacters(); - - if( *pstring == '%' ) - OperatorPercentage(); - - - if( *pstring == 0 ) - return 1; - else - if( *pstring == ')' ) - { - result.type = Item::last_bracket; - ++pstring; - } - else - if( *pstring == ';' || (param_sep!=0 && *pstring==param_sep) ) - { - result.type = Item::semicolon; - ++pstring; - } - else - if( (*pstring>='a' && *pstring<='z') || (*pstring>='A' && *pstring<='Z') ) - { - // short mul (without any operators) - - result.type = Item::mat_operator; - result.moperator.SetType( MatOperator::shortmul ); - } - else - ReadMathematicalOperator(result); - -return 0; -} - - - -/*! - this method is making the standard mathematic operation like '-' '+' '*' '/' and '^' - - the operation is made between 'value1' and 'value2' - the result of this operation is stored in the 'value1' -*/ -void MakeStandardMathematicOperation(ValueType & value1, typename MatOperator::Type mat_operator, - const ValueType & value2) -{ -uint res; - - calculated = true; - - switch( mat_operator ) - { - case MatOperator::land: - (!value1.IsZero() && !value2.IsZero()) ? value1.SetOne() : value1.SetZero(); - break; - - case MatOperator::lor: - (!value1.IsZero() || !value2.IsZero()) ? value1.SetOne() : value1.SetZero(); - break; - - case MatOperator::eq: - (value1 == value2) ? value1.SetOne() : value1.SetZero(); - break; - - case MatOperator::neq: - (value1 != value2) ? value1.SetOne() : value1.SetZero(); - break; - - case MatOperator::lt: - (value1 < value2) ? value1.SetOne() : value1.SetZero(); - break; - - case MatOperator::gt: - (value1 > value2) ? value1.SetOne() : value1.SetZero(); - break; - - case MatOperator::let: - (value1 <= value2) ? value1.SetOne() : value1.SetZero(); - break; - - case MatOperator::get: - (value1 >= value2) ? value1.SetOne() : value1.SetZero(); - break; - - case MatOperator::sub: - if( value1.Sub(value2) ) Error( err_overflow ); - break; - - case MatOperator::add: - if( value1.Add(value2) ) Error( err_overflow ); - break; - - case MatOperator::mul: - case MatOperator::shortmul: - if( value1.Mul(value2) ) Error( err_overflow ); - break; - - case MatOperator::div: - if( value2.IsZero() ) Error( err_division_by_zero ); - if( value1.Div(value2) ) Error( err_overflow ); - break; - - case MatOperator::pow: - res = value1.Pow( value2 ); - - if( res == 1 ) Error( err_overflow ); - else - if( res == 2 ) Error( err_improper_argument ); - - break; - - default: - /* - on the stack left an unknown operator but we had to recognize its before - that means there's an error in our algorithm - */ - Error( err_internal_error ); - } -} - - - - -/*! - this method is trying to roll the stack up with the operator's priority - - for example if there are: - "1 - 2 +" - we can subtract "1-2" and the result store on the place where is '1' and copy the last - operator '+', that means there'll be '-1+' on our stack - - but if there are: - "1 - 2 *" - we can't roll the stack up because the operator '*' has greater priority than '-' -*/ -void TryRollingUpStackWithOperatorPriority() -{ - while( stack_index>=4 && - stack[stack_index-4].type == Item::numerical_value && - stack[stack_index-3].type == Item::mat_operator && - stack[stack_index-2].type == Item::numerical_value && - stack[stack_index-1].type == Item::mat_operator && - ( - ( - // the first operator has greater priority - stack[stack_index-3].moperator.GetPriority() > stack[stack_index-1].moperator.GetPriority() - ) || - ( - // or both operators have the same priority and the first operator is not right associative - stack[stack_index-3].moperator.GetPriority() == stack[stack_index-1].moperator.GetPriority() && - stack[stack_index-3].moperator.GetAssoc() == MatOperator::non_right - ) - ) - ) - { - MakeStandardMathematicOperation(stack[stack_index-4].value, - stack[stack_index-3].moperator.GetType(), - stack[stack_index-2].value); - - - /* - copying the last operator and setting the stack pointer to the correct value - */ - stack[stack_index-3] = stack[stack_index-1]; - stack_index -= 2; - } -} - - -/*! - this method is trying to roll the stack up without testing any operators - - for example if there are: - "1 - 2" - there'll be "-1" on our stack -*/ -void TryRollingUpStack() -{ - while( stack_index >= 3 && - stack[stack_index-3].type == Item::numerical_value && - stack[stack_index-2].type == Item::mat_operator && - stack[stack_index-1].type == Item::numerical_value ) - { - MakeStandardMathematicOperation( stack[stack_index-3].value, - stack[stack_index-2].moperator.GetType(), - stack[stack_index-1].value ); - - stack_index -= 2; - } -} - - -/*! - this method is reading a value or a variable or a function - (the normal first bracket as well) and push it into the stack -*/ -int ReadValueVariableOrFunctionAndPushItIntoStack(Item & temp) -{ -int code = ReadValueVariableOrFunction( temp ); - - if( code == 0 ) - { - if( stack_index < stack.size() ) - stack[stack_index] = temp; - else - stack.push_back( temp ); - - ++stack_index; - } - - if( code == 2 ) - // there was a final bracket, we didn't push it into the stack - // (it'll be read by the 'ReadOperatorAndCheckFinalBracket' method next) - code = 0; - - -return code; -} - - - -/*! - this method calculate how many parameters there are on the stack - and the index of the first parameter - - if there aren't any parameters on the stack this method returns - 'size' equals zero and 'index' pointing after the first bracket - (on non-existend element) -*/ -void HowManyParameters(int & size, int & index) -{ - size = 0; - index = stack_index; - - if( index == 0 ) - // we haven't put a first bracket on the stack - Error( err_unexpected_final_bracket ); - - - if( stack[index-1].type == Item::first_bracket ) - // empty brackets - return; - - for( --index ; index>=1 ; index-=2 ) - { - if( stack[index].type != Item::numerical_value ) - { - /* - this element must be 'numerical_value', if not that means - there's an error in our algorithm - */ - Error( err_internal_error ); - } - - ++size; - - if( stack[index-1].type != Item::semicolon ) - break; - } - - if( index<1 || stack[index-1].type != Item::first_bracket ) - { - /* - we haven't put a first bracket on the stack - */ - Error( err_unexpected_final_bracket ); - } -} - - -/*! - this method is being called when the final bracket ')' is being found - - this method's rolling the stack up, counting how many parameters there are - on the stack and if there was a function it's calling the function -*/ -void RollingUpFinalBracket() -{ -int amount_of_parameters; -int index; - - - if( stack_index<1 || - (stack[stack_index-1].type != Item::numerical_value && - stack[stack_index-1].type != Item::first_bracket) - ) - Error( err_unexpected_final_bracket ); - - - TryRollingUpStack(); - HowManyParameters(amount_of_parameters, index); - - // 'index' will be greater than zero - // 'amount_of_parameters' can be zero - - - if( amount_of_parameters==0 && !stack[index-1].function ) - Error( err_unexpected_final_bracket ); - - - bool was_sign = stack[index-1].sign; - - - if( stack[index-1].function ) - { - // the result of a function will be on 'stack[index-1]' - // and then at the end we'll set the correct type (numerical value) of this element - CallFunction(stack[index-1].function_name, amount_of_parameters, index); - } - else - { - /* - there was a normal bracket (not a funcion) - */ - if( amount_of_parameters != 1 ) - Error( err_unexpected_semicolon_operator ); - - - /* - in the place where is the bracket we put the result - */ - stack[index-1] = stack[index]; - } - - - /* - if there was a '-' character before the first bracket - we change the sign of the expression - */ - stack[index-1].sign = false; - - if( was_sign ) - stack[index-1].value.ChangeSign(); - - stack[index-1].type = Item::numerical_value; - - - /* - the pointer of the stack will be pointing on the next (non-existing now) element - */ - stack_index = index; -} - - -/*! - this method is putting the operator on the stack -*/ - -void PushOperatorIntoStack(Item & temp) -{ - if( stack_index < stack.size() ) - stack[stack_index] = temp; - else - stack.push_back( temp ); - - ++stack_index; -} - - - -/*! - this method is reading a operator and if it's a final bracket - it's calling RollingUpFinalBracket() and reading a operator again -*/ -int ReadOperatorAndCheckFinalBracket(Item & temp) -{ - do - { - if( ReadOperator(temp) == 1 ) - { - /* - the string is finished - */ - return 1; - } - - if( temp.type == Item::last_bracket ) - RollingUpFinalBracket(); - - } - while( temp.type == Item::last_bracket ); - -return 0; -} - - -/*! - we check wheter there are only numerical value's or 'semicolon' operators on the stack -*/ -void CheckIntegrityOfStack() -{ - for(unsigned int i=0 ; iWasStopSignal() ) - Error( err_interrupt ); - - result_code = ReadValueVariableOrFunctionAndPushItIntoStack( item ); - - if( result_code == 0 ) - { - if( item.type == Item::first_bracket ) - continue; - - result_code = ReadOperatorAndCheckFinalBracket( item ); - } - - - if( result_code==1 || item.type==Item::semicolon ) - { - /* - the string is finished or the 'semicolon' operator has appeared - */ - - if( stack_index == 0 ) - Error( err_nothing_has_read ); - - TryRollingUpStack(); - - if( result_code == 1 ) - { - CheckIntegrityOfStack(); - - return; - } - } - - - PushOperatorIntoStack( item ); - TryRollingUpStackWithOperatorPriority(); - } -} - -/*! - this method is called at the end of the parsing process - - on our stack we can have another value than 'numerical_values' for example - when someone use the operator ';' in the global scope or there was an error during - parsing and the parser hasn't finished its job - - if there was an error the stack is cleaned up now - otherwise we resize stack and leave on it only 'numerical_value' items -*/ -void NormalizeStack() -{ - if( error!=err_ok || stack_index==0 ) - { - stack.clear(); - return; - } - - - /* - 'stack_index' tell us how many elements there are on the stack, - we must resize the stack now because 'stack_index' is using only for parsing - and stack has more (or equal) elements than value of 'stack_index' - */ - stack.resize( stack_index ); - - for(uint i=stack_index-1 ; i!=uint(-1) ; --i) - { - if( stack[i].type != Item::numerical_value ) - stack.erase( stack.begin() + i ); - } -} - - -public: - - -/*! - the default constructor -*/ -Parser(): default_stack_size(100) -{ - pstop_calculating = 0; - puser_variables = 0; - puser_functions = 0; - pfunction_local_variables = 0; - base = 10; - deg_rad_grad = 1; - error = err_ok; - group = 0; - comma = '.'; - comma2 = ','; - param_sep = 0; - - CreateFunctionsTable(); - CreateVariablesTable(); - CreateMathematicalOperatorsTable(); -} - - -/*! - the assignment operator -*/ -Parser & operator=(const Parser & p) -{ - pstop_calculating = p.pstop_calculating; - puser_variables = p.puser_variables; - puser_functions = p.puser_functions; - pfunction_local_variables = 0; - base = p.base; - deg_rad_grad = p.deg_rad_grad; - error = p.error; - group = p.group; - comma = p.comma; - comma2 = p.comma2; - param_sep = p.param_sep; - - /* - we don't have to call 'CreateFunctionsTable()' etc. - we can only copy these tables - */ - functions_table = p.functions_table; - variables_table = p.variables_table; - operators_table = p.operators_table; - - visited_variables = p.visited_variables; - visited_functions = p.visited_functions; - -return *this; -} - - -/*! - the copying constructor -*/ -Parser(const Parser & p): default_stack_size(p.default_stack_size) -{ - operator=(p); -} - - -/*! - the new base of mathematic system - default is 10 -*/ -void SetBase(int b) -{ - if( b>=2 && b<=16 ) - base = b; -} - - -/*! - the unit of angles used in: sin,cos,tan,cot,asin,acos,atan,acot - 0 - deg - 1 - rad (default) - 2 - grad -*/ -void SetDegRadGrad(int angle) -{ - if( angle >= 0 && angle <= 2 ) - deg_rad_grad = angle; -} - -/*! - this method sets a pointer to the object which tell us whether we should stop - calculations -*/ -void SetStopObject(const volatile StopCalculating * ps) -{ - pstop_calculating = ps; -} - - -/*! - this method sets the new table of user-defined variables - if you don't want any other variables just put zero value into the 'puser_variables' variable - - (you can have only one table at the same time) -*/ -void SetVariables(const Objects * pv) -{ - puser_variables = pv; -} - - -/*! - this method sets the new table of user-defined functions - if you don't want any other functions just put zero value into the 'puser_functions' variable - - (you can have only one table at the same time) -*/ -void SetFunctions(const Objects * pf) -{ - puser_functions = pf; -} - - -/*! - setting the group character - default zero (not used) -*/ -void SetGroup(int g) -{ - group = g; -} - - -/*! - setting the main comma operator and the additional comma operator - the additional operator can be zero (which means it is not used) - default are: '.' and ',' -*/ -void SetComma(int c, int c2 = 0) -{ - comma = c; - comma2 = c2; -} - - -/*! - setting an additional character which is used as a parameters separator - the main parameters separator is a semicolon (is used always) - - this character is used also as a global separator -*/ -void SetParamSep(int s) -{ - param_sep = s; -} - - -/*! - the main method using for parsing string -*/ -ErrorCode Parse(const char * str) -{ - stack_index = 0; - pstring = str; - error = err_ok; - calculated = false; - - stack.resize( default_stack_size ); - - try - { - Parse(); - } - catch(ErrorCode c) - { - error = c; - calculated = false; - } - - NormalizeStack(); - -return error; -} - - -/*! - the main method using for parsing string -*/ -ErrorCode Parse(const std::string & str) -{ - return Parse(str.c_str()); -} - - -#ifndef TTMATH_DONT_USE_WCHAR - -/*! - the main method using for parsing string -*/ -ErrorCode Parse(const wchar_t * str) -{ - Misc::AssignString(wide_to_ansi, str); - -return Parse(wide_to_ansi.c_str()); - - // !! wide_to_ansi clearing can be added here -} - - -/*! - the main method using for parsing string -*/ -ErrorCode Parse(const std::wstring & str) -{ - return Parse(str.c_str()); -} - -#endif - - -/*! - this method returns true is something was calculated - (at least one mathematical operator was used or a function or variable) - e.g. true if the string to Parse() looked like this: - "1+1" - "2*3" - "sin(5)" - - if the string was e.g. "678" the result is false -*/ -bool Calculated() -{ - return calculated; -} - - -/*! - initializing coefficients used when calculating the gamma (or factorial) function - this speed up the next calculations - you don't have to call this method explicitly - these coefficients will be calculated when needed -*/ -void InitCGamma() -{ - cgamma.InitAll(); -} - - -}; - - - -} // namespace - - -#endif diff --git a/include/geos/algorithm/ttmath/ttmaththreads.h b/include/geos/algorithm/ttmath/ttmaththreads.h deleted file mode 100644 index 57c3650346..0000000000 --- a/include/geos/algorithm/ttmath/ttmaththreads.h +++ /dev/null @@ -1,252 +0,0 @@ -/* - * This file is a part of TTMath Bignum Library - * and is distributed under the 3-Clause BSD Licence. - * Author: Tomasz Sowa - */ - -/* - * Copyright (c) 2006-2009, Tomasz Sowa - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * * Neither the name Tomasz Sowa nor the names of contributors to this - * project may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#ifndef headerfilettmaththreads -#define headerfilettmaththreads - -#include "ttmathtypes.h" - -#ifdef TTMATH_WIN32_THREADS -#include -#include -#endif - -#ifdef TTMATH_POSIX_THREADS -#include -#endif - - - -/*! - \file ttmaththreads.h - \brief Some objects used in multithreads environment -*/ - - -namespace ttmath -{ - - -#ifdef TTMATH_WIN32_THREADS - - /* - we use win32 threads - */ - - - /*! - in multithreads environment you should use TTMATH_MULTITHREADS_HELPER macro - somewhere in *.cpp file - - (at the moment in win32 this macro does nothing) - */ - #define TTMATH_MULTITHREADS_HELPER - - - /*! - objects of this class are used to synchronize - */ - class ThreadLock - { - HANDLE mutex_handle; - - - void CreateName(char * buffer) const - { - #ifdef _MSC_VER - #pragma warning (disable : 4996) - // warning C4996: 'sprintf': This function or variable may be unsafe. Consider using sprintf_s instead. - #endif - - sprintf(buffer, "TTMATH_LOCK_%ul", (unsigned long)GetCurrentProcessId()); - - #ifdef _MSC_VER - #pragma warning (default : 4996) - #endif - } - - - public: - - bool Lock() - { - char buffer[50]; - - CreateName(buffer); - mutex_handle = CreateMutexA(0, false, buffer); - - if( mutex_handle == 0 ) - return false; - - WaitForSingleObject(mutex_handle, INFINITE); - - return true; - } - - - ThreadLock() - { - mutex_handle = 0; - } - - - ~ThreadLock() - { - if( mutex_handle != 0 ) - { - ReleaseMutex(mutex_handle); - CloseHandle(mutex_handle); - } - } - }; - -#endif // #ifdef TTMATH_WIN32_THREADS - - - - - -#ifdef TTMATH_POSIX_THREADS - - /* - we use posix threads - */ - - - /*! - in multithreads environment you should use TTMATH_MULTITHREADS_HELPER macro - somewhere in *.cpp file - (this macro defines a pthread_mutex_t object used by TTMath library) - */ - #define TTMATH_MULTITHREADS_HELPER \ - namespace ttmath \ - { \ - pthread_mutex_t ttmath_mutex = PTHREAD_MUTEX_INITIALIZER; \ - } - - - /*! - ttmath_mutex will be defined by TTMATH_MULTITHREADS_HELPER macro - */ - extern pthread_mutex_t ttmath_mutex; - - - /*! - \brief objects of this class are used to synchronize - - this is a simple skeleton of a program in multithreads environment: - - #define TTMATH_MULTITHREADS - #include - - TTMATH_MULTITHREADS_HELPER - - int main() - { - [...] - } - - make sure that macro TTMATH_MULTITHREADS is defined and (somewhere in *.cpp file) - use TTMATH_MULTITHREADS_HELPER macro (outside of any classes/functions/namespaces scope) - */ - class ThreadLock - { - public: - - /*! - lock the current thread - - it uses a global mutex created by TTMATH_MULTITHREADS_HELPER macro - */ - bool Lock() - { - if( pthread_mutex_lock(&ttmath_mutex) != 0 ) - return false; - - return true; - } - - - ~ThreadLock() - { - pthread_mutex_unlock(&ttmath_mutex); - } - }; - -#endif // #ifdef TTMATH_POSIX_THREADS - - - - -#if !defined(TTMATH_POSIX_THREADS) && !defined(TTMATH_WIN32_THREADS) - - /*! - we don't use win32 and pthreads - */ - - /*! - */ - #define TTMATH_MULTITHREADS_HELPER - - - /*! - objects of this class are used to synchronize - actually we don't synchronize, the method Lock() returns always 'false' - */ - class ThreadLock - { - public: - - bool Lock() - { - return false; - } - }; - - -#endif // #if !defined(TTMATH_POSIX_THREADS) && !defined(TTMATH_WIN32_THREADS) - - - - - -} // namespace - -#endif - diff --git a/include/geos/algorithm/ttmath/ttmathtypes.h b/include/geos/algorithm/ttmath/ttmathtypes.h deleted file mode 100644 index 5c4e0b73e2..0000000000 --- a/include/geos/algorithm/ttmath/ttmathtypes.h +++ /dev/null @@ -1,718 +0,0 @@ -/* - * This file is a part of TTMath Bignum Library - * and is distributed under the 3-Clause BSD Licence. - * Author: Tomasz Sowa - */ - -/* - * Copyright (c) 2006-2017, Tomasz Sowa - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * * Neither the name Tomasz Sowa nor the names of contributors to this - * project may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - - -#ifndef headerfilettmathtypes -#define headerfilettmathtypes - -/*! - \file ttmathtypes.h - \brief constants used in the library - - As our library is written in header files (templates) we cannot use - constants like 'const int' etc. because we should have some source files - *.cpp to define this variables. Only what we can have are constants - defined by \#define preprocessor macros. - - All macros are preceded by TTMATH_ prefix -*/ - - -#include -#include -#include - -#ifndef _MSC_VER -#include -// for uint64_t and int64_t on a 32 bit platform -#endif - - - -/*! - the major version of the library - - the version present to the end user is constructed in this way: - - TTMATH_MAJOR_VER.TTMATH_MINOR_VER.TTMATH_REVISION_VER.[prerelease if TTMATH_PRERELEASE_VER==1] -*/ -#define TTMATH_MAJOR_VER 0 - -/*! - the minor version of the library - - the version present to the end user is constructed in this way: - - TTMATH_MAJOR_VER.TTMATH_MINOR_VER.TTMATH_REVISION_VER.[prerelease if TTMATH_PRERELEASE_VER==1] -*/ -#define TTMATH_MINOR_VER 9 - -/*! - the revision version of the library - - the version present to the end user is constructed in this way: - - TTMATH_MAJOR_VER.TTMATH_MINOR_VER.TTMATH_REVISION_VER.[prerelease if TTMATH_PRERELEASE_VER==1] -*/ -#define TTMATH_REVISION_VER 4 - -/*! - TTMATH_PRERELEASE_VER is either zero or one - zero means that this is the release version of the library - (one means something like beta) - - the version present to the end user is constructed in this way: - - TTMATH_MAJOR_VER.TTMATH_MINOR_VER.TTMATH_REVISION_VER.[prerelease if TTMATH_PRERELEASE_VER==1] -*/ -#define TTMATH_PRERELEASE_VER 1 - - - -/*! - you can define a platform explicitly by defining either - TTMATH_PLATFORM32 or TTMATH_PLATFORM64 macro -*/ -#if !defined TTMATH_PLATFORM32 && !defined TTMATH_PLATFORM64 - - #if !defined _M_X64 && !defined __x86_64__ - - /* - other platforms than x86 and amd64 are not recognized at the moment - so you should set TTMATH_PLATFORMxx manually - */ - - // we're using a 32bit platform - #define TTMATH_PLATFORM32 - - #else - - // we're using a 64bit platform - #define TTMATH_PLATFORM64 - - #endif - -#endif - - -/*! - asm version of the library is available by default only for: - x86 and amd64 platforms and for Microsoft Visual and GCC compilers - - but you can force using asm version (the same asm as for Microsoft Visual) - by defining TTMATH_FORCEASM macro - you have to be sure that your compiler accept such an asm format -*/ -#ifndef TTMATH_FORCEASM - - #if !defined __i386__ && !defined _X86_ && !defined _M_IX86 && !defined __x86_64__ && !defined _M_X64 - /*! - x86 architecture: - __i386__ defined by GNU C - _X86_ defined by MinGW32 - _M_IX86 defined by Visual Studio, Intel C/C++, Digital Mars and Watcom C/C++ - - amd64 architecture: - __x86_64__ defined by GNU C, CLANG (LLVM) and Sun Studio - _M_X64 defined by Visual Studio - - asm version is available only for x86 or amd64 platforms - */ - #define TTMATH_NOASM - #endif - - - - #if !defined _MSC_VER && !defined __GNUC__ - /*! - another compilers than MS VC or GCC or CLANG (LLVM) by default use no asm version - (CLANG defines __GNUC__ too) - */ - #define TTMATH_NOASM - #endif - - /* 32-bit gcc < 5 doesn't like to build the ASM with PIC enabled as */ - /* we do for GEOS */ - #if defined __GNUC__ && __GNUC__ < 5 && !defined __x86_64__ && !defined _M_X64 - #define TTMATH_NOASM - #endif - -#endif - - -namespace ttmath -{ - - -#ifdef TTMATH_PLATFORM32 - - /*! - on 32bit platforms one word (uint, sint) will be equal 32bits - */ - typedef unsigned int uint; - typedef signed int sint; - - /*! - on 32 bit platform ulint and slint will be equal 64 bits - */ - #ifdef _MSC_VER - // long long on MS Windows (Visual and GCC mingw compilers) have 64 bits - // stdint.h is not available on Visual Studio prior to VS 2010 version - typedef unsigned long long int ulint; - typedef signed long long int slint; - #else - // we do not use 'long' here because there is a difference in unix and windows - // environments: in unix 'long' has 64 bits but in windows it has only 32 bits - typedef uint64_t ulint; - typedef int64_t slint; - #endif - - /*! - how many bits there are in the uint type - */ - #define TTMATH_BITS_PER_UINT 32u - - /*! - the mask for the highest bit in the unsigned 32bit word (2^31) - */ - #define TTMATH_UINT_HIGHEST_BIT 2147483648u - - /*! - the max value of the unsigned 32bit word (2^32 - 1) - (all bits equal one) - */ - #define TTMATH_UINT_MAX_VALUE 4294967295u - - /*! - the number of words (32bit words on 32bit platform) - which are kept in built-in variables for a Big<> type - (these variables are defined in ttmathbig.h) - */ - #define TTMATH_BUILTIN_VARIABLES_SIZE 256u - - /*! - this macro returns the number of machine words - capable to hold min_bits bits - e.g. TTMATH_BITS(128) returns 4 - */ - #define TTMATH_BITS(min_bits) ((min_bits-1)/32 + 1) - -#else - - #ifdef _MSC_VER - /* in VC 'long' type has 32 bits, __int64 is VC extension */ - typedef unsigned __int64 uint; - typedef signed __int64 sint; - #else - #ifdef __MINGW64__ - //Mingw64 64-bit patch from https://www.ttmath.org/forum/patch_for_building_64_bit_using_windows_mingw64_gcc - typedef uint64_t uint; - typedef int64_t sint; - #else - /*! - on 64bit platforms one word (uint, sint) will be equal 64bits - */ - typedef unsigned long uint; - /*! - on 64bit platforms one word (uint, sint) will be equal 64bits - */ - typedef signed long sint; - #endif - - #endif - - /*! - on 64bit platforms we do not define ulint and slint - */ - - /*! - how many bits there are in the uint type - */ - #define TTMATH_BITS_PER_UINT 64ul - - /*! - the mask for the highest bit in the unsigned 64bit word (2^63) - */ - #define TTMATH_UINT_HIGHEST_BIT 9223372036854775808ul - - /*! - the max value of the unsigned 64bit word (2^64 - 1) - (all bits equal one) - */ - #define TTMATH_UINT_MAX_VALUE 18446744073709551615ul - - /*! - the number of words (64bit words on 64bit platforms) - which are kept in built-in variables for a Big<> type - (these variables are defined in ttmathbig.h) - */ - #define TTMATH_BUILTIN_VARIABLES_SIZE 128ul - - /*! - this macro returns the number of machine words - capable to hold min_bits bits - e.g. TTMATH_BITS(128) returns 2 - */ - #define TTMATH_BITS(min_bits) ((min_bits-1)/64 + 1) - -#endif -} - - -#if defined(TTMATH_MULTITHREADS) && !defined(TTMATH_MULTITHREADS_NOSYNC) - #if !defined(TTMATH_POSIX_THREADS) && !defined(TTMATH_WIN32_THREADS) - - #if defined(_WIN32) - #define TTMATH_WIN32_THREADS - #elif defined(unix) || defined(__unix__) || defined(__unix) - #define TTMATH_POSIX_THREADS - #endif - - #endif -#endif - - - -/*! - this variable defines how many iterations are performed - during some kind of calculating when we're making any long formulas - (for example Taylor series) - - it's used in ExpSurrounding0(...), LnSurrounding1(...), Sin0pi05(...), etc. - - note! there'll not be so many iterations, iterations are stopped when - there is no sense to continue calculating (for example when the result - still remains unchanged after adding next series and we know that the next - series are smaller than previous ones) -*/ -#define TTMATH_ARITHMETIC_MAX_LOOP 10000 - - - -/*! - this is a limit when calculating Karatsuba multiplication - if the size of a vector is smaller than TTMATH_USE_KARATSUBA_MULTIPLICATION_FROM_SIZE - the Karatsuba algorithm will use standard schoolbook multiplication -*/ -#ifdef TTMATH_DEBUG_LOG - // if TTMATH_DEBUG_LOG is defined then we should use the same size regardless of the compiler - #define TTMATH_USE_KARATSUBA_MULTIPLICATION_FROM_SIZE 3 -#else - #ifdef __GNUC__ - #define TTMATH_USE_KARATSUBA_MULTIPLICATION_FROM_SIZE 3 - #else - #define TTMATH_USE_KARATSUBA_MULTIPLICATION_FROM_SIZE 5 - #endif -#endif - - -/*! - this is a special value used when calculating the Gamma(x) function - if x is greater than this value then the Gamma(x) will be calculated using - some kind of series - - don't use smaller values than about 100 -*/ -#define TTMATH_GAMMA_BOUNDARY 2000 - - - - - -namespace ttmath -{ - - /*! - lib type codes: - - asm_vc_32 - with asm code designed for Microsoft Visual C++ (32 bits) - - asm_gcc_32 - with asm code designed for GCC (32 bits) - - asm_vc_64 - with asm for VC (64 bit) - - asm_gcc_64 - with asm for GCC (64 bit) - - no_asm_32 - pure C++ version (32 bit) - without any asm code - - no_asm_64 - pure C++ version (64 bit) - without any asm code - */ - enum LibTypeCode - { - asm_vc_32 = 0, - asm_gcc_32, - asm_vc_64, - asm_gcc_64, - no_asm_32, - no_asm_64 - }; - - - /*! - error codes - */ - enum ErrorCode - { - err_ok = 0, - err_nothing_has_read, - err_unknown_character, - err_unexpected_final_bracket, - err_stack_not_clear, - err_unknown_variable, - err_division_by_zero, - err_interrupt, - err_overflow, - err_unknown_function, - err_unknown_operator, - err_unexpected_semicolon_operator, - err_improper_amount_of_arguments, - err_improper_argument, - err_unexpected_end, - err_internal_error, - err_incorrect_name, - err_incorrect_value, - err_variable_exists, - err_variable_loop, - err_functions_loop, - err_must_be_only_one_value, - err_object_exists, - err_unknown_object, - err_still_calculating, - err_in_short_form_used_function, - err_percent_from - }; - - - /*! - this struct is used when converting to/from a string - /temporarily only in Big::ToString() and Big::FromString()/ - */ - struct Conv - { - /*! - base (radix) on which the value will be shown (or read) - default: 10 - */ - uint base; - - - /*! - used only in Big::ToString() - if true the value will be always shown in the scientific mode, e.g: 123e+30 - default: false - */ - bool scient; - - - /*! - used only in Big::ToString() - if scient is false then the value will be printed in the scientific mode - only if the exponent is greater than scien_from - default: 15 - */ - sint scient_from; - - - /*! - if 'base_round' is true and 'base' is different from 2, 4, 8, or 16 - and the result value is not an integer then we make an additional rounding - (after converting the last digit from the result is skipped) - default: true - - e.g. - - Conv c; - c.base_round = false; - Big<1, 1> a = "0.1"; // decimal input - std::cout << a.ToString(c) << std::endl; // the result is: 0.099999999 - */ - bool base_round; - - - /*! - used only in Big::ToString() - tells how many digits after comma are possible - default: -1 which means all digits are printed - - set it to zero if you want integer value only - - for example when the value is: - 12.345678 and 'round' is 4 - then the result will be - 12.3457 (the last digit was rounded) - */ - sint round; - - - /*! - if true that not mattered digits in the mantissa will be cut off - (zero characters at the end -- after the comma operator) - e.g. 1234,78000 will be: 1234,78 - default: true - */ - bool trim_zeroes; - - - /*! - the main comma operator (used when reading and writing) - default is a dot '.' - */ - uint comma; - - - /*! - additional comma operator (used only when reading) - if you don't want it just set it to zero - default is a comma ',' - - this allowes you to convert from a value: - 123.45 as well as from 123,45 - */ - uint comma2; - - - /*! - it sets the character which is used for grouping - if group=' ' then: 1234,56789 will be printed as: 1 234,567 89 - - if you don't want grouping just set it to zero (which is default) - */ - uint group; - - - /*! - how many digits should be grouped (it is used if 'group' is non zero) - default: 3 - */ - uint group_digits; - - - /*! - */ - uint group_exp; // not implemented yet - - - - - Conv() - { - // default values - base = 10; - scient = false; - scient_from = 15; - base_round = true; - round = -1; - trim_zeroes = true; - comma = '.'; - comma2 = ','; - group = 0; - group_digits = 3; - group_exp = 0; - } - }; - - - - /*! - this simple class can be used in multithreading model - (you can write your own class derived from this one) - - for example: in some functions like Factorial() - /at the moment only Factorial/ you can give a pointer to - the 'stop object', if the method WasStopSignal() of this - object returns true that means we should break the calculating - and return - */ - class StopCalculating - { - public: - virtual bool WasStopSignal() const volatile { return false; } - virtual ~StopCalculating(){} - }; - - - /*! - a small class which is useful when compiling with gcc - - object of this type holds the name and the line of a file - in which the macro TTMATH_ASSERT or TTMATH_REFERENCE_ASSERT was used - */ - class ExceptionInfo - { - const char * file; - int line; - - public: - ExceptionInfo() : file(0), line(0) {} - ExceptionInfo(const char * f, int l) : file(f), line(l) {} - - std::string Where() const - { - if( !file ) - return "unknown"; - - std::ostringstream result; - result << file << ":" << line; - - return result.str(); - } - }; - - - /*! - A small class used for reporting 'reference' errors - - In the library is used macro TTMATH_REFERENCE_ASSERT which - can throw an exception of this type - - ** from version 0.9.2 this macro is removed from all methods - in public interface so you don't have to worry about it ** - - If you compile with gcc you can get a small benefit - from using method Where() (it returns std::string) with - the name and the line of a file where the macro TTMATH_REFERENCE_ASSERT - was used) - */ - class ReferenceError : public std::logic_error, public ExceptionInfo - { - public: - - ReferenceError() : std::logic_error("reference error") - { - } - - ReferenceError(const char * f, int l) : - std::logic_error("reference error"), ExceptionInfo(f,l) - { - } - - std::string Where() const - { - return ExceptionInfo::Where(); - } - }; - - - /*! - a small class used for reporting errors - - in the library is used macro TTMATH_ASSERT which - (if the condition in it is false) throw an exception - of this type - - if you compile with gcc you can get a small benefit - from using method Where() (it returns std::string) with - the name and the line of a file where the macro TTMATH_ASSERT - was used) - */ - class RuntimeError : public std::runtime_error, public ExceptionInfo - { - public: - - RuntimeError() : std::runtime_error("internal error") - { - } - - RuntimeError(const char * f, int l) : - std::runtime_error("internal error"), ExceptionInfo(f,l) - { - } - - std::string Where() const - { - return ExceptionInfo::Where(); - } - }; - - - - /*! - TTMATH_DEBUG - this macro enables further testing during writing your code - you don't have to define it in a release mode - - if this macro is set then macros TTMATH_ASSERT and TTMATH_REFERENCE_ASSERT - are set as well and these macros can throw an exception if a condition in it - is not fulfilled (look at the definition of TTMATH_ASSERT and TTMATH_REFERENCE_ASSERT) - - TTMATH_DEBUG is set automatically if DEBUG or _DEBUG are defined - */ - #if defined DEBUG || defined _DEBUG - #define TTMATH_DEBUG - #endif - - - #ifdef TTMATH_DEBUG - - #if defined(__FILE__) && defined(__LINE__) - - #define TTMATH_REFERENCE_ASSERT(expression) \ - if( &(expression) == this ) throw ttmath::ReferenceError(__FILE__, __LINE__); - - #define TTMATH_ASSERT(expression) \ - if( !(expression) ) throw ttmath::RuntimeError(__FILE__, __LINE__); - - #else - - #define TTMATH_REFERENCE_ASSERT(expression) \ - if( &(expression) == this ) throw ReferenceError(); - - #define TTMATH_ASSERT(expression) \ - if( !(expression) ) throw RuntimeError(); - #endif - - #else - #define TTMATH_REFERENCE_ASSERT(expression) - #define TTMATH_ASSERT(expression) - #endif - - - - #ifdef TTMATH_DEBUG_LOG - #define TTMATH_LOG(msg) PrintLog(msg, std::cout); - #define TTMATH_LOGC(msg, carry) PrintLog(msg, carry, std::cout); - #define TTMATH_VECTOR_LOG(msg, vector, len) PrintVectorLog(msg, std::cout, vector, len); - #define TTMATH_VECTOR_LOGC(msg, carry, vector, len) PrintVectorLog(msg, carry, std::cout, vector, len); - #else - #define TTMATH_LOG(msg) - #define TTMATH_LOGC(msg, carry) - #define TTMATH_VECTOR_LOG(msg, vector, len) - #define TTMATH_VECTOR_LOGC(msg, carry, vector, len) - #endif - - - - -} // namespace - - -#endif - diff --git a/include/geos/algorithm/ttmath/ttmathuint.h b/include/geos/algorithm/ttmath/ttmathuint.h deleted file mode 100644 index 9b647459d7..0000000000 --- a/include/geos/algorithm/ttmath/ttmathuint.h +++ /dev/null @@ -1,4189 +0,0 @@ -/* - * This file is a part of TTMath Bignum Library - * and is distributed under the 3-Clause BSD Licence. - * Author: Tomasz Sowa - */ - -/* - * Copyright (c) 2006-2017, Tomasz Sowa - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * * Neither the name Tomasz Sowa nor the names of contributors to this - * project may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#ifndef headerfilettmathuint -#define headerfilettmathuint - - -/*! - \file ttmathuint.h - \brief template class UInt -*/ - -#include -#include - - -#include "ttmathtypes.h" -#include "ttmathmisc.h" - - - -/*! - \brief a namespace for the TTMath library -*/ -namespace ttmath -{ - -/*! - \brief UInt implements a big integer value without a sign - - value_size - how many bytes specify our value - - on 32bit platforms: value_size=1 -> 4 bytes -> 32 bits - - on 64bit platforms: value_size=1 -> 8 bytes -> 64 bits - value_size = 1,2,3,4,5,6.... -*/ -template -class UInt -{ -public: - - /*! - buffer for the integer value - table[0] - the lowest word of the value - */ - uint table[value_size]; - - - - /*! - some methods used for debugging purposes - */ - - - /*! - this method is only for debugging purposes or when we want to make - a table of a variable (constant) in ttmathbig.h - - it prints the table in a nice form of several columns - */ - template - void PrintTable(ostream_type & output) const - { - // how many columns there'll be - const int columns = 8; - - int c = 1; - for(int i=value_size-1 ; i>=0 ; --i) - { - output << "0x" << std::setfill('0'); - - #ifdef TTMATH_PLATFORM32 - output << std::setw(8); - #else - output << std::setw(16); - #endif - - output << std::hex << table[i]; - - if( i>0 ) - { - output << ", "; - - if( ++c > columns ) - { - output << std::endl; - c = 1; - } - } - } - - output << std::dec << std::endl; - } - - - /*! - this method is used when macro TTMATH_DEBUG_LOG is defined - */ - template - static void PrintVectorLog(const char_type * msg, ostream_type & output, const uint * vector, uint vector_len) - { - output << msg << std::endl; - - for(uint i=0 ; i - static void PrintVectorLog(const char_type * msg, uint carry, ostream_type & output, const uint * vector, uint vector_len) - { - PrintVectorLog(msg, output, vector, vector_len); - output << " carry: " << carry << std::endl; - } - - - /*! - this method is used when macro TTMATH_DEBUG_LOG is defined - */ - template - void PrintLog(const char_type * msg, ostream_type & output) const - { - PrintVectorLog(msg, output, table, value_size); - } - - - /*! - this method is used when macro TTMATH_DEBUG_LOG is defined - */ - template - void PrintLog(const char_type * msg, uint carry, ostream_type & output) const - { - PrintVectorLog(msg, output, table, value_size); - output << " carry: " << carry << std::endl; - } - - - /*! - this method returns the size of the table - */ - uint Size() const - { - return value_size; - } - - - /*! - this method sets zero - */ - void SetZero() - { - // in the future here can be 'memset' - - for(uint i=0 ; i & ss2) - { - for(uint i=0 ; i=0 && temp_table_index=0 ; --i) - table[i] = 0; - - - TTMATH_LOG("UInt::SetFromTable") - } - -#endif - - -#ifdef TTMATH_PLATFORM64 - /*! - this method copies the value stored in an another table - (warning: first values in temp_table are the highest words -- it's different - from our table) - - ***this method is created only on a 64bit platform*** - - we copy as many words as it is possible - - if temp_table_len is bigger than value_size we'll try to round - the lowest word from table depending on the last not used bit in temp_table - (this rounding isn't a perfect rounding -- look at the description below) - - and if temp_table_len is smaller than value_size we'll clear the rest words - in the table - - warning: we're using 'temp_table' as a pointer at 32bit words - */ - void SetFromTable(const unsigned int * temp_table, uint temp_table_len) - { - uint temp_table_index = 0; - sint i; // 'i' with a sign - - for(i=value_size-1 ; i>=0 && temp_table_index= 0 ; --i) - table[i] = 0; - - TTMATH_LOG("UInt::SetFromTable") - } - -#endif - - - - - - /*! - * - * basic mathematic functions - * - */ - - - - - /*! - this method adds one to the existing value - */ - uint AddOne() - { - return AddInt(1); - } - - - /*! - this method subtracts one from the existing value - */ - uint SubOne() - { - return SubInt(1); - } - - -private: - - - /*! - an auxiliary method for moving bits into the left hand side - - this method moves only words - */ - void RclMoveAllWords(uint & rest_bits, uint & last_c, uint bits, uint c) - { - rest_bits = bits % TTMATH_BITS_PER_UINT; - uint all_words = bits / TTMATH_BITS_PER_UINT; - uint mask = ( c ) ? TTMATH_UINT_MAX_VALUE : 0; - - - if( all_words >= value_size ) - { - if( all_words == value_size && rest_bits == 0 ) - last_c = table[0] & 1; - // else: last_c is default set to 0 - - // clearing - for(uint i = 0 ; i 0 ) - { - // 0 < all_words < value_size - - sint first, second; - last_c = table[value_size - all_words] & 1; // all_words is greater than 0 - - // copying the first part of the value - for(first = value_size-1, second=first-all_words ; second>=0 ; --first, --second) - table[first] = table[second]; - - // setting the rest to 'c' - for( ; first>=0 ; --first ) - table[first] = mask; - } - - TTMATH_LOG("UInt::RclMoveAllWords") - } - -public: - - /*! - moving all bits into the left side 'bits' times - return value <- this <- C - - bits is from a range of <0, man * TTMATH_BITS_PER_UINT> - or it can be even bigger then all bits will be set to 'c' - - the value c will be set into the lowest bits - and the method returns state of the last moved bit - */ - uint Rcl(uint bits, uint c=0) - { - uint last_c = 0; - uint rest_bits = bits; - - if( bits == 0 ) - return 0; - - if( bits >= TTMATH_BITS_PER_UINT ) - RclMoveAllWords(rest_bits, last_c, bits, c); - - if( rest_bits == 0 ) - { - TTMATH_LOG("UInt::Rcl") - return last_c; - } - - // rest_bits is from 1 to TTMATH_BITS_PER_UINT-1 now - if( rest_bits == 1 ) - { - last_c = Rcl2_one(c); - } - else if( rest_bits == 2 ) - { - // performance tests showed that for rest_bits==2 it's better to use Rcl2_one twice instead of Rcl2(2,c) - Rcl2_one(c); - last_c = Rcl2_one(c); - } - else - { - last_c = Rcl2(rest_bits, c); - } - - TTMATH_LOGC("UInt::Rcl", last_c) - - return last_c; - } - -private: - - /*! - an auxiliary method for moving bits into the right hand side - - this method moves only words - */ - void RcrMoveAllWords(uint & rest_bits, uint & last_c, uint bits, uint c) - { - rest_bits = bits % TTMATH_BITS_PER_UINT; - uint all_words = bits / TTMATH_BITS_PER_UINT; - uint mask = ( c ) ? TTMATH_UINT_MAX_VALUE : 0; - - - if( all_words >= value_size ) - { - if( all_words == value_size && rest_bits == 0 ) - last_c = (table[value_size-1] & TTMATH_UINT_HIGHEST_BIT) ? 1 : 0; - // else: last_c is default set to 0 - - // clearing - for(uint i = 0 ; i 0 ) - { - // 0 < all_words < value_size - - uint first, second; - last_c = (table[all_words - 1] & TTMATH_UINT_HIGHEST_BIT) ? 1 : 0; // all_words is > 0 - - // copying the first part of the value - for(first=0, second=all_words ; second this -> return value - - bits is from a range of <0, man * TTMATH_BITS_PER_UINT> - or it can be even bigger then all bits will be set to 'c' - - the value c will be set into the highest bits - and the method returns state of the last moved bit - */ - uint Rcr(uint bits, uint c=0) - { - uint last_c = 0; - uint rest_bits = bits; - - if( bits == 0 ) - return 0; - - if( bits >= TTMATH_BITS_PER_UINT ) - RcrMoveAllWords(rest_bits, last_c, bits, c); - - if( rest_bits == 0 ) - { - TTMATH_LOG("UInt::Rcr") - return last_c; - } - - // rest_bits is from 1 to TTMATH_BITS_PER_UINT-1 now - if( rest_bits == 1 ) - { - last_c = Rcr2_one(c); - } - else if( rest_bits == 2 ) - { - // performance tests showed that for rest_bits==2 it's better to use Rcr2_one twice instead of Rcr2(2,c) - Rcr2_one(c); - last_c = Rcr2_one(c); - } - else - { - last_c = Rcr2(rest_bits, c); - } - - TTMATH_LOGC("UInt::Rcr", last_c) - - return last_c; - } - - - /*! - this method moves all bits into the left side - (it returns value how many bits have been moved) - */ - uint CompensationToLeft() - { - uint moving = 0; - - // a - index a last word which is different from zero - sint a; - for(a=value_size-1 ; a>=0 && table[a]==0 ; --a); - - if( a < 0 ) - return moving; // all words in table have zero - - if( a != value_size-1 ) - { - moving += ( value_size-1 - a ) * TTMATH_BITS_PER_UINT; - - // moving all words - sint i; - for(i=value_size-1 ; a>=0 ; --i, --a) - table[i] = table[a]; - - // setting the rest word to zero - for(; i>=0 ; --i) - table[i] = 0; - } - - uint moving2 = FindLeadingBitInWord( table[value_size-1] ); - // moving2 is different from -1 because the value table[value_size-1] - // is not zero - - moving2 = TTMATH_BITS_PER_UINT - moving2 - 1; - Rcl(moving2); - - TTMATH_LOG("UInt::CompensationToLeft") - - return moving + moving2; - } - - - /*! - this method looks for the highest set bit - - result: - - if 'this' is not zero: - return value - true, - 'table_id' - the index of a word <0..value_size-1>, - 'index' - the index of this set bit in the word <0..TTMATH_BITS_PER_UINT) - - - if 'this' is zero: - return value - false, - both 'table_id' and 'index' are zero - */ - bool FindLeadingBit(uint & table_id, uint & index) const - { - for(table_id=value_size-1 ; table_id!=0 && table[table_id]==0 ; --table_id); - - if( table_id==0 && table[table_id]==0 ) - { - // is zero - index = 0; - - return false; - } - - // table[table_id] is different from 0 - index = FindLeadingBitInWord( table[table_id] ); - - return true; - } - - - /*! - this method looks for the smallest set bit - - result: - - if 'this' is not zero: - return value - true, - 'table_id' - the index of a word <0..value_size-1>, - 'index' - the index of this set bit in the word <0..TTMATH_BITS_PER_UINT) - - - if 'this' is zero: - return value - false, - both 'table_id' and 'index' are zero - */ - bool FindLowestBit(uint & table_id, uint & index) const - { - for(table_id=0 ; table_id= value_size ) - { - // is zero - index = 0; - table_id = 0; - - return false; - } - - // table[table_id] is different from 0 - index = FindLowestBitInWord( table[table_id] ); - - return true; - } - - - /*! - getting the 'bit_index' bit - - bit_index bigger or equal zero - */ - uint GetBit(uint bit_index) const - { - TTMATH_ASSERT( bit_index < value_size * TTMATH_BITS_PER_UINT ) - - uint index = bit_index / TTMATH_BITS_PER_UINT; - uint bit = bit_index % TTMATH_BITS_PER_UINT; - - uint temp = table[index]; - uint res = SetBitInWord(temp, bit); - - return res; - } - - - /*! - setting the 'bit_index' bit - and returning the last state of the bit - - bit_index bigger or equal zero - */ - uint SetBit(uint bit_index) - { - TTMATH_ASSERT( bit_index < value_size * TTMATH_BITS_PER_UINT ) - - uint index = bit_index / TTMATH_BITS_PER_UINT; - uint bit = bit_index % TTMATH_BITS_PER_UINT; - uint res = SetBitInWord(table[index], bit); - - TTMATH_LOG("UInt::SetBit") - - return res; - } - - - /*! - this method performs a bitwise operation AND - */ - void BitAnd(const UInt & ss2) - { - for(uint x=0 ; x & ss2) - { - for(uint x=0 ; x & ss2) - { - for(uint x=0 ; x - - for example: - BitNot2(8) = BitNot2( 1000(bin) ) = 111(bin) = 7 - */ - void BitNot2() - { - uint table_id, index; - - if( FindLeadingBit(table_id, index) ) - { - for(uint x=0 ; x>= shift; - - table[table_id] ^= mask; - } - else - table[0] = 1; - - - TTMATH_LOG("UInt::BitNot2") - } - - - - /*! - * - * Multiplication - * - * - */ - -public: - - /*! - multiplication: this = this * ss2 - - it can return a carry - */ - uint MulInt(uint ss2) - { - uint r1, r2, x1; - uint c = 0; - - UInt u(*this); - SetZero(); - - if( ss2 == 0 ) - { - TTMATH_LOGC("UInt::MulInt(uint)", 0) - return 0; - } - - for(x1=0 ; x1 - void MulInt(uint ss2, UInt & result) const - { - TTMATH_ASSERT( result_size > value_size ) - - uint r2,r1; - uint x1size=value_size; - uint x1start=0; - - result.SetZero(); - - if( ss2 == 0 ) - { - TTMATH_VECTOR_LOG("UInt::MulInt(uint, UInt<>)", result.table, result_size) - return; - } - - if( value_size > 2 ) - { - // if the value_size is smaller than or equal to 2 - // there is no sense to set x1size and x1start to another values - - for(x1size=value_size ; x1size>0 && table[x1size-1]==0 ; --x1size); - - if( x1size == 0 ) - { - TTMATH_VECTOR_LOG("UInt::MulInt(uint, UInt<>)", result.table, result_size) - return; - } - - for(x1start=0 ; x1start)", result.table, result_size) - - return; - } - - - - /*! - the multiplication 'this' = 'this' * ss2 - - algorithm: 100 - means automatically choose the fastest algorithm - */ - uint Mul(const UInt & ss2, uint algorithm = 100) - { - switch( algorithm ) - { - case 1: - return Mul1(ss2); - - case 2: - return Mul2(ss2); - - case 3: - return Mul3(ss2); - - case 100: - default: - return MulFastest(ss2); - } - } - - - /*! - the multiplication 'result' = 'this' * ss2 - - since the 'result' is twice bigger than 'this' and 'ss2' - this method never returns a carry - - algorithm: 100 - means automatically choose the fastest algorithm - */ - void MulBig(const UInt & ss2, - UInt & result, - uint algorithm = 100) - { - switch( algorithm ) - { - case 1: - Mul1Big(ss2, result); - break; - - case 2: - Mul2Big(ss2, result); - break; - - case 3: - Mul3Big(ss2, result); - break; - - case 100: - default: - MulFastestBig(ss2, result); - } - } - - - - /*! - the first version of the multiplication algorithm - */ - -private: - - /*! - multiplication: this = this * ss2 - - it returns carry if it has been - */ - uint Mul1Ref(const UInt & ss2) - { - TTMATH_REFERENCE_ASSERT( ss2 ) - - UInt ss1( *this ); - SetZero(); - - for(uint i=0; i < value_size*TTMATH_BITS_PER_UINT ; ++i) - { - if( Add(*this) ) - { - TTMATH_LOGC("UInt::Mul1", 1) - return 1; - } - - if( ss1.Rcl(1) ) - if( Add(ss2) ) - { - TTMATH_LOGC("UInt::Mul1", 1) - return 1; - } - } - - TTMATH_LOGC("UInt::Mul1", 0) - - return 0; - } - - -public: - - /*! - multiplication: this = this * ss2 - can return carry - */ - uint Mul1(const UInt & ss2) - { - if( this == &ss2 ) - { - UInt copy_ss2(ss2); - return Mul1Ref(copy_ss2); - } - else - { - return Mul1Ref(ss2); - } - } - - - /*! - multiplication: result = this * ss2 - - result is twice bigger than 'this' and 'ss2' - this method never returns carry - */ - void Mul1Big(const UInt & ss2_, UInt & result) - { - UInt ss2; - uint i; - - // copying *this into result and ss2_ into ss2 - for(i=0 ; i & ss2) - { - UInt result; - uint i, c = 0; - - Mul2Big(ss2, result); - - // copying result - for(i=0 ; i & ss2, UInt & result) - { - Mul2Big2(table, ss2.table, result); - - TTMATH_LOG("UInt::Mul2Big") - } - - -private: - - /*! - an auxiliary method for calculating the multiplication - - arguments we're taking as pointers (this is to improve the Mul3Big2()- avoiding - unnecessary copying objects), the result should be taken as a pointer too, - but at the moment there is no method AddTwoInts() which can operate on pointers - */ - template - void Mul2Big2(const uint * ss1, const uint * ss2, UInt & result) - { - uint x1size = ss_size, x2size = ss_size; - uint x1start = 0, x2start = 0; - - if( ss_size > 2 ) - { - // if the ss_size is smaller than or equal to 2 - // there is no sense to set x1size (and others) to another values - - for(x1size=ss_size ; x1size>0 && ss1[x1size-1]==0 ; --x1size); - for(x2size=ss_size ; x2size>0 && ss2[x2size-1]==0 ; --x2size); - - for(x1start=0 ; x1start(ss1, ss2, result, x1start, x1size, x2start, x2size); - } - - - - /*! - an auxiliary method for calculating the multiplication - */ - template - void Mul2Big3(const uint * ss1, const uint * ss2, UInt & result, uint x1start, uint x1size, uint x2start, uint x2size) - { - uint r2, r1; - - result.SetZero(); - - if( x1size==0 || x2size==0 ) - return; - - for(uint x1=x1start ; x1 & ss2) - { - UInt result; - uint i, c = 0; - - Mul3Big(ss2, result); - - // copying result - for(i=0 ; i & ss2, UInt & result) - { - Mul3Big2(table, ss2.table, result.table); - - TTMATH_LOG("UInt::Mul3Big") - } - - - -private: - - /*! - an auxiliary method for calculating the Karatsuba multiplication - - result_size is equal ss_size*2 - */ - template - void Mul3Big2(const uint * ss1, const uint * ss2, uint * result) - { - const uint * x1, * x0, * y1, * y0; - - - if( ss_size>1 && ss_size res; - Mul2Big2(ss1, ss2, res); - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wtautological-compare" -#endif - - for(uint i=0 ; i(x1, x0, y1, y0, result); - } - else - { - // ss_size is even - x0 = ss1; - y0 = ss2; - x1 = ss1 + ss_size / 2; - y1 = ss2 + ss_size / 2; - - // all four vectors (x0 x1 y0 y1) are equal in size - Mul3Big3(x1, x0, y1, y0, result); - } - } - - - -#ifdef _MSC_VER -#pragma warning (disable : 4717) -//warning C4717: recursive on all control paths, function will cause runtime stack overflow -//we have the stop point in Mul3Big2() method -#endif - -#if defined(__GNUC__) && !defined(__clang__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-but-set-variable" -#endif - - - /*! - an auxiliary method for calculating the Karatsuba multiplication - - x = x1*B^m + x0 - y = y1*B^m + y0 - - first_size - is the size of vectors: x0 and y0 - second_size - is the size of vectors: x1 and y1 (can be either equal first_size or smaller about one from first_size) - - x*y = (x1*B^m + x0)(y1*B^m + y0) = z2*B^(2m) + z1*B^m + z0 - where - z0 = x0*y0 - z2 = x1*y1 - z1 = (x1 + x0)*(y1 + y0) - z2 - z0 - */ - template - void Mul3Big3(const uint * x1, const uint * x0, const uint * y1, const uint * y0, uint * result) - { - uint i, c, xc, yc; - - UInt temp, temp2; - UInt z1; - - // z0 and z2 we store directly in the result (we don't use any temporary variables) - Mul3Big2(x0, y0, result); // z0 - Mul3Big2(x1, y1, result+first_size*2); // z2 - - // now we calculate z1 - // temp = (x0 + x1) - // temp2 = (y0 + y1) - // we're using temp and temp2 with UInt, although there can be a carry but - // we simple remember it in xc and yc (xc and yc can be either 0 or 1), - // and (x0 + x1)*(y0 + y1) we calculate in this way (schoolbook algorithm): - // - // xc | temp - // yc | temp2 - // -------------------- - // (temp * temp2) - // xc*temp2 | - // yc*temp | - // xc*yc | - // ---------- z1 -------- - // - // and the result is never larger in size than 3*first_size - - xc = AddVector(x0, x1, first_size, second_size, temp.table); - yc = AddVector(y0, y1, first_size, second_size, temp2.table); - - Mul3Big2(temp.table, temp2.table, z1.table); - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wtautological-compare" -#endif - - // clearing the rest of z1 - for(i=first_size*2 ; i second_size ) - { - uint z1_size = result_size - first_size; - TTMATH_ASSERT( z1_size <= first_size*3 ) - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wtautological-compare" -#endif - - for(i=z1_size ; i & ss2) - { - UInt result; - uint i, c = 0; - - MulFastestBig(ss2, result); - - // copying result - for(i=0 ; i & ss2, UInt & result) - { - if( value_size < TTMATH_USE_KARATSUBA_MULTIPLICATION_FROM_SIZE ) - { - Mul2Big(ss2, result); - return; - } - - uint x1size = value_size, x2size = value_size; - uint x1start = 0, x2start = 0; - - for(x1size=value_size ; x1size>0 && table[x1size-1]==0 ; --x1size); - for(x2size=value_size ; x2size>0 && ss2.table[x2size-1]==0 ; --x2size); - - if( x1size==0 || x2size==0 ) - { - // either 'this' or 'ss2' is equal zero - the result is zero too - result.SetZero(); - return; - } - - for(x1start=0 ; x1start(table, ss2.table, result, x1start, x1size, x2start, x2size); - return; - } - - - // Karatsuba multiplication - Mul3Big(ss2, result); - - TTMATH_LOG("UInt::MulFastestBig") - } - - - /*! - * - * Division - * - * - */ - -public: - - - /*! - division by one unsigned word - - returns 1 when divisor is zero - */ - uint DivInt(uint divisor, uint * remainder = 0) - { - if( divisor == 0 ) - { - if( remainder ) - *remainder = 0; // this is for convenience, without it the compiler can report that 'remainder' is uninitialized - - TTMATH_LOG("UInt::DivInt") - - return 1; - } - - if( divisor == 1 ) - { - if( remainder ) - *remainder = 0; - - TTMATH_LOG("UInt::DivInt") - - return 0; - } - - UInt dividend(*this); - SetZero(); - - sint i; // i must be with a sign - uint r = 0; - - // we're looking for the last word in ss1 - for(i=value_size-1 ; i>0 && dividend.table[i]==0 ; --i); - - for( ; i>=0 ; --i) - DivTwoWords(r, dividend.table[i], divisor, &table[i], &r); - - if( remainder ) - *remainder = r; - - TTMATH_LOG("UInt::DivInt") - - return 0; - } - - uint DivInt(uint divisor, uint & remainder) - { - return DivInt(divisor, &remainder); - } - - - - /*! - division this = this / ss2 - - return values: - - 0 - ok - - 1 - division by zero - - 'this' will be the quotient - - 'remainder' - remainder - */ - uint Div( const UInt & divisor, - UInt * remainder = 0, - uint algorithm = 3) - { - switch( algorithm ) - { - case 1: - return Div1(divisor, remainder); - - case 2: - return Div2(divisor, remainder); - - case 3: - default: - return Div3(divisor, remainder); - } - } - - uint Div(const UInt & divisor, UInt & remainder, uint algorithm = 3) - { - return Div(divisor, &remainder, algorithm); - } - - - -private: - - /*! - return values: - - 0 - none has to be done - - 1 - division by zero - - 2 - division should be made - */ - uint Div_StandardTest( const UInt & v, - uint & m, uint & n, - UInt * remainder = 0) - { - switch( Div_CalculatingSize(v, m, n) ) - { - case 4: // 'this' is equal v - if( remainder ) - remainder->SetZero(); - - SetOne(); - TTMATH_LOG("UInt::Div_StandardTest") - return 0; - - case 3: // 'this' is smaller than v - if( remainder ) - *remainder = *this; - - SetZero(); - TTMATH_LOG("UInt::Div_StandardTest") - return 0; - - case 2: // 'this' is zero - if( remainder ) - remainder->SetZero(); - - SetZero(); - TTMATH_LOG("UInt::Div_StandardTest") - return 0; - - case 1: // v is zero - TTMATH_LOG("UInt::Div_StandardTest") - return 1; - } - - TTMATH_LOG("UInt::Div_StandardTest") - - return 2; - } - - - - /*! - return values: - - 0 - ok - - 'm' - is the index (from 0) of last non-zero word in table ('this') - - 'n' - is the index (from 0) of last non-zero word in v.table - - 1 - v is zero - - 2 - 'this' is zero - - 3 - 'this' is smaller than v - - 4 - 'this' is equal v - - if the return value is different than zero the 'm' and 'n' are undefined - */ - uint Div_CalculatingSize(const UInt & v, uint & m, uint & n) - { - m = n = value_size-1; - - for( ; n!=0 && v.table[n]==0 ; --n); - - if( n==0 && v.table[n]==0 ) - return 1; - - for( ; m!=0 && table[m]==0 ; --m); - - if( m==0 && table[m]==0 ) - return 2; - - if( m < n ) - return 3; - else - if( m == n ) - { - uint i; - for(i = n ; i!=0 && table[i]==v.table[i] ; --i); - - if( table[i] < v.table[i] ) - return 3; - else - if (table[i] == v.table[i] ) - return 4; - } - - return 0; - } - - -public: - - /*! - the first division algorithm - (radix 2) - */ - uint Div1(const UInt & divisor, UInt * remainder = 0) - { - uint m,n, test; - - test = Div_StandardTest(divisor, m, n, remainder); - if( test < 2 ) - return test; - - if( !remainder ) - { - UInt rem; - - return Div1_Calculate(divisor, rem); - } - - return Div1_Calculate(divisor, *remainder); - } - - - /*! - the first division algorithm - (radix 2) - */ - uint Div1(const UInt & divisor, UInt & remainder) - { - return Div1(divisor, &remainder); - } - - -private: - - uint Div1_Calculate(const UInt & divisor, UInt & rest) - { - if( this == &divisor ) - { - UInt divisor_copy(divisor); - return Div1_CalculateRef(divisor_copy, rest); - } - else - { - return Div1_CalculateRef(divisor, rest); - } - } - - - uint Div1_CalculateRef(const UInt & divisor, UInt & rest) - { - TTMATH_REFERENCE_ASSERT( divisor ) - - sint loop; - sint c; - - rest.SetZero(); - loop = value_size * TTMATH_BITS_PER_UINT; - c = 0; - - - div_a: - c = Rcl(1, c); - c = rest.Add(rest,c); - c = rest.Sub(divisor,c); - - c = !c; - - if(!c) - goto div_d; - - - div_b: - --loop; - if(loop) - goto div_a; - - c = Rcl(1, c); - TTMATH_LOG("UInt::Div1_Calculate") - return 0; - - - div_c: - c = Rcl(1, c); - c = rest.Add(rest,c); - c = rest.Add(divisor); - - if(c) - goto div_b; - - - div_d: - --loop; - if(loop) - goto div_c; - - c = Rcl(1, c); - c = rest.Add(divisor); - - TTMATH_LOG("UInt::Div1_Calculate") - - return 0; - } - - -public: - - /*! - the second division algorithm - - return values: - - 0 - ok - - 1 - division by zero - */ - uint Div2(const UInt & divisor, UInt * remainder = 0) - { - if( this == &divisor ) - { - UInt divisor_copy(divisor); - return Div2Ref(divisor_copy, remainder); - } - else - { - return Div2Ref(divisor, remainder); - } - } - - - /*! - the second division algorithm - - return values: - - 0 - ok - - 1 - division by zero - */ - uint Div2(const UInt & divisor, UInt & remainder) - { - return Div2(divisor, &remainder); - } - - -private: - - /*! - the second division algorithm - - return values: - - 0 - ok - - 1 - division by zero - */ - uint Div2Ref(const UInt & divisor, UInt * remainder = 0) - { - uint bits_diff; - uint status = Div2_Calculate(divisor, remainder, bits_diff); - if( status < 2 ) - return status; - - if( CmpBiggerEqual(divisor) ) - { - Div2(divisor, remainder); - SetBit(bits_diff); - } - else - { - if( remainder ) - *remainder = *this; - - SetZero(); - SetBit(bits_diff); - } - - TTMATH_LOG("UInt::Div2") - - return 0; - } - - - /*! - return values: - - 0 - we've calculated the division - - 1 - division by zero - - 2 - we have to still calculate - - */ - uint Div2_Calculate(const UInt & divisor, UInt * remainder, - uint & bits_diff) - { - uint table_id, index; - uint divisor_table_id, divisor_index; - - uint status = Div2_FindLeadingBitsAndCheck( divisor, remainder, - table_id, index, - divisor_table_id, divisor_index); - - if( status < 2 ) - { - TTMATH_LOG("UInt::Div2_Calculate") - return status; - } - - // here we know that 'this' is greater than divisor - // then 'index' is greater or equal 'divisor_index' - bits_diff = index - divisor_index; - - UInt divisor_copy(divisor); - divisor_copy.Rcl(bits_diff, 0); - - if( CmpSmaller(divisor_copy, table_id) ) - { - divisor_copy.Rcr(1); - --bits_diff; - } - - Sub(divisor_copy, 0); - - TTMATH_LOG("UInt::Div2_Calculate") - - return 2; - } - - - /*! - return values: - - 0 - we've calculated the division - - 1 - division by zero - - 2 - we have to still calculate - */ - uint Div2_FindLeadingBitsAndCheck( const UInt & divisor, - UInt * remainder, - uint & table_id, uint & index, - uint & divisor_table_id, uint & divisor_index) - { - if( !divisor.FindLeadingBit(divisor_table_id, divisor_index) ) - { - // division by zero - TTMATH_LOG("UInt::Div2_FindLeadingBitsAndCheck") - return 1; - } - - if( !FindLeadingBit(table_id, index) ) - { - // zero is divided by something - - SetZero(); - - if( remainder ) - remainder->SetZero(); - - TTMATH_LOG("UInt::Div2_FindLeadingBitsAndCheck") - - return 0; - } - - divisor_index += divisor_table_id * TTMATH_BITS_PER_UINT; - index += table_id * TTMATH_BITS_PER_UINT; - - if( divisor_table_id == 0 ) - { - // dividor has only one 32-bit word - - uint r; - DivInt(divisor.table[0], &r); - - if( remainder ) - { - remainder->SetZero(); - remainder->table[0] = r; - } - - TTMATH_LOG("UInt::Div2_FindLeadingBitsAndCheck") - - return 0; - } - - - if( Div2_DivisorGreaterOrEqual( divisor, remainder, - table_id, index, - divisor_index) ) - { - TTMATH_LOG("UInt::Div2_FindLeadingBitsAndCheck") - return 0; - } - - - TTMATH_LOG("UInt::Div2_FindLeadingBitsAndCheck") - - return 2; - } - - - /*! - return values: - - true if divisor is equal or greater than 'this' - */ - bool Div2_DivisorGreaterOrEqual( const UInt & divisor, - UInt * remainder, - uint table_id, uint index, - uint divisor_index ) - { - if( divisor_index > index ) - { - // divisor is greater than this - - if( remainder ) - *remainder = *this; - - SetZero(); - - TTMATH_LOG("UInt::Div2_DivisorGreaterOrEqual") - - return true; - } - - if( divisor_index == index ) - { - // table_id == divisor_table_id as well - - uint i; - for(i = table_id ; i!=0 && table[i]==divisor.table[i] ; --i); - - if( table[i] < divisor.table[i] ) - { - // divisor is greater than 'this' - - if( remainder ) - *remainder = *this; - - SetZero(); - - TTMATH_LOG("UInt::Div2_DivisorGreaterOrEqual") - - return true; - } - else - if( table[i] == divisor.table[i] ) - { - // divisor is equal 'this' - - if( remainder ) - remainder->SetZero(); - - SetOne(); - - TTMATH_LOG("UInt::Div2_DivisorGreaterOrEqual") - - return true; - } - } - - TTMATH_LOG("UInt::Div2_DivisorGreaterOrEqual") - - return false; - } - - -public: - - /*! - the third division algorithm - */ - uint Div3(const UInt & ss2, UInt * remainder = 0) - { - if( this == &ss2 ) - { - UInt copy_ss2(ss2); - return Div3Ref(copy_ss2, remainder); - } - else - { - return Div3Ref(ss2, remainder); - } - } - - - /*! - the third division algorithm - */ - uint Div3(const UInt & ss2, UInt & remainder) - { - return Div3(ss2, &remainder); - } - - -private: - - /*! - the third division algorithm - - this algorithm is described in the following book: - "The art of computer programming 2" (4.3.1 page 272) - Donald E. Knuth - !! give the description here (from the book) - */ - uint Div3Ref(const UInt & v, UInt * remainder = 0) - { - uint m,n, test; - - test = Div_StandardTest(v, m, n, remainder); - if( test < 2 ) - return test; - - if( n == 0 ) - { - uint r; - DivInt( v.table[0], &r ); - - if( remainder ) - { - remainder->SetZero(); - remainder->table[0] = r; - } - - TTMATH_LOG("UInt::Div3") - - return 0; - } - - - // we can only use the third division algorithm when - // the divisor is greater or equal 2^32 (has more than one 32-bit word) - ++m; - ++n; - m = m - n; - Div3_Division(v, remainder, m, n); - - TTMATH_LOG("UInt::Div3") - - return 0; - } - - - -private: - - - void Div3_Division(UInt v, UInt * remainder, uint m, uint n) - { - TTMATH_ASSERT( n>=2 ) - - UInt uu, vv; - UInt q; - uint d, u_value_size, u0, u1, u2, v1, v0, j=m; - - u_value_size = Div3_Normalize(v, n, d); - - if( j+n == value_size ) - u2 = u_value_size; - else - u2 = table[j+n]; - - Div3_MakeBiggerV(v, vv); - - for(uint i = j+1 ; i & uu, uint j, uint n, uint u_max) - { - uint i; - - for(i=0 ; i so and 'i' is from <0..value_size> - // then table[i] is always correct (look at the declaration of 'uu') - uu.table[i] = u_max; - - for( ++i ; i & uu, uint j, uint n) - { - uint i; - - for(i=0 ; i & v, UInt & vv) - { - for(uint i=0 ; i & v, uint n, uint & d) - { - // v.table[n-1] is != 0 - - uint bit = (uint)FindLeadingBitInWord(v.table[n-1]); - uint move = (TTMATH_BITS_PER_UINT - bit - 1); - uint res = table[value_size-1]; - d = move; - - if( move > 0 ) - { - v.Rcl(move, 0); - Rcl(move, 0); - res = res >> (bit + 1); - } - else - { - res = 0; - } - - TTMATH_LOG("UInt::Div3_Normalize") - - return res; - } - - - void Div3_Unnormalize(UInt * remainder, uint n, uint d) - { - for(uint i=n ; i u_temp; - uint rp; - bool next_test; - - TTMATH_ASSERT( v1 != 0 ) - - u_temp.table[1] = u2; - u_temp.table[0] = u1; - u_temp.DivInt(v1, &rp); - - TTMATH_ASSERT( u_temp.table[1]==0 || u_temp.table[1]==1 ) - - do - { - bool decrease = false; - - if( u_temp.table[1] == 1 ) - decrease = true; - else - { - UInt<2> temp1, temp2; - - UInt<2>::MulTwoWords(u_temp.table[0], v0, temp1.table+1, temp1.table); - temp2.table[1] = rp; - temp2.table[0] = u0; - - if( temp1 > temp2 ) - decrease = true; - } - - next_test = false; - - if( decrease ) - { - u_temp.SubOne(); - - rp += v1; - - if( rp >= v1 ) // it means that there wasn't a carry (r & uu, - const UInt & vv, uint & qp) - { - // D4 (in the book) - - UInt vv_temp(vv); - vv_temp.MulInt(qp); - - if( uu.Sub(vv_temp) ) - { - // there was a carry - - // - // !!! this part of code was not tested - // - - --qp; - uu.Add(vv); - - // can be a carry from this additions but it should be ignored - // because it cancels with the borrow from uu.Sub(vv_temp) - } - - TTMATH_LOG("UInt::Div3_MultiplySubtract") - } - - - - - - -public: - - - /*! - power this = this ^ pow - binary algorithm (r-to-l) - - return values: - - 0 - ok - - 1 - carry - - 2 - incorrect argument (0^0) - */ - uint Pow(UInt pow) - { - if(pow.IsZero() && IsZero()) - // we don't define zero^zero - return 2; - - UInt start(*this); - UInt result; - result.SetOne(); - uint c = 0; - - while( !c ) - { - if( pow.table[0] & 1 ) - c += result.Mul(start); - - pow.Rcr2_one(0); - if( pow.IsZero() ) - break; - - c += start.Mul(start); - } - - *this = result; - - TTMATH_LOGC("UInt::Pow(UInt<>)", c) - - return (c==0)? 0 : 1; - } - - - /*! - square root - e.g. Sqrt(9) = 3 - ('digit-by-digit' algorithm) - */ - void Sqrt() - { - UInt bit, temp; - - if( IsZero() ) - return; - - UInt value(*this); - - SetZero(); - bit.SetZero(); - bit.table[value_size-1] = (TTMATH_UINT_HIGHEST_BIT >> 1); - - while( bit > value ) - bit.Rcr(2); - - while( !bit.IsZero() ) - { - temp = *this; - temp.Add(bit); - - if( value >= temp ) - { - value.Sub(temp); - Rcr(1); - Add(bit); - } - else - { - Rcr(1); - } - - bit.Rcr(2); - } - - TTMATH_LOG("UInt::Sqrt") - } - - - - - /*! - this method sets n first bits to value zero - - For example: - let n=2 then if there's a value 111 (bin) there'll be '100' (bin) - */ - void ClearFirstBits(uint n) - { - if( n >= value_size*TTMATH_BITS_PER_UINT ) - { - SetZero(); - TTMATH_LOG("UInt::ClearFirstBits") - return; - } - - uint * p = table; - - // first we're clearing the whole words - while( n >= TTMATH_BITS_PER_UINT ) - { - *p++ = 0; - n -= TTMATH_BITS_PER_UINT; - } - - if( n == 0 ) - { - TTMATH_LOG("UInt::ClearFirstBits") - return; - } - - // and then we're clearing one word which has left - // mask -- all bits are set to one - uint mask = TTMATH_UINT_MAX_VALUE; - - mask = mask << n; - - (*p) &= mask; - - TTMATH_LOG("UInt::ClearFirstBits") - } - - - /*! - this method returns true if the highest bit of the value is set - */ - bool IsTheHighestBitSet() const - { - return (table[value_size-1] & TTMATH_UINT_HIGHEST_BIT) != 0; - } - - - /*! - this method returns true if the lowest bit of the value is set - */ - bool IsTheLowestBitSet() const - { - return (*table & 1) != 0; - } - - - /*! - returning true if only the highest bit is set - */ - bool IsOnlyTheHighestBitSet() const - { -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wtautological-compare" -#endif - - for(uint i=0 ; i> (TTMATH_BITS_PER_UINT - rest); - - return (table[i] & mask) == 0; - } - - - - /*! - * - * conversion methods - * - */ - - - - /*! - this method converts an UInt type to this class - - this operation has mainly sense if the value from p is - equal or smaller than that one which is returned from UInt::SetMax() - - it returns a carry if the value 'p' is too big - */ - template - uint FromUInt(const UInt & p) - { - uint min_size = (value_size < argument_size)? value_size : argument_size; - uint i; - - for(i=0 ; i argument_size ) - { - // 'this' is longer than 'p' - - for( ; i)", 1) - return 1; - } - } - - TTMATH_LOGC("UInt::FromUInt(UInt<>)", 0) - - return 0; - } - - - /*! - this method converts an UInt type to this class - - this operation has mainly sense if the value from p is - equal or smaller than that one which is returned from UInt::SetMax() - - it returns a carry if the value 'p' is too big - */ - template - uint FromInt(const UInt & p) - { - return FromUInt(p); - } - - - /*! - this method converts the uint type to this class - */ - uint FromUInt(uint value) - { - for(uint i=1 ; i type to this class - - it doesn't return a carry - */ - template - UInt & operator=(const UInt & p) - { - FromUInt(p); - - return *this; - } - - - /*! - the assignment operator - */ - UInt & operator=(const UInt & p) - { - for(uint i=0 ; i)") - - return *this; - } - - - /*! - this method converts the uint type to this class - */ - UInt & operator=(uint i) - { - FromUInt(i); - - return *this; - } - - - /*! - a constructor for converting the uint to this class - */ - UInt(uint i) - { - FromUInt(i); - } - - - /*! - this method converts the sint type to this class - */ - UInt & operator=(sint i) - { - FromInt(i); - - return *this; - } - - - /*! - a constructor for converting the sint to this class - - look at the description of UInt::operator=(sint) - */ - UInt(sint i) - { - FromInt(i); - } - - -#ifdef TTMATH_PLATFORM32 - - - /*! - this method converts unsigned 64 bit int type to this class - ***this method is created only on a 32bit platform*** - */ - uint FromUInt(ulint n) - { - table[0] = (uint)n; - - if( value_size == 1 ) - { - uint c = ((n >> TTMATH_BITS_PER_UINT) == 0) ? 0 : 1; - - TTMATH_LOGC("UInt::FromUInt(ulint)", c) - return c; - } - - table[1] = (uint)(n >> TTMATH_BITS_PER_UINT); - - for(uint i=2 ; i & operator=(ulint n) - { - FromUInt(n); - - return *this; - } - - - /*! - a constructor for converting unsigned 64 bit int to this class - ***this constructor is created only on a 32bit platform*** - */ - UInt(ulint n) - { - FromUInt(n); - } - - - /*! - this operator converts signed 64 bit int type to this class - ***this operator is created only on a 32bit platform*** - */ - UInt & operator=(slint n) - { - FromInt(n); - - return *this; - } - - - /*! - a constructor for converting signed 64 bit int to this class - ***this constructor is created only on a 32bit platform*** - */ - UInt(slint n) - { - FromInt(n); - } - -#endif - - - -#ifdef TTMATH_PLATFORM64 - - - /*! - this method converts 32 bit unsigned int type to this class - ***this operator is created only on a 64bit platform*** - */ - uint FromUInt(unsigned int i) - { - return FromUInt(uint(i)); - } - - /*! - this method converts 32 bit unsigned int type to this class - ***this operator is created only on a 64bit platform*** - */ - uint FromInt(unsigned int i) - { - return FromUInt(uint(i)); - } - - - /*! - this method converts 32 bit signed int type to this class - ***this operator is created only on a 64bit platform*** - */ - uint FromInt(signed int i) - { - return FromInt(sint(i)); - } - - - /*! - this operator converts 32 bit unsigned int type to this class - ***this operator is created only on a 64bit platform*** - */ - UInt & operator=(unsigned int i) - { - FromUInt(i); - - return *this; - } - - - /*! - a constructor for converting 32 bit unsigned int to this class - ***this constructor is created only on a 64bit platform*** - */ - UInt(unsigned int i) - { - FromUInt(i); - } - - - /*! - an operator for converting 32 bit signed int to this class - ***this constructor is created only on a 64bit platform*** - */ - UInt & operator=(signed int i) - { - FromInt(i); - - return *this; - } - - - /*! - a constructor for converting 32 bit signed int to this class - ***this constructor is created only on a 64bit platform*** - */ - UInt(signed int i) - { - FromInt(i); - } - - -#endif - - - - - - /*! - a constructor for converting a string to this class (with the base=10) - */ - UInt(const char * s) - { - FromString(s); - } - - - /*! - a constructor for converting a string to this class (with the base=10) - */ - UInt(const std::string & s) - { - FromString( s.c_str() ); - } - - -#ifndef TTMATH_DONT_USE_WCHAR - - /*! - a constructor for converting a string to this class (with the base=10) - */ - UInt(const wchar_t * s) - { - FromString(s); - } - - - /*! - a constructor for converting a string to this class (with the base=10) - */ - UInt(const std::wstring & s) - { - FromString( s.c_str() ); - } - -#endif - - - - - /*! - a default constructor - - we don't clear the table - */ - UInt() - { - // when macro TTMATH_DEBUG_LOG is defined - // we set special values to the table - // in order to be everywhere the same value of the UInt object - // without this it would be difficult to analyse the log file - #ifdef TTMATH_DEBUG_LOG - #ifdef TTMATH_PLATFORM32 - for(uint i=0 ; i & u) - { - for(uint i=0 ; i)") - } - - - - /*! - a template for producting constructors for copying from another types - */ - template - UInt(const UInt & u) - { - // look that 'size' we still set as 'value_size' and not as u.value_size - FromUInt(u); - } - - - - - /*! - a destructor - */ - ~UInt() - { - } - - - /*! - this method returns the lowest value from table - - we must be sure when we using this method whether the value - will hold in an uint type or not (the rest value from the table must be zero) - */ - uint ToUInt() const - { - return table[0]; - } - - - /*! - this method converts the value to uint type - can return a carry if the value is too long to store it in uint type - */ - uint ToUInt(uint & result) const - { - result = table[0]; - - for(uint i=1 ; i> 32) != 0 ) - return 1; - - for(uint i=1 ; i - */ - double ToStringLog2(uint x) const - { - static double log_tab[] = { - 1.000000000000000000, - 0.630929753571457437, - 0.500000000000000000, - 0.430676558073393050, - 0.386852807234541586, - 0.356207187108022176, - 0.333333333333333333, - 0.315464876785728718, - 0.301029995663981195, - 0.289064826317887859, - 0.278942945651129843, - 0.270238154427319741, - 0.262649535037193547, - 0.255958024809815489, - 0.250000000000000000 - }; - - if( x<2 || x>16 ) - return 0; - - return log_tab[x-2]; - } - - -public: - - - /*! - an auxiliary method for converting to a string - it's used from Int::ToString() too (negative is set true then) - */ - template - void ToStringBase(string_type & result, uint b = 10, bool negative = false) const - { - UInt temp(*this); - uint rest, table_id, index, digits; - double digits_d; - char character; - - result.clear(); - - if( b<2 || b>16 ) - return; - - if( !FindLeadingBit(table_id, index) ) - { - result = '0'; - return; - } - - if( negative ) - result = '-'; - - digits_d = static_cast(table_id); // for not making an overflow in uint type - digits_d *= TTMATH_BITS_PER_UINT; - digits_d += index + 1; - digits_d *= ToStringLog2(b); - digits = static_cast(digits_d) + 3; // plus some epsilon - - if( result.capacity() < digits ) - result.reserve(digits); - - do - { - temp.DivInt(b, &rest); - character = static_cast(Misc::DigitToChar(rest)); - result.insert(result.end(), character); - } - while( !temp.IsZero() ); - - size_t i1 = negative ? 1 : 0; // the first is a hyphen (when negative is true) - size_t i2 = result.size() - 1; - - for( ; i1 < i2 ; ++i1, --i2 ) - { - char tempc = static_cast(result[i1]); - result[i1] = result[i2]; - result[i2] = tempc; - } - } - - - - /*! - this method converts the value to a string with a base equal 'b' - */ - void ToString(std::string & result, uint b = 10) const - { - return ToStringBase(result, b); - } - - - std::string ToString(uint b = 10) const - { - std::string result; - ToStringBase(result, b); - - return result; - } - - -#ifndef TTMATH_DONT_USE_WCHAR - - void ToString(std::wstring & result, uint b = 10) const - { - return ToStringBase(result, b); - } - - std::wstring ToWString(uint b = 10) const - { - std::wstring result; - ToStringBase(result, b); - - return result; - } - -#endif - - - -private: - - /*! - an auxiliary method for converting from a string - */ - template - uint FromStringBase(const char_type * s, uint b = 10, const char_type ** after_source = 0, bool * value_read = 0) - { - UInt base( b ); - UInt temp; - sint z; - uint c = 0; - - SetZero(); - temp.SetZero(); - Misc::SkipWhiteCharacters(s); - - if( after_source ) - *after_source = s; - - if( value_read ) - *value_read = false; - - if( b<2 || b>16 ) - return 1; - - - for( ; (z=Misc::CharToDigit(*s, b)) != -1 ; ++s) - { - if( value_read ) - *value_read = true; - - if( c == 0 ) - { - temp.table[0] = z; - - c += Mul(base); // !! IMPROVE ME: there can be used MulInt here - c += Add(temp); - } - } - - if( after_source ) - *after_source = s; - - TTMATH_LOGC("UInt::FromString", c) - - return (c==0)? 0 : 1; - } - - -public: - - - /*! - this method converts a string into its value - it returns carry=1 if the value will be too big or an incorrect base 'b' is given - - string is ended with a non-digit value, for example: - "12" will be translated to 12 - as well as: - "12foo" will be translated to 12 too - - existing first white characters will be ommited - - if the value from s is too large the rest digits will be skipped - - after_source (if exists) is pointing at the end of the parsed string - - value_read (if exists) tells whether something has actually been read (at least one digit) - */ - uint FromString(const char * s, uint b = 10, const char ** after_source = 0, bool * value_read = 0) - { - return FromStringBase(s, b, after_source, value_read); - } - - - /*! - this method converts a string into its value - - (it returns carry=1 if the value will be too big or an incorrect base 'b' is given) - */ - uint FromString(const std::string & s, uint b = 10) - { - return FromString( s.c_str(), b ); - } - - - /*! - this operator converts a string into its value (with base = 10) - */ - UInt & operator=(const char * s) - { - FromString(s); - - return *this; - } - - - /*! - this operator converts a string into its value (with base = 10) - */ - UInt & operator=(const std::string & s) - { - FromString( s.c_str() ); - - return *this; - } - - - -#ifndef TTMATH_DONT_USE_WCHAR - - /*! - this method converts a string into its value - */ - uint FromString(const wchar_t * s, uint b = 10, const wchar_t ** after_source = 0, bool * value_read = 0) - { - return FromStringBase(s, b, after_source, value_read); - } - - - /*! - this method converts a string into its value - - (it returns carry=1 if the value will be too big or an incorrect base 'b' is given) - */ - uint FromString(const std::wstring & s, uint b = 10) - { - return FromString( s.c_str(), b ); - } - - - /*! - this operator converts a string into its value (with base = 10) - */ - UInt & operator=(const wchar_t * s) - { - FromString(s); - - return *this; - } - - - /*! - this operator converts a string into its value (with base = 10) - */ - UInt & operator=(const std::wstring & s) - { - FromString( s.c_str() ); - - return *this; - } - -#endif - - - /*! - * - * methods for comparing - * - */ - - - /*! - this method returns true if 'this' is smaller than 'l' - - 'index' is an index of the first word from will be the comparison performed - (note: we start the comparison from back - from the last word, when index is -1 /default/ - it is automatically set into the last word) - I introduced it for some kind of optimization made in the second division algorithm (Div2) - */ - bool CmpSmaller(const UInt & l, sint index = -1) const - { - sint i; - - if( index==-1 || index>=sint(value_size) ) - i = value_size - 1; - else - i = index; - - - for( ; i>=0 ; --i) - { - if( table[i] != l.table[i] ) - return table[i] < l.table[i]; - } - - // they're equal - return false; - } - - - - /*! - this method returns true if 'this' is bigger than 'l' - - 'index' is an index of the first word from will be the comparison performed - (note: we start the comparison from back - from the last word, when index is -1 /default/ - it is automatically set into the last word) - - I introduced it for some kind of optimization made in the second division algorithm (Div2) - */ - bool CmpBigger(const UInt & l, sint index = -1) const - { - sint i; - - if( index==-1 || index>=sint(value_size) ) - i = value_size - 1; - else - i = index; - - - for( ; i>=0 ; --i) - { - if( table[i] != l.table[i] ) - return table[i] > l.table[i]; - } - - // they're equal - return false; - } - - - /*! - this method returns true if 'this' is equal 'l' - - 'index' is an index of the first word from will be the comparison performed - (note: we start the comparison from back - from the last word, when index is -1 /default/ - it is automatically set into the last word) - */ - bool CmpEqual(const UInt & l, sint index = -1) const - { - sint i; - - if( index==-1 || index>=sint(value_size) ) - i = value_size - 1; - else - i = index; - - - for( ; i>=0 ; --i) - if( table[i] != l.table[i] ) - return false; - - return true; - } - - - - /*! - this method returns true if 'this' is smaller than or equal 'l' - - 'index' is an index of the first word from will be the comparison performed - (note: we start the comparison from back - from the last word, when index is -1 /default/ - it is automatically set into the last word) - */ - bool CmpSmallerEqual(const UInt & l, sint index=-1) const - { - sint i; - - if( index==-1 || index>=sint(value_size) ) - i = value_size - 1; - else - i = index; - - - for( ; i>=0 ; --i) - { - if( table[i] != l.table[i] ) - return table[i] < l.table[i]; - } - - // they're equal - return true; - } - - - - /*! - this method returns true if 'this' is bigger than or equal 'l' - - 'index' is an index of the first word from will be the comparison performed - (note: we start the comparison from back - from the last word, when index is -1 /default/ - it is automatically set into the last word) - */ - bool CmpBiggerEqual(const UInt & l, sint index=-1) const - { - sint i; - - if( index==-1 || index>=sint(value_size) ) - i = value_size - 1; - else - i = index; - - - for( ; i>=0 ; --i) - { - if( table[i] != l.table[i] ) - return table[i] > l.table[i]; - } - - // they're equal - return true; - } - - - /* - operators for comparising - */ - - bool operator<(const UInt & l) const - { - return CmpSmaller(l); - } - - - bool operator>(const UInt & l) const - { - return CmpBigger(l); - } - - - bool operator==(const UInt & l) const - { - return CmpEqual(l); - } - - - bool operator!=(const UInt & l) const - { - return !operator==(l); - } - - - bool operator<=(const UInt & l) const - { - return CmpSmallerEqual(l); - } - - bool operator>=(const UInt & l) const - { - return CmpBiggerEqual(l); - } - - - /*! - * - * standard mathematical operators - * - */ - - UInt operator-(const UInt & p2) const - { - UInt temp(*this); - - temp.Sub(p2); - - return temp; - } - - UInt & operator-=(const UInt & p2) - { - Sub(p2); - - return *this; - } - - UInt operator+(const UInt & p2) const - { - UInt temp(*this); - - temp.Add(p2); - - return temp; - } - - UInt & operator+=(const UInt & p2) - { - Add(p2); - - return *this; - } - - - UInt operator*(const UInt & p2) const - { - UInt temp(*this); - - temp.Mul(p2); - - return temp; - } - - - UInt & operator*=(const UInt & p2) - { - Mul(p2); - - return *this; - } - - - UInt operator/(const UInt & p2) const - { - UInt temp(*this); - - temp.Div(p2); - - return temp; - } - - - UInt & operator/=(const UInt & p2) - { - Div(p2); - - return *this; - } - - - UInt operator%(const UInt & p2) const - { - UInt temp(*this); - UInt remainder; - - temp.Div( p2, remainder ); - - return remainder; - } - - - UInt & operator%=(const UInt & p2) - { - UInt remainder; - - Div( p2, remainder ); - operator=(remainder); - - return *this; - } - - - /*! - Prefix operator e.g ++variable - */ - UInt & operator++() - { - AddOne(); - - return *this; - } - - - /*! - Postfix operator e.g variable++ - */ - UInt operator++(int) - { - UInt temp( *this ); - - AddOne(); - - return temp; - } - - - UInt & operator--() - { - SubOne(); - - return *this; - } - - - UInt operator--(int) - { - UInt temp( *this ); - - SubOne(); - - return temp; - } - - - - /*! - * - * bitwise operators - * - */ - - UInt operator~() const - { - UInt temp( *this ); - - temp.BitNot(); - - return temp; - } - - - UInt operator&(const UInt & p2) const - { - UInt temp( *this ); - - temp.BitAnd(p2); - - return temp; - } - - - UInt & operator&=(const UInt & p2) - { - BitAnd(p2); - - return *this; - } - - - UInt operator|(const UInt & p2) const - { - UInt temp( *this ); - - temp.BitOr(p2); - - return temp; - } - - - UInt & operator|=(const UInt & p2) - { - BitOr(p2); - - return *this; - } - - - UInt operator^(const UInt & p2) const - { - UInt temp( *this ); - - temp.BitXor(p2); - - return temp; - } - - - UInt & operator^=(const UInt & p2) - { - BitXor(p2); - - return *this; - } - - - UInt operator>>(int move) const - { - UInt temp( *this ); - - temp.Rcr(move); - - return temp; - } - - - UInt & operator>>=(int move) - { - Rcr(move); - - return *this; - } - - - UInt operator<<(int move) const - { - UInt temp( *this ); - - temp.Rcl(move); - - return temp; - } - - - UInt & operator<<=(int move) - { - Rcl(move); - - return *this; - } - - - /*! - * - * input/output operators for standard streams - * - * (they are very simple, in the future they should be changed) - * - */ - - -private: - - - /*! - an auxiliary method for outputing to standard streams - */ - template - static ostream_type & OutputToStream(ostream_type & s, const UInt & l) - { - string_type ss; - - l.ToString(ss); - s << ss; - - return s; - } - - -public: - - - /*! - output to standard streams - */ - friend std::ostream & operator<<(std::ostream & s, const UInt & l) - { - return OutputToStream(s, l); - } - - -#ifndef TTMATH_DONT_USE_WCHAR - - /*! - output to standard streams - */ - friend std::wostream & operator<<(std::wostream & s, const UInt & l) - { - return OutputToStream(s, l); - } - -#endif - - - -private: - - /*! - an auxiliary method for reading from standard streams - */ - template - static istream_type & InputFromStream(istream_type & s, UInt & l) - { - string_type ss; - - // char or wchar_t for operator>> - char_type z; - - // operator>> omits white characters if they're set for ommiting - s >> z; - - // we're reading only digits (base=10) - while( s.good() && Misc::CharToDigit(z, 10)>=0 ) - { - ss += z; - z = static_cast(s.get()); - } - - // we're leaving the last read character - // (it's not belonging to the value) - s.unget(); - - l.FromString(ss); - - return s; - } - -public: - - - /*! - input from standard streams - */ - friend std::istream & operator>>(std::istream & s, UInt & l) - { - return InputFromStream(s, l); - } - - -#ifndef TTMATH_DONT_USE_WCHAR - - /*! - input from standard streams - */ - friend std::wistream & operator>>(std::wistream & s, UInt & l) - { - return InputFromStream(s, l); - } - -#endif - - - /* - Following methods are defined in: - ttmathuint_x86.h - ttmathuint_x86_64.h - ttmathuint_noasm.h - */ - -#ifdef TTMATH_NOASM - static uint AddTwoWords(uint a, uint b, uint carry, uint * result); - static uint SubTwoWords(uint a, uint b, uint carry, uint * result); - -#ifdef TTMATH_PLATFORM64 - - union uint_ - { - struct - { - unsigned int low; // 32 bit - unsigned int high; // 32 bit - } u_; - - uint u; // 64 bit - }; - - - static void DivTwoWords2(uint a,uint b, uint c, uint * r, uint * rest); - static uint DivTwoWordsNormalize(uint_ & a_, uint_ & b_, uint_ & c_); - static uint DivTwoWordsUnnormalize(uint u, uint d); - static unsigned int DivTwoWordsCalculate(uint_ u_, unsigned int u3, uint_ v_); - static void MultiplySubtract(uint_ & u_, unsigned int & u3, unsigned int & q, uint_ v_); - -#endif // TTMATH_PLATFORM64 -#endif // TTMATH_NOASM - - -private: - uint Rcl2_one(uint c); - uint Rcr2_one(uint c); - uint Rcl2(uint bits, uint c); - uint Rcr2(uint bits, uint c); - -public: - static const char * LibTypeStr(); - static LibTypeCode LibType(); - uint Add(const UInt & ss2, uint c=0); - uint AddInt(uint value, uint index = 0); - uint AddTwoInts(uint x2, uint x1, uint index); - static uint AddVector(const uint * ss1, const uint * ss2, uint ss1_size, uint ss2_size, uint * result); - uint Sub(const UInt & ss2, uint c=0); - uint SubInt(uint value, uint index = 0); - static uint SubVector(const uint * ss1, const uint * ss2, uint ss1_size, uint ss2_size, uint * result); - static sint FindLeadingBitInWord(uint x); - static sint FindLowestBitInWord(uint x); - static uint SetBitInWord(uint & value, uint bit); - static void MulTwoWords(uint a, uint b, uint * result_high, uint * result_low); - static void DivTwoWords(uint a,uint b, uint c, uint * r, uint * rest); - -}; - - - -/*! - this specialization is needed in order to not confuse the compiler "error: ISO C++ forbids zero-size array" - when compiling Mul3Big2() method -*/ -template<> -class UInt<0> -{ -public: - uint table[1]; - - void Mul2Big(const UInt<0> &, UInt<0> &) { TTMATH_ASSERT(false) }; - void SetZero() { TTMATH_ASSERT(false) }; - uint AddTwoInts(uint, uint, uint) { TTMATH_ASSERT(false) return 0; }; -}; - - -} //namespace - - -#include "ttmathuint_x86.h" -#include "ttmathuint_x86_64.h" -#include "ttmathuint_noasm.h" - -#endif diff --git a/include/geos/algorithm/ttmath/ttmathuint_noasm.h b/include/geos/algorithm/ttmath/ttmathuint_noasm.h deleted file mode 100644 index 96ab494c2f..0000000000 --- a/include/geos/algorithm/ttmath/ttmathuint_noasm.h +++ /dev/null @@ -1,1038 +0,0 @@ -/* - * This file is a part of TTMath Bignum Library - * and is distributed under the 3-Clause BSD Licence. - * Author: Tomasz Sowa - */ - -/* - * Copyright (c) 2006-2010, Tomasz Sowa - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * * Neither the name Tomasz Sowa nor the names of contributors to this - * project may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef headerfilettmathuint_noasm -#define headerfilettmathuint_noasm - - -/*! - \file ttmathuint_noasm.h - \brief template class UInt with methods without any assembler code (used for no-asm version of ttmath) - - this file is included at the end of ttmathuint.h -*/ - -#ifdef TTMATH_NOASM - - - -namespace ttmath -{ - - /*! - returning the string represents the currect type of the library - we have following types: - - asm_vc_32 - with asm code designed for Microsoft Visual C++ (32 bits) - - asm_gcc_32 - with asm code designed for GCC (32 bits) - - asm_vc_64 - with asm for VC (64 bit) - - asm_gcc_64 - with asm for GCC (64 bit) - - no_asm_32 - pure C++ version (32 bit) - without any asm code - - no_asm_64 - pure C++ version (64 bit) - without any asm code - */ - template - const char * UInt::LibTypeStr() - { - #ifdef TTMATH_PLATFORM32 - static const char info[] = "no_asm_32"; - #endif - - #ifdef TTMATH_PLATFORM64 - static const char info[] = "no_asm_64"; - #endif - - return info; - } - - - /*! - returning the currect type of the library - */ - template - LibTypeCode UInt::LibType() - { - #ifdef TTMATH_PLATFORM32 - LibTypeCode info = no_asm_32; - #endif - - #ifdef TTMATH_PLATFORM64 - LibTypeCode info = no_asm_64; - #endif - - return info; - } - - - /*! - this method adds two words together - returns carry - - this method is created only when TTMATH_NOASM macro is defined - */ - template - uint UInt::AddTwoWords(uint a, uint b, uint carry, uint * result) - { - uint temp; - - if( carry == 0 ) - { - temp = a + b; - - if( temp < a ) - carry = 1; - } - else - { - carry = 1; - temp = a + b + carry; - - if( temp > a ) // !(temp<=a) - carry = 0; - } - - *result = temp; - - return carry; - } - - - - /*! - this method adding ss2 to the this and adding carry if it's defined - (this = this + ss2 + c) - - c must be zero or one (might be a bigger value than 1) - function returns carry (1) (if it was) - */ - - template - uint UInt::Add(const UInt & ss2, uint c) - { - uint i; - - for(i=0 ; i - uint UInt::AddInt(uint value, uint index) - { - uint i, c; - - TTMATH_ASSERT( index < value_size ) - - - c = AddTwoWords(table[index], value, 0, &table[index]); - - for(i=index+1 ; i - uint UInt::AddTwoInts(uint x2, uint x1, uint index) - { - uint i, c; - - TTMATH_ASSERT( index < value_size - 1 ) - - - c = AddTwoWords(table[index], x1, 0, &table[index]); - c = AddTwoWords(table[index+1], x2, c, &table[index+1]); - - for(i=index+2 ; i - uint UInt::AddVector(const uint * ss1, const uint * ss2, uint ss1_size, uint ss2_size, uint * result) - { - uint i, c = 0; - - TTMATH_ASSERT( ss1_size >= ss2_size ) - - for(i=0 ; i - uint UInt::SubTwoWords(uint a, uint b, uint carry, uint * result) - { - if( carry == 0 ) - { - *result = a - b; - - if( a < b ) - carry = 1; - } - else - { - carry = 1; - *result = a - b - carry; - - if( a > b ) // !(a <= b ) - carry = 0; - } - - return carry; - } - - - - - /*! - this method's subtracting ss2 from the 'this' and subtracting - carry if it has been defined - (this = this - ss2 - c) - - c must be zero or one (might be a bigger value than 1) - function returns carry (1) (if it was) - */ - template - uint UInt::Sub(const UInt & ss2, uint c) - { - uint i; - - for(i=0 ; i - uint UInt::SubInt(uint value, uint index) - { - uint i, c; - - TTMATH_ASSERT( index < value_size ) - - - c = SubTwoWords(table[index], value, 0, &table[index]); - - for(i=index+1 ; i - uint UInt::SubVector(const uint * ss1, const uint * ss2, uint ss1_size, uint ss2_size, uint * result) - { - uint i, c = 0; - - TTMATH_ASSERT( ss1_size >= ss2_size ) - - for(i=0 ; i - uint UInt::Rcl2_one(uint c) - { - uint i, new_c; - - if( c != 0 ) - c = 1; - - for(i=0 ; i this -> return value - - the highest *bit* will be held the 'c' and - the state of one additional bit (on the right hand side) - will be returned - - for example: - let this is 000000010 - after Rcr2_one(1) there'll be 100000001 and Rcr2_one returns 0 - */ - template - uint UInt::Rcr2_one(uint c) - { - sint i; // signed i - uint new_c; - - if( c != 0 ) - c = TTMATH_UINT_HIGHEST_BIT; - - for(i=sint(value_size)-1 ; i>=0 ; --i) - { - new_c = (table[i] & 1) ? TTMATH_UINT_HIGHEST_BIT : 0; - table[i] = (table[i] >> 1) | c; - c = new_c; - } - - c = (c != 0)? 1 : 0; - - TTMATH_LOGC("UInt::Rcr2_one", c) - - return c; - } - - - - - /*! - this method moves all bits into the left hand side - return value <- this <- c - - the lowest *bits* will be held the 'c' and - the state of one additional bit (on the left hand side) - will be returned - - for example: - let this is 001010000 - after Rcl2(3, 1) there'll be 010000111 and Rcl2 returns 1 - */ - template - uint UInt::Rcl2(uint bits, uint c) - { - TTMATH_ASSERT( bits>0 && bits> move; - - for(i=0 ; i> move; - table[i] = (table[i] << bits) | c; - c = new_c; - } - - TTMATH_LOGC("UInt::Rcl2", (c & 1)) - - return (c & 1); - } - - - - - /*! - this method moves all bits into the right hand side - C -> this -> return value - - the highest *bits* will be held the 'c' and - the state of one additional bit (on the right hand side) - will be returned - - for example: - let this is 000000010 - after Rcr2(2, 1) there'll be 110000000 and Rcr2 returns 1 - */ - template - uint UInt::Rcr2(uint bits, uint c) - { - TTMATH_ASSERT( bits>0 && bits=0 ; --i) - { - new_c = table[i] << move; - table[i] = (table[i] >> bits) | c; - c = new_c; - } - - c = (c & TTMATH_UINT_HIGHEST_BIT) ? 1 : 0; - - TTMATH_LOGC("UInt::Rcr2", c) - - return c; - } - - - - - /*! - this method returns the number of the highest set bit in x - if the 'x' is zero this method returns '-1' - */ - template - sint UInt::FindLeadingBitInWord(uint x) - { - if( x == 0 ) - return -1; - - uint bit = TTMATH_BITS_PER_UINT - 1; - - while( (x & TTMATH_UINT_HIGHEST_BIT) == 0 ) - { - x = x << 1; - --bit; - } - - return bit; - } - - - - /*! - this method returns the number of the highest set bit in x - if the 'x' is zero this method returns '-1' - */ - template - sint UInt::FindLowestBitInWord(uint x) - { - if( x == 0 ) - return -1; - - uint bit = 0; - - while( (x & 1) == 0 ) - { - x = x >> 1; - ++bit; - } - - return bit; - } - - - - /*! - this method sets a special bit in the 'value' - and returns the last state of the bit (zero or one) - - bit is from <0,TTMATH_BITS_PER_UINT-1> - - e.g. - - uint x = 100; - uint bit = SetBitInWord(x, 3); - - now: x = 108 and bit = 0 - */ - template - uint UInt::SetBitInWord(uint & value, uint bit) - { - TTMATH_ASSERT( bit < TTMATH_BITS_PER_UINT ) - - uint mask = 1; - - if( bit > 0 ) - mask = mask << bit; - - uint last = value & mask; - value = value | mask; - - return (last != 0) ? 1 : 0; - } - - - - - - - /*! - * - * Multiplication - * - * - */ - - - /*! - multiplication: result_high:result_low = a * b - - result_high - higher word of the result - - result_low - lower word of the result - - this methos never returns a carry - - this method is used in the second version of the multiplication algorithms - */ - template - void UInt::MulTwoWords(uint a, uint b, uint * result_high, uint * result_low) - { - #ifdef TTMATH_PLATFORM32 - - /* - on 32bit platforms we have defined 'unsigned long long int' type known as 'ulint' in ttmath namespace - this type has 64 bits, then we're using only one multiplication: 32bit * 32bit = 64bit - */ - - union uint_ - { - struct - { - uint low; // 32 bits - uint high; // 32 bits - } u_; - - ulint u; // 64 bits - } res; - - res.u = ulint(a) * ulint(b); // multiply two 32bit words, the result has 64 bits - - *result_high = res.u_.high; - *result_low = res.u_.low; - - #else - - /* - 64 bits platforms - - we don't have a native type which has 128 bits - then we're splitting 'a' and 'b' to 4 parts (high and low halves) - and using 4 multiplications (with additions and carry correctness) - */ - - uint_ a_; - uint_ b_; - uint_ res_high1, res_high2; - uint_ res_low1, res_low2; - - a_.u = a; - b_.u = b; - - /* - the multiplication is as follows (schoolbook algorithm with O(n^2) ): - - 32 bits 32 bits - - +--------------------------------+ - | a_.u_.high | a_.u_.low | - +--------------------------------+ - | b_.u_.high | b_.u_.low | - +--------------------------------+--------------------------------+ - | res_high1.u | res_low1.u | - +--------------------------------+--------------------------------+ - | res_high2.u | res_low2.u | - +--------------------------------+--------------------------------+ - - 64 bits 64 bits - */ - - - uint_ temp; - - res_low1.u = uint(b_.u_.low) * uint(a_.u_.low); - - temp.u = uint(res_low1.u_.high) + uint(b_.u_.low) * uint(a_.u_.high); - res_low1.u_.high = temp.u_.low; - res_high1.u_.low = temp.u_.high; - res_high1.u_.high = 0; - - res_low2.u_.low = 0; - temp.u = uint(b_.u_.high) * uint(a_.u_.low); - res_low2.u_.high = temp.u_.low; - - res_high2.u = uint(b_.u_.high) * uint(a_.u_.high) + uint(temp.u_.high); - - uint c = AddTwoWords(res_low1.u, res_low2.u, 0, &res_low2.u); - AddTwoWords(res_high1.u, res_high2.u, c, &res_high2.u); // there is no carry from here - - *result_high = res_high2.u; - *result_low = res_low2.u; - - #endif - } - - - - - /*! - * - * Division - * - * - */ - - - /*! - this method calculates 64bits word a:b / 32bits c (a higher, b lower word) - r = a:b / c and rest - remainder - - * - * WARNING: - * the c has to be suitably large for the result being keeped in one word, - * if c is equal zero there'll be a hardware interruption (0) - * and probably the end of your program - * - */ - template - void UInt::DivTwoWords(uint a, uint b, uint c, uint * r, uint * rest) - { - // (a < c ) for the result to be one word - TTMATH_ASSERT( c != 0 && a < c ) - - #ifdef TTMATH_PLATFORM32 - - union - { - struct - { - uint low; // 32 bits - uint high; // 32 bits - } u_; - - ulint u; // 64 bits - } ab; - - ab.u_.high = a; - ab.u_.low = b; - - *r = uint(ab.u / c); - *rest = uint(ab.u % c); - - #else - - uint_ c_; - c_.u = c; - - - if( a == 0 ) - { - *r = b / c; - *rest = b % c; - } - else - if( c_.u_.high == 0 ) - { - // higher half of 'c' is zero - // then higher half of 'a' is zero too (look at the asserts at the beginning - 'a' is smaller than 'c') - uint_ a_, b_, res_, temp1, temp2; - - a_.u = a; - b_.u = b; - - temp1.u_.high = a_.u_.low; - temp1.u_.low = b_.u_.high; - - res_.u_.high = (unsigned int)(temp1.u / c); - temp2.u_.high = (unsigned int)(temp1.u % c); - temp2.u_.low = b_.u_.low; - - res_.u_.low = (unsigned int)(temp2.u / c); - *rest = temp2.u % c; - - *r = res_.u; - } - else - { - return DivTwoWords2(a, b, c, r, rest); - } - - #endif - } - - -#ifdef TTMATH_PLATFORM64 - - - /*! - this method is available only on 64bit platforms - - the same algorithm like the third division algorithm in ttmathuint.h - but now with the radix=2^32 - */ - template - void UInt::DivTwoWords2(uint a, uint b, uint c, uint * r, uint * rest) - { - // a is not zero - // c_.u_.high is not zero - - uint_ a_, b_, c_, u_, q_; - unsigned int u3; // 32 bit - - a_.u = a; - b_.u = b; - c_.u = c; - - // normalizing - uint d = DivTwoWordsNormalize(a_, b_, c_); - - // loop from j=1 to j=0 - // the first step (for j=2) is skipped because our result is only in one word, - // (first 'q' were 0 and nothing would be changed) - u_.u_.high = a_.u_.high; - u_.u_.low = a_.u_.low; - u3 = b_.u_.high; - q_.u_.high = DivTwoWordsCalculate(u_, u3, c_); - MultiplySubtract(u_, u3, q_.u_.high, c_); - - u_.u_.high = u_.u_.low; - u_.u_.low = u3; - u3 = b_.u_.low; - q_.u_.low = DivTwoWordsCalculate(u_, u3, c_); - MultiplySubtract(u_, u3, q_.u_.low, c_); - - *r = q_.u; - - // unnormalizing for the remainder - u_.u_.high = u_.u_.low; - u_.u_.low = u3; - *rest = DivTwoWordsUnnormalize(u_.u, d); - } - - - - - template - uint UInt::DivTwoWordsNormalize(uint_ & a_, uint_ & b_, uint_ & c_) - { - uint d = 0; - - for( ; (c_.u & TTMATH_UINT_HIGHEST_BIT) == 0 ; ++d ) - { - c_.u = c_.u << 1; - - uint bc = b_.u & TTMATH_UINT_HIGHEST_BIT; // carry from 'b' - - b_.u = b_.u << 1; - a_.u = a_.u << 1; // carry bits from 'a' are simply skipped - - if( bc ) - a_.u = a_.u | 1; - } - - return d; - } - - - template - uint UInt::DivTwoWordsUnnormalize(uint u, uint d) - { - if( d == 0 ) - return u; - - u = u >> d; - - return u; - } - - - template - unsigned int UInt::DivTwoWordsCalculate(uint_ u_, unsigned int u3, uint_ v_) - { - bool next_test; - uint_ qp_, rp_, temp_; - - qp_.u = u_.u / uint(v_.u_.high); - rp_.u = u_.u % uint(v_.u_.high); - - TTMATH_ASSERT( qp_.u_.high==0 || qp_.u_.high==1 ) - - do - { - bool decrease = false; - - if( qp_.u_.high == 1 ) - decrease = true; - else - { - temp_.u_.high = rp_.u_.low; - temp_.u_.low = u3; - - if( qp_.u * uint(v_.u_.low) > temp_.u ) - decrease = true; - } - - next_test = false; - - if( decrease ) - { - --qp_.u; - rp_.u += v_.u_.high; - - if( rp_.u_.high == 0 ) - next_test = true; - } - } - while( next_test ); - - return qp_.u_.low; - } - - - template - void UInt::MultiplySubtract(uint_ & u_, unsigned int & u3, unsigned int & q, uint_ v_) - { - uint_ temp_; - - uint res_high; - uint res_low; - - MulTwoWords(v_.u, q, &res_high, &res_low); - - uint_ sub_res_high_; - uint_ sub_res_low_; - - temp_.u_.high = u_.u_.low; - temp_.u_.low = u3; - - uint c = SubTwoWords(temp_.u, res_low, 0, &sub_res_low_.u); - - temp_.u_.high = 0; - temp_.u_.low = u_.u_.high; - c = SubTwoWords(temp_.u, res_high, c, &sub_res_high_.u); - - if( c ) - { - --q; - - c = AddTwoWords(sub_res_low_.u, v_.u, 0, &sub_res_low_.u); - AddTwoWords(sub_res_high_.u, 0, c, &sub_res_high_.u); - } - - u_.u_.high = sub_res_high_.u_.low; - u_.u_.low = sub_res_low_.u_.high; - u3 = sub_res_low_.u_.low; - } - -#endif // #ifdef TTMATH_PLATFORM64 - - - -} //namespace - - -#endif //ifdef TTMATH_NOASM -#endif - - - - diff --git a/include/geos/algorithm/ttmath/ttmathuint_x86.h b/include/geos/algorithm/ttmath/ttmathuint_x86.h deleted file mode 100644 index 811b2256a6..0000000000 --- a/include/geos/algorithm/ttmath/ttmathuint_x86.h +++ /dev/null @@ -1,1620 +0,0 @@ -/* - * This file is a part of TTMath Bignum Library - * and is distributed under the 3-Clause BSD Licence. - * Author: Tomasz Sowa - */ - -/* - * Copyright (c) 2006-2009, Tomasz Sowa - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * * Neither the name Tomasz Sowa nor the names of contributors to this - * project may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef headerfilettmathuint_x86 -#define headerfilettmathuint_x86 - - -/*! - \file ttmathuint_x86.h - \brief template class UInt with assembler code for 32bit x86 processors - - this file is included at the end of ttmathuint.h -*/ - - -#ifndef TTMATH_NOASM -#ifdef TTMATH_PLATFORM32 - - - - - -/*! - \brief a namespace for the TTMath library -*/ -namespace ttmath -{ - - /*! - returning the string represents the currect type of the library - - we have following types: - - asm_vc_32 - with asm code designed for Microsoft Visual C++ (32 bits) - - asm_gcc_32 - with asm code designed for GCC (32 bits) - - asm_vc_64 - with asm for VC (64 bit) - - asm_gcc_64 - with asm for GCC (64 bit) - - no_asm_32 - pure C++ version (32 bit) - without any asm code - - no_asm_64 - pure C++ version (64 bit) - without any asm code - */ - template - const char * UInt::LibTypeStr() - { - #ifndef __GNUC__ - static const char info[] = "asm_vc_32"; - #endif - - #ifdef __GNUC__ - static const char info[] = "asm_gcc_32"; - #endif - - return info; - } - - - /*! - returning the currect type of the library - */ - template - LibTypeCode UInt::LibType() - { - #ifndef __GNUC__ - LibTypeCode info = asm_vc_32; - #endif - - #ifdef __GNUC__ - LibTypeCode info = asm_gcc_32; - #endif - - return info; - } - - - - /*! - * - * basic mathematic functions - * - */ - - - /*! - adding ss2 to the this and adding carry if it's defined - (this = this + ss2 + c) - - c must be zero or one (might be a bigger value than 1) - function returns carry (1) (if it has been) - */ - template - uint UInt::Add(const UInt & ss2, uint c) - { - uint b = value_size; - uint * p1 = table; - uint * p2 = const_cast(ss2.table); - - // we don't have to use TTMATH_REFERENCE_ASSERT here - // this algorithm doesn't require it - - #ifndef __GNUC__ - - // this part might be compiled with for example visual c - - __asm - { - push eax - push ebx - push ecx - push edx - push esi - - mov ecx,[b] - - mov ebx,[p1] - mov esi,[p2] - - xor edx,edx // edx=0 - mov eax,[c] - neg eax // CF=1 if rax!=0 , CF=0 if rax==0 - - ttmath_loop: - mov eax,[esi+edx*4] - adc [ebx+edx*4],eax - - inc edx - dec ecx - jnz ttmath_loop - - adc ecx, ecx - mov [c], ecx - - pop esi - pop edx - pop ecx - pop ebx - pop eax - } - - - - #endif - - - #ifdef __GNUC__ - uint dummy, dummy2; - // this part should be compiled with gcc - - __asm__ __volatile__( - - "xorl %%edx, %%edx \n" - "negl %%eax \n" // CF=1 if rax!=0 , CF=0 if rax==0 - - "1: \n" - "movl (%%esi,%%edx,4), %%eax \n" - "adcl %%eax, (%%ebx,%%edx,4) \n" - - "incl %%edx \n" - "decl %%ecx \n" - "jnz 1b \n" - - "adc %%ecx, %%ecx \n" - - : "=c" (c), "=a" (dummy), "=d" (dummy2) - : "0" (b), "1" (c), "b" (p1), "S" (p2) - : "cc", "memory" ); - #endif - - TTMATH_LOGC("UInt::Add", c) - - return c; - } - - - - /*! - adding one word (at a specific position) - and returning a carry (if it has been) - - e.g. - - if we've got (value_size=3): - - table[0] = 10; - table[1] = 30; - table[2] = 5; - - and we call: - - AddInt(2,1) - - then it'll be: - - table[0] = 10; - table[1] = 30 + 2; - table[2] = 5; - - of course if there was a carry from table[2] it would be returned - */ - template - uint UInt::AddInt(uint value, uint index) - { - uint b = value_size; - uint * p1 = table; - uint c; - - TTMATH_ASSERT( index < value_size ) - - #ifndef __GNUC__ - - __asm - { - push eax - push ebx - push ecx - push edx - - mov ecx, [b] - sub ecx, [index] - - mov edx, [index] - mov ebx, [p1] - - mov eax, [value] - - ttmath_loop: - add [ebx+edx*4], eax - jnc ttmath_end - - mov eax, 1 - inc edx - dec ecx - jnz ttmath_loop - - ttmath_end: - setc al - movzx edx, al - mov [c], edx - - pop edx - pop ecx - pop ebx - pop eax - } - - #endif - - - #ifdef __GNUC__ - uint dummy, dummy2; - - __asm__ __volatile__( - - "subl %%edx, %%ecx \n" - - "1: \n" - "addl %%eax, (%%ebx,%%edx,4) \n" - "jnc 2f \n" - - "movl $1, %%eax \n" - "incl %%edx \n" - "decl %%ecx \n" - "jnz 1b \n" - - "2: \n" - "setc %%al \n" - "movzx %%al, %%edx \n" - - : "=d" (c), "=a" (dummy), "=c" (dummy2) - : "0" (index), "1" (value), "2" (b), "b" (p1) - : "cc", "memory" ); - - #endif - - TTMATH_LOGC("UInt::AddInt", c) - - return c; - } - - - - - /*! - adding only two unsigned words to the existing value - and these words begin on the 'index' position - (it's used in the multiplication algorithm 2) - - index should be equal or smaller than value_size-2 (index <= value_size-2) - x1 - lower word, x2 - higher word - - for example if we've got value_size equal 4 and: - - table[0] = 3 - table[1] = 4 - table[2] = 5 - table[3] = 6 - - then let - - x1 = 10 - x2 = 20 - - and - - index = 1 - - the result of this method will be: - - table[0] = 3 - table[1] = 4 + x1 = 14 - table[2] = 5 + x2 = 25 - table[3] = 6 - - and no carry at the end of table[3] - - (of course if there was a carry in table[2](5+20) then - this carry would be passed to the table[3] etc.) - */ - template - uint UInt::AddTwoInts(uint x2, uint x1, uint index) - { - uint b = value_size; - uint * p1 = table; - uint c; - - TTMATH_ASSERT( index < value_size - 1 ) - - #ifndef __GNUC__ - __asm - { - push eax - push ebx - push ecx - push edx - - mov ecx, [b] - sub ecx, [index] - - mov ebx, [p1] - mov edx, [index] - - mov eax, [x1] - add [ebx+edx*4], eax - inc edx - dec ecx - - mov eax, [x2] - - ttmath_loop: - adc [ebx+edx*4], eax - jnc ttmath_end - - mov eax, 0 - inc edx - dec ecx - jnz ttmath_loop - - ttmath_end: - setc al - movzx edx, al - mov [c], edx - - pop edx - pop ecx - pop ebx - pop eax - - } - #endif - - - #ifdef __GNUC__ - uint dummy, dummy2; - - __asm__ __volatile__( - - "subl %%edx, %%ecx \n" - - "addl %%esi, (%%ebx,%%edx,4) \n" - "incl %%edx \n" - "decl %%ecx \n" - - "1: \n" - "adcl %%eax, (%%ebx,%%edx,4) \n" - "jnc 2f \n" - - "mov $0, %%eax \n" - "incl %%edx \n" - "decl %%ecx \n" - "jnz 1b \n" - - "2: \n" - "setc %%al \n" - "movzx %%al, %%eax \n" - - : "=a" (c), "=c" (dummy), "=d" (dummy2) - : "0" (x2), "1" (b), "2" (index), "b" (p1), "S" (x1) - : "cc", "memory" ); - - #endif - - TTMATH_LOGC("UInt::AddTwoInts", c) - - return c; - } - - - - /*! - this static method addes one vector to the other - 'ss1' is larger in size or equal to 'ss2' - - ss1 points to the first (larger) vector - ss2 points to the second vector - ss1_size - size of the ss1 (and size of the result too) - ss2_size - size of the ss2 - result - is the result vector (which has size the same as ss1: ss1_size) - - Example: ss1_size is 5, ss2_size is 3 - ss1: ss2: result (output): - 5 1 5+1 - 4 3 4+3 - 2 7 2+7 - 6 6 - 9 9 - of course the carry is propagated and will be returned from the last item - (this method is used by the Karatsuba multiplication algorithm) - */ - template - uint UInt::AddVector(const uint * ss1, const uint * ss2, uint ss1_size, uint ss2_size, uint * result) - { - TTMATH_ASSERT( ss1_size >= ss2_size ) - - uint rest = ss1_size - ss2_size; - uint c; - - #ifndef __GNUC__ - - // this part might be compiled with for example visual c - __asm - { - pushad - - mov ecx, [ss2_size] - xor edx, edx // edx = 0, cf = 0 - - mov esi, [ss1] - mov ebx, [ss2] - mov edi, [result] - - ttmath_loop: - mov eax, [esi+edx*4] - adc eax, [ebx+edx*4] - mov [edi+edx*4], eax - - inc edx - dec ecx - jnz ttmath_loop - - adc ecx, ecx // ecx has the cf state - - mov ebx, [rest] - or ebx, ebx - jz ttmath_end - - xor ebx, ebx // ebx = 0 - neg ecx // setting cf from ecx - mov ecx, [rest] // ecx is != 0 - - ttmath_loop2: - mov eax, [esi+edx*4] - adc eax, ebx - mov [edi+edx*4], eax - - inc edx - dec ecx - jnz ttmath_loop2 - - adc ecx, ecx - - ttmath_end: - mov [c], ecx - - popad - } - - #endif - - - #ifdef __GNUC__ - - // this part should be compiled with gcc - uint dummy1, dummy2, dummy3; - - __asm__ __volatile__( - "push %%edx \n" - "xor %%edx, %%edx \n" // edx = 0, cf = 0 - "1: \n" - "mov (%%esi,%%edx,4), %%eax \n" - "adc (%%ebx,%%edx,4), %%eax \n" - "mov %%eax, (%%edi,%%edx,4) \n" - - "inc %%edx \n" - "dec %%ecx \n" - "jnz 1b \n" - - "adc %%ecx, %%ecx \n" // ecx has the cf state - "pop %%eax \n" // eax = rest - - "or %%eax, %%eax \n" - "jz 3f \n" - - "xor %%ebx, %%ebx \n" // ebx = 0 - "neg %%ecx \n" // setting cf from ecx - "mov %%eax, %%ecx \n" // ecx=rest and is != 0 - "2: \n" - "mov (%%esi, %%edx, 4), %%eax \n" - "adc %%ebx, %%eax \n" - "mov %%eax, (%%edi, %%edx, 4) \n" - - "inc %%edx \n" - "dec %%ecx \n" - "jnz 2b \n" - - "adc %%ecx, %%ecx \n" - "3: \n" - - : "=a" (dummy1), "=b" (dummy2), "=c" (c), "=d" (dummy3) - : "1" (ss2), "2" (ss2_size), "3" (rest), "S" (ss1), "D" (result) - : "cc", "memory" ); - - #endif - - TTMATH_VECTOR_LOGC("UInt::AddVector", c, result, ss1_size) - - return c; - } - - - /*! - subtracting ss2 from the 'this' and subtracting - carry if it has been defined - (this = this - ss2 - c) - - c must be zero or one (might be a bigger value than 1) - function returns carry (1) (if it has been) - */ - template - uint UInt::Sub(const UInt & ss2, uint c) - { - uint b = value_size; - uint * p1 = table; - uint * p2 = const_cast(ss2.table); - - // we don't have to use TTMATH_REFERENCE_ASSERT here - // this algorithm doesn't require it - - #ifndef __GNUC__ - - __asm - { - push eax - push ebx - push ecx - push edx - push esi - - mov ecx,[b] - - mov ebx,[p1] - mov esi,[p2] - - xor edx,edx // edx=0 - mov eax,[c] - neg eax // CF=1 if rax!=0 , CF=0 if rax==0 - - ttmath_loop: - mov eax,[esi+edx*4] - sbb [ebx+edx*4],eax - - inc edx - dec ecx - jnz ttmath_loop - - adc ecx, ecx - mov [c], ecx - - pop esi - pop edx - pop ecx - pop ebx - pop eax - } - - #endif - - - #ifdef __GNUC__ - uint dummy, dummy2; - - __asm__ __volatile__( - - "xorl %%edx, %%edx \n" - "negl %%eax \n" // CF=1 if rax!=0 , CF=0 if rax==0 - - "1: \n" - "movl (%%esi,%%edx,4), %%eax \n" - "sbbl %%eax, (%%ebx,%%edx,4) \n" - - "incl %%edx \n" - "decl %%ecx \n" - "jnz 1b \n" - - "adc %%ecx, %%ecx \n" - - : "=c" (c), "=a" (dummy), "=d" (dummy2) - : "0" (b), "1" (c), "b" (p1), "S" (p2) - : "cc", "memory" ); - - #endif - - TTMATH_LOGC("UInt::Sub", c) - - return c; - } - - - - - /*! - this method subtracts one word (at a specific position) - and returns a carry (if it was) - - e.g. - - if we've got (value_size=3): - - table[0] = 10; - table[1] = 30; - table[2] = 5; - - and we call: - - SubInt(2,1) - - then it'll be: - - table[0] = 10; - table[1] = 30 - 2; - table[2] = 5; - - of course if there was a carry from table[2] it would be returned - */ - template - uint UInt::SubInt(uint value, uint index) - { - uint b = value_size; - uint * p1 = table; - uint c; - - TTMATH_ASSERT( index < value_size ) - - #ifndef __GNUC__ - - __asm - { - push eax - push ebx - push ecx - push edx - - mov ecx, [b] - sub ecx, [index] - - mov edx, [index] - mov ebx, [p1] - - mov eax, [value] - - ttmath_loop: - sub [ebx+edx*4], eax - jnc ttmath_end - - mov eax, 1 - inc edx - dec ecx - jnz ttmath_loop - - ttmath_end: - setc al - movzx edx, al - mov [c], edx - - pop edx - pop ecx - pop ebx - pop eax - } - - #endif - - - #ifdef __GNUC__ - uint dummy, dummy2; - - __asm__ __volatile__( - - "subl %%edx, %%ecx \n" - - "1: \n" - "subl %%eax, (%%ebx,%%edx,4) \n" - "jnc 2f \n" - - "movl $1, %%eax \n" - "incl %%edx \n" - "decl %%ecx \n" - "jnz 1b \n" - - "2: \n" - "setc %%al \n" - "movzx %%al, %%edx \n" - - : "=d" (c), "=a" (dummy), "=c" (dummy2) - : "0" (index), "1" (value), "2" (b), "b" (p1) - : "cc", "memory" ); - - #endif - - TTMATH_LOGC("UInt::SubInt", c) - - return c; - } - - - - /*! - this static method subtractes one vector from the other - 'ss1' is larger in size or equal to 'ss2' - - ss1 points to the first (larger) vector - ss2 points to the second vector - ss1_size - size of the ss1 (and size of the result too) - ss2_size - size of the ss2 - result - is the result vector (which has size the same as ss1: ss1_size) - - Example: ss1_size is 5, ss2_size is 3 - ss1: ss2: result (output): - 5 1 5-1 - 4 3 4-3 - 2 7 2-7 - 6 6-1 (the borrow from previous item) - 9 9 - return (carry): 0 - of course the carry (borrow) is propagated and will be returned from the last item - (this method is used by the Karatsuba multiplication algorithm) - */ - template - uint UInt::SubVector(const uint * ss1, const uint * ss2, uint ss1_size, uint ss2_size, uint * result) - { - TTMATH_ASSERT( ss1_size >= ss2_size ) - - uint rest = ss1_size - ss2_size; - uint c; - - #ifndef __GNUC__ - - // this part might be compiled with for example visual c - - /* - the asm code is nearly the same as in AddVector - only two instructions 'adc' are changed to 'sbb' - */ - __asm - { - pushad - - mov ecx, [ss2_size] - xor edx, edx // edx = 0, cf = 0 - - mov esi, [ss1] - mov ebx, [ss2] - mov edi, [result] - - ttmath_loop: - mov eax, [esi+edx*4] - sbb eax, [ebx+edx*4] - mov [edi+edx*4], eax - - inc edx - dec ecx - jnz ttmath_loop - - adc ecx, ecx // ecx has the cf state - - mov ebx, [rest] - or ebx, ebx - jz ttmath_end - - xor ebx, ebx // ebx = 0 - neg ecx // setting cf from ecx - mov ecx, [rest] // ecx is != 0 - - ttmath_loop2: - mov eax, [esi+edx*4] - sbb eax, ebx - mov [edi+edx*4], eax - - inc edx - dec ecx - jnz ttmath_loop2 - - adc ecx, ecx - - ttmath_end: - mov [c], ecx - - popad - } - - #endif - - - #ifdef __GNUC__ - - // this part should be compiled with gcc - uint dummy1, dummy2, dummy3; - - __asm__ __volatile__( - "push %%edx \n" - "xor %%edx, %%edx \n" // edx = 0, cf = 0 - "1: \n" - "mov (%%esi,%%edx,4), %%eax \n" - "sbb (%%ebx,%%edx,4), %%eax \n" - "mov %%eax, (%%edi,%%edx,4) \n" - - "inc %%edx \n" - "dec %%ecx \n" - "jnz 1b \n" - - "adc %%ecx, %%ecx \n" // ecx has the cf state - "pop %%eax \n" // eax = rest - - "or %%eax, %%eax \n" - "jz 3f \n" - - "xor %%ebx, %%ebx \n" // ebx = 0 - "neg %%ecx \n" // setting cf from ecx - "mov %%eax, %%ecx \n" // ecx=rest and is != 0 - "2: \n" - "mov (%%esi, %%edx, 4), %%eax \n" - "sbb %%ebx, %%eax \n" - "mov %%eax, (%%edi, %%edx, 4) \n" - - "inc %%edx \n" - "dec %%ecx \n" - "jnz 2b \n" - - "adc %%ecx, %%ecx \n" - "3: \n" - - : "=a" (dummy1), "=b" (dummy2), "=c" (c), "=d" (dummy3) - : "1" (ss2), "2" (ss2_size), "3" (rest), "S" (ss1), "D" (result) - : "cc", "memory" ); - - #endif - - TTMATH_VECTOR_LOGC("UInt::SubVector", c, result, ss1_size) - - return c; - } - - - - /*! - this method moves all bits into the left hand side - return value <- this <- c - - the lowest *bit* will be held the 'c' and - the state of one additional bit (on the left hand side) - will be returned - - for example: - let this is 001010000 - after Rcl2_one(1) there'll be 010100001 and Rcl2_one returns 0 - */ - template - uint UInt::Rcl2_one(uint c) - { - uint b = value_size; - uint * p1 = table; - - #ifndef __GNUC__ - __asm - { - push ebx - push ecx - push edx - - mov ebx, [p1] - xor edx, edx - mov ecx, [c] - neg ecx - mov ecx, [b] - - ttmath_loop: - rcl dword ptr [ebx+edx*4], 1 - - inc edx - dec ecx - jnz ttmath_loop - - adc ecx, ecx - mov [c], ecx - - pop edx - pop ecx - pop ebx - } - #endif - - - #ifdef __GNUC__ - uint dummy, dummy2; - - __asm__ __volatile__( - - "xorl %%edx, %%edx \n" // edx=0 - "negl %%eax \n" // CF=1 if eax!=0 , CF=0 if eax==0 - - "1: \n" - "rcll $1, (%%ebx, %%edx, 4) \n" - - "incl %%edx \n" - "decl %%ecx \n" - "jnz 1b \n" - - "adcl %%ecx, %%ecx \n" - - : "=c" (c), "=a" (dummy), "=d" (dummy2) - : "0" (b), "1" (c), "b" (p1) - : "cc", "memory" ); - - #endif - - TTMATH_LOGC("UInt::Rcl2_one", c) - - return c; - } - - - - /*! - this method moves all bits into the right hand side - c -> this -> return value - - the highest *bit* will be held the 'c' and - the state of one additional bit (on the right hand side) - will be returned - - for example: - let this is 000000010 - after Rcr2_one(1) there'll be 100000001 and Rcr2_one returns 0 - */ - template - uint UInt::Rcr2_one(uint c) - { - uint b = value_size; - uint * p1 = table; - - #ifndef __GNUC__ - __asm - { - push ebx - push ecx - - mov ebx, [p1] - mov ecx, [c] - neg ecx - mov ecx, [b] - - ttmath_loop: - rcr dword ptr [ebx+ecx*4-4], 1 - - dec ecx - jnz ttmath_loop - - adc ecx, ecx - mov [c], ecx - - pop ecx - pop ebx - } - #endif - - - #ifdef __GNUC__ - uint dummy; - - __asm__ __volatile__( - - "negl %%eax \n" // CF=1 if eax!=0 , CF=0 if eax==0 - - "1: \n" - "rcrl $1, -4(%%ebx, %%ecx, 4) \n" - - "decl %%ecx \n" - "jnz 1b \n" - - "adcl %%ecx, %%ecx \n" - - : "=c" (c), "=a" (dummy) - : "0" (b), "1" (c), "b" (p1) - : "cc", "memory" ); - - #endif - - TTMATH_LOGC("UInt::Rcr2_one", c) - - return c; - } - - - -#ifdef _MSC_VER -#pragma warning (disable : 4731) -//warning C4731: frame pointer register 'ebp' modified by inline assembly code -#endif - - - - /*! - this method moves all bits into the left hand side - return value <- this <- c - - the lowest *bits* will be held the 'c' and - the state of one additional bit (on the left hand side) - will be returned - - for example: - let this is 001010000 - after Rcl2(3, 1) there'll be 010000111 and Rcl2 returns 1 - */ - template - uint UInt::Rcl2(uint bits, uint c) - { - TTMATH_ASSERT( bits>0 && bits edx -> cf) (cl times) - "movl %%edx, %%ebp \n" // ebp = edx = mask - "movl %%esi, %%ecx \n" - - "xorl %%edx, %%edx \n" - "movl %%edx, %%esi \n" - "orl %%eax, %%eax \n" - "cmovnz %%ebp, %%esi \n" // if(c) esi=mask else esi=0 - - "1: \n" - "roll %%cl, (%%ebx,%%edx,4) \n" - - "movl (%%ebx,%%edx,4), %%eax \n" - "andl %%ebp, %%eax \n" - "xorl %%eax, (%%ebx,%%edx,4) \n" - "orl %%esi, (%%ebx,%%edx,4) \n" - "movl %%eax, %%esi \n" - - "incl %%edx \n" - "decl %%edi \n" - "jnz 1b \n" - - "and $1, %%eax \n" - - "pop %%ebp \n" - - : "=a" (c), "=D" (dummy), "=S" (dummy2), "=d" (dummy3) - : "0" (c), "1" (b), "b" (p1), "c" (bits) - : "cc", "memory" ); - - #endif - - TTMATH_LOGC("UInt::Rcl2", c) - - return c; - } - - - - - /*! - this method moves all bits into the right hand side - C -> this -> return value - - the highest *bits* will be held the 'c' and - the state of one additional bit (on the right hand side) - will be returned - - for example: - let this is 000000010 - after Rcr2(2, 1) there'll be 110000000 and Rcr2 returns 1 - */ - template - uint UInt::Rcr2(uint bits, uint c) - { - TTMATH_ASSERT( bits>0 && bits - sint UInt::FindLeadingBitInWord(uint x) - { - sint result; - - #ifndef __GNUC__ - __asm - { - push eax - push edx - - mov edx,-1 - bsr eax,[x] - cmovz eax,edx - mov [result], eax - - pop edx - pop eax - } - #endif - - - #ifdef __GNUC__ - uint dummy; - - __asm__ ( - - "movl $-1, %1 \n" - "bsrl %2, %0 \n" - "cmovz %1, %0 \n" - - : "=r" (result), "=&r" (dummy) - : "r" (x) - : "cc" ); - - #endif - - return result; - } - - - - /* - this method returns the number of the smallest set bit in one 32-bit word - if the 'x' is zero this method returns '-1' - */ - template - sint UInt::FindLowestBitInWord(uint x) - { - sint result; - - #ifndef __GNUC__ - __asm - { - push eax - push edx - - mov edx,-1 - bsf eax,[x] - cmovz eax,edx - mov [result], eax - - pop edx - pop eax - } - #endif - - - #ifdef __GNUC__ - uint dummy; - - __asm__ ( - - "movl $-1, %1 \n" - "bsfl %2, %0 \n" - "cmovz %1, %0 \n" - - : "=r" (result), "=&r" (dummy) - : "r" (x) - : "cc" ); - - #endif - - return result; - } - - - - /*! - this method sets a special bit in the 'value' - and returns the last state of the bit (zero or one) - - bit is from <0,31> - e.g. - - uint x = 100; - uint bit = SetBitInWord(x, 3); - now: x = 108 and bit = 0 - */ - template - uint UInt::SetBitInWord(uint & value, uint bit) - { - TTMATH_ASSERT( bit < TTMATH_BITS_PER_UINT ) - - uint old_bit; - uint v = value; - - #ifndef __GNUC__ - __asm - { - push ebx - push eax - - mov eax, [v] - mov ebx, [bit] - bts eax, ebx - mov [v], eax - - setc bl - movzx ebx, bl - mov [old_bit], ebx - - pop eax - pop ebx - } - #endif - - - #ifdef __GNUC__ - __asm__ ( - - "btsl %%ebx, %%eax \n" - "setc %%bl \n" - "movzx %%bl, %%ebx \n" - - : "=a" (v), "=b" (old_bit) - : "0" (v), "1" (bit) - : "cc" ); - - #endif - - value = v; - - return old_bit; - } - - - - - /*! - multiplication: result_high:result_low = a * b - result_high - higher word of the result - result_low - lower word of the result - - this methos never returns a carry - this method is used in the second version of the multiplication algorithms - */ - template - void UInt::MulTwoWords(uint a, uint b, uint * result_high, uint * result_low) - { - /* - we must use these temporary variables in order to inform the compilator - that value pointed with result1 and result2 has changed - - this has no effect in visual studio but it's useful when - using gcc and options like -Ox - */ - uint result1_; - uint result2_; - - #ifndef __GNUC__ - - __asm - { - push eax - push edx - - mov eax, [a] - mul dword ptr [b] - - mov [result2_], edx - mov [result1_], eax - - pop edx - pop eax - } - - #endif - - - #ifdef __GNUC__ - - __asm__ ( - - "mull %%edx \n" - - : "=a" (result1_), "=d" (result2_) - : "0" (a), "1" (b) - : "cc" ); - - #endif - - - *result_low = result1_; - *result_high = result2_; - } - - - - - - /*! - * - * Division - * - * - */ - - - - - /*! - this method calculates 64bits word a:b / 32bits c (a higher, b lower word) - r = a:b / c and rest - remainder - - * - * WARNING: - * if r (one word) is too small for the result or c is equal zero - * there'll be a hardware interruption (0) - * and probably the end of your program - * - */ - template - void UInt::DivTwoWords(uint a, uint b, uint c, uint * r, uint * rest) - { - uint r_; - uint rest_; - /* - these variables have similar meaning like those in - the multiplication algorithm MulTwoWords - */ - - TTMATH_ASSERT( c != 0 ) - - #ifndef __GNUC__ - __asm - { - push eax - push edx - - mov edx, [a] - mov eax, [b] - div dword ptr [c] - - mov [r_], eax - mov [rest_], edx - - pop edx - pop eax - } - #endif - - - #ifdef __GNUC__ - - __asm__ ( - - "divl %%ecx \n" - - : "=a" (r_), "=d" (rest_) - : "0" (b), "1" (a), "c" (c) - : "cc" ); - - #endif - - - *r = r_; - *rest = rest_; - - } - - - -} //namespace - - - -#endif //ifdef TTMATH_PLATFORM32 -#endif //ifndef TTMATH_NOASM -#endif diff --git a/include/geos/algorithm/ttmath/ttmathuint_x86_64.h b/include/geos/algorithm/ttmath/ttmathuint_x86_64.h deleted file mode 100644 index 7ec501d9d4..0000000000 --- a/include/geos/algorithm/ttmath/ttmathuint_x86_64.h +++ /dev/null @@ -1,1177 +0,0 @@ -/* - * This file is a part of TTMath Bignum Library - * and is distributed under the 3-Clause BSD Licence. - * Author: Tomasz Sowa - */ - -/* - * Copyright (c) 2006-2010, Tomasz Sowa - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * * Neither the name Tomasz Sowa nor the names of contributors to this - * project may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - - -#ifndef headerfilettmathuint_x86_64 -#define headerfilettmathuint_x86_64 - - -#ifndef TTMATH_NOASM -#ifdef TTMATH_PLATFORM64 - - -/*! - \file ttmathuint_x86_64.h - \brief template class UInt with assembler code for 64bit x86_64 processors - - this file is included at the end of ttmathuint.h -*/ - - -/*! - \file ttmathuint_x86_64_msvc.asm - \brief some asm routines for x86_64 when using Microsoft compiler - - this file should be first compiled: - - compile with debug info: ml64.exe /c /Zd /Zi ttmathuint_x86_64_msvc.asm - - compile without debug info: ml64.exe /c ttmathuint_x86_64_msvc.asm - - this creates ttmathuint_x86_64_msvc.obj file which can be linked with your program - - (you can use win64_assemble.bat file from ttmath subdirectory) -*/ - - -#ifndef __GNUC__ -#include -#endif - - -namespace ttmath -{ - - #ifndef __GNUC__ - - extern "C" - { - uint __fastcall ttmath_adc_x64(uint* p1, const uint* p2, uint nSize, uint c); - uint __fastcall ttmath_addindexed_x64(uint* p1, uint nSize, uint nPos, uint nValue); - uint __fastcall ttmath_addindexed2_x64(uint* p1, uint nSize, uint nPos, uint nValue1, uint nValue2); - uint __fastcall ttmath_addvector_x64(const uint * ss1, const uint * ss2, uint ss1_size, uint ss2_size, uint * result); - uint __fastcall ttmath_sbb_x64(uint* p1, const uint* p2, uint nSize, uint c); - uint __fastcall ttmath_subindexed_x64(uint* p1, uint nSize, uint nPos, uint nValue); - uint __fastcall ttmath_subvector_x64(const uint * ss1, const uint * ss2, uint ss1_size, uint ss2_size, uint * result); - uint __fastcall ttmath_rcl_x64(uint* p1, uint nSize, uint nLowestBit); - uint __fastcall ttmath_rcr_x64(uint* p1, uint nSize, uint nLowestBit); - uint __fastcall ttmath_div_x64(uint* pnValHi, uint* pnValLo, uint nDiv); - uint __fastcall ttmath_rcl2_x64(uint* p1, uint nSize, uint nBits, uint c); - uint __fastcall ttmath_rcr2_x64(uint* p1, uint nSize, uint nBits, uint c); - }; - #endif - - - /*! - returning the string represents the currect type of the library - we have following types: - asm_vc_32 - with asm code designed for Microsoft Visual C++ (32 bits) - asm_gcc_32 - with asm code designed for GCC (32 bits) - asm_vc_64 - with asm for VC (64 bit) - asm_gcc_64 - with asm for GCC (64 bit) - no_asm_32 - pure C++ version (32 bit) - without any asm code - no_asm_64 - pure C++ version (64 bit) - without any asm code - */ - template - const char * UInt::LibTypeStr() - { - #ifndef __GNUC__ - static const char info[] = "asm_vc_64"; - #endif - - #ifdef __GNUC__ - static const char info[] = "asm_gcc_64"; - #endif - - return info; - } - - - /*! - returning the currect type of the library - */ - template - LibTypeCode UInt::LibType() - { - #ifndef __GNUC__ - LibTypeCode info = asm_vc_64; - #endif - - #ifdef __GNUC__ - LibTypeCode info = asm_gcc_64; - #endif - - return info; - } - - - /*! - * - * basic mathematic functions - * - */ - - - - /*! - this method adding ss2 to the this and adding carry if it's defined - (this = this + ss2 + c) - - ***this method is created only on a 64bit platform*** - - c must be zero or one (might be a bigger value than 1) - function returns carry (1) (if it was) - */ - template - uint UInt::Add(const UInt & ss2, uint c) - { - uint b = value_size; - uint * p1 = table; - const uint * p2 = ss2.table; - - // we don't have to use TTMATH_REFERENCE_ASSERT here - // this algorithm doesn't require it - - #ifndef __GNUC__ - c = ttmath_adc_x64(p1,p2,b,c); - #endif - - #ifdef __GNUC__ - uint dummy, dummy2; - - /* - this part should be compiled with gcc - */ - __asm__ __volatile__( - - "xorq %%rdx, %%rdx \n" - "negq %%rax \n" // CF=1 if rax!=0 , CF=0 if rax==0 - - "1: \n" - "movq (%%rsi,%%rdx,8), %%rax \n" - "adcq %%rax, (%%rbx,%%rdx,8) \n" - - "incq %%rdx \n" - "decq %%rcx \n" - "jnz 1b \n" - - "adcq %%rcx, %%rcx \n" - - : "=c" (c), "=a" (dummy), "=d" (dummy2) - : "0" (b), "1" (c), "b" (p1), "S" (p2) - : "cc", "memory" ); - - #endif - - TTMATH_LOGC("UInt::Add", c) - - return c; - } - - - - /*! - this method adds one word (at a specific position) - and returns a carry (if it was) - - ***this method is created only on a 64bit platform*** - - - if we've got (value_size=3): - - table[0] = 10; - table[1] = 30; - table[2] = 5; - - and we call: - - AddInt(2,1) - - then it'll be: - - table[0] = 10; - table[1] = 30 + 2; - table[2] = 5; - - of course if there was a carry from table[2] it would be returned - */ - template - uint UInt::AddInt(uint value, uint index) - { - uint b = value_size; - uint * p1 = table; - uint c; - - TTMATH_ASSERT( index < value_size ) - - #ifndef __GNUC__ - c = ttmath_addindexed_x64(p1,b,index,value); - #endif - - - #ifdef __GNUC__ - uint dummy, dummy2; - - __asm__ __volatile__( - - "subq %%rdx, %%rcx \n" - - "1: \n" - "addq %%rax, (%%rbx,%%rdx,8) \n" - "jnc 2f \n" - - "movq $1, %%rax \n" - "incq %%rdx \n" - "decq %%rcx \n" - "jnz 1b \n" - - "2: \n" - "setc %%al \n" - "movzx %%al, %%rdx \n" - - : "=d" (c), "=a" (dummy), "=c" (dummy2) - : "0" (index), "1" (value), "2" (b), "b" (p1) - : "cc", "memory" ); - - #endif - - TTMATH_LOGC("UInt::AddInt", c) - - return c; - } - - - - /*! - this method adds only two unsigned words to the existing value - and these words begin on the 'index' position - (it's used in the multiplication algorithm 2) - - ***this method is created only on a 64bit platform*** - - index should be equal or smaller than value_size-2 (index <= value_size-2) - x1 - lower word, x2 - higher word - - for example if we've got value_size equal 4 and: - - table[0] = 3 - table[1] = 4 - table[2] = 5 - table[3] = 6 - - then let - - x1 = 10 - x2 = 20 - - and - - index = 1 - - the result of this method will be: - - table[0] = 3 - table[1] = 4 + x1 = 14 - table[2] = 5 + x2 = 25 - table[3] = 6 - - and no carry at the end of table[3] - - (of course if there was a carry in table[2](5+20) then - this carry would be passed to the table[3] etc.) - */ - template - uint UInt::AddTwoInts(uint x2, uint x1, uint index) - { - uint b = value_size; - uint * p1 = table; - uint c; - - TTMATH_ASSERT( index < value_size - 1 ) - - #ifndef __GNUC__ - c = ttmath_addindexed2_x64(p1,b,index,x1,x2); - #endif - - - #ifdef __GNUC__ - uint dummy, dummy2; - - __asm__ __volatile__( - - "subq %%rdx, %%rcx \n" - - "addq %%rsi, (%%rbx,%%rdx,8) \n" - "incq %%rdx \n" - "decq %%rcx \n" - - "1: \n" - "adcq %%rax, (%%rbx,%%rdx,8) \n" - "jnc 2f \n" - - "mov $0, %%rax \n" - "incq %%rdx \n" - "decq %%rcx \n" - "jnz 1b \n" - - "2: \n" - "setc %%al \n" - "movzx %%al, %%rax \n" - - : "=a" (c), "=c" (dummy), "=d" (dummy2) - : "0" (x2), "1" (b), "2" (index), "b" (p1), "S" (x1) - : "cc", "memory" ); - - #endif - - TTMATH_LOGC("UInt::AddTwoInts", c) - - return c; - } - - - - /*! - this static method addes one vector to the other - 'ss1' is larger in size or equal to 'ss2' - - - ss1 points to the first (larger) vector - - ss2 points to the second vector - - ss1_size - size of the ss1 (and size of the result too) - - ss2_size - size of the ss2 - - result - is the result vector (which has size the same as ss1: ss1_size) - - Example: ss1_size is 5, ss2_size is 3 - ss1: ss2: result (output): - 5 1 5+1 - 4 3 4+3 - 2 7 2+7 - 6 6 - 9 9 - of course the carry is propagated and will be returned from the last item - (this method is used by the Karatsuba multiplication algorithm) - */ - template - uint UInt::AddVector(const uint * ss1, const uint * ss2, uint ss1_size, uint ss2_size, uint * result) - { - TTMATH_ASSERT( ss1_size >= ss2_size ) - - uint c; - - #ifndef __GNUC__ - c = ttmath_addvector_x64(ss1, ss2, ss1_size, ss2_size, result); - #endif - - - #ifdef __GNUC__ - uint dummy1, dummy2, dummy3; - uint rest = ss1_size - ss2_size; - - // this part should be compiled with gcc - - __asm__ __volatile__( - "mov %%rdx, %%r8 \n" - "xor %%rdx, %%rdx \n" // rdx = 0, cf = 0 - "1: \n" - "mov (%%rsi,%%rdx,8), %%rax \n" - "adc (%%rbx,%%rdx,8), %%rax \n" - "mov %%rax, (%%rdi,%%rdx,8) \n" - - "inc %%rdx \n" - "dec %%rcx \n" - "jnz 1b \n" - - "adc %%rcx, %%rcx \n" // rcx has the cf state - - "or %%r8, %%r8 \n" - "jz 3f \n" - - "xor %%rbx, %%rbx \n" // ebx = 0 - "neg %%rcx \n" // setting cf from rcx - "mov %%r8, %%rcx \n" // rcx=rest and is != 0 - "2: \n" - "mov (%%rsi, %%rdx, 8), %%rax \n" - "adc %%rbx, %%rax \n" - "mov %%rax, (%%rdi, %%rdx, 8) \n" - - "inc %%rdx \n" - "dec %%rcx \n" - "jnz 2b \n" - - "adc %%rcx, %%rcx \n" - "3: \n" - - : "=a" (dummy1), "=b" (dummy2), "=c" (c), "=d" (dummy3) - : "1" (ss2), "2" (ss2_size), "3" (rest), "S" (ss1), "D" (result) - : "%r8", "cc", "memory" ); - - #endif - - TTMATH_VECTOR_LOGC("UInt::AddVector", c, result, ss1_size) - - return c; - } - - - - /*! - this method's subtracting ss2 from the 'this' and subtracting - carry if it has been defined - (this = this - ss2 - c) - - ***this method is created only on a 64bit platform*** - - c must be zero or one (might be a bigger value than 1) - function returns carry (1) (if it was) - */ - template - uint UInt::Sub(const UInt & ss2, uint c) - { - uint b = value_size; - uint * p1 = table; - const uint * p2 = ss2.table; - - // we don't have to use TTMATH_REFERENCE_ASSERT here - // this algorithm doesn't require it - - #ifndef __GNUC__ - c = ttmath_sbb_x64(p1,p2,b,c); - #endif - - - #ifdef __GNUC__ - uint dummy, dummy2; - - __asm__ __volatile__( - - "xorq %%rdx, %%rdx \n" - "negq %%rax \n" // CF=1 if rax!=0 , CF=0 if rax==0 - - "1: \n" - "movq (%%rsi,%%rdx,8), %%rax \n" - "sbbq %%rax, (%%rbx,%%rdx,8) \n" - - "incq %%rdx \n" - "decq %%rcx \n" - "jnz 1b \n" - - "adcq %%rcx, %%rcx \n" - - : "=c" (c), "=a" (dummy), "=d" (dummy2) - : "0" (b), "1" (c), "b" (p1), "S" (p2) - : "cc", "memory" ); - - #endif - - TTMATH_LOGC("UInt::Sub", c) - - return c; - } - - - - /*! - this method subtracts one word (at a specific position) - and returns a carry (if it was) - - ***this method is created only on a 64bit platform*** - - if we've got (value_size=3): - - table[0] = 10; - table[1] = 30; - table[2] = 5; - - and we call: - - SubInt(2,1) - - then it'll be: - - table[0] = 10; - table[1] = 30 - 2; - table[2] = 5; - - of course if there was a carry from table[2] it would be returned - */ - template - uint UInt::SubInt(uint value, uint index) - { - uint b = value_size; - uint * p1 = table; - uint c; - - TTMATH_ASSERT( index < value_size ) - - #ifndef __GNUC__ - c = ttmath_subindexed_x64(p1,b,index,value); - #endif - - - #ifdef __GNUC__ - uint dummy, dummy2; - - __asm__ __volatile__( - - "subq %%rdx, %%rcx \n" - - "1: \n" - "subq %%rax, (%%rbx,%%rdx,8) \n" - "jnc 2f \n" - - "movq $1, %%rax \n" - "incq %%rdx \n" - "decq %%rcx \n" - "jnz 1b \n" - - "2: \n" - "setc %%al \n" - "movzx %%al, %%rdx \n" - - : "=d" (c), "=a" (dummy), "=c" (dummy2) - : "0" (index), "1" (value), "2" (b), "b" (p1) - : "cc", "memory" ); - - #endif - - TTMATH_LOGC("UInt::SubInt", c) - - return c; - } - - - /*! - this static method subtractes one vector from the other - 'ss1' is larger in size or equal to 'ss2' - - - ss1 points to the first (larger) vector - - ss2 points to the second vector - - ss1_size - size of the ss1 (and size of the result too) - - ss2_size - size of the ss2 - - result - is the result vector (which has size the same as ss1: ss1_size) - - Example: ss1_size is 5, ss2_size is 3 - ss1: ss2: result (output): - 5 1 5-1 - 4 3 4-3 - 2 7 2-7 - 6 6-1 (the borrow from previous item) - 9 9 - return (carry): 0 - of course the carry (borrow) is propagated and will be returned from the last item - (this method is used by the Karatsuba multiplication algorithm) - */ - template - uint UInt::SubVector(const uint * ss1, const uint * ss2, uint ss1_size, uint ss2_size, uint * result) - { - TTMATH_ASSERT( ss1_size >= ss2_size ) - - uint c; - - #ifndef __GNUC__ - c = ttmath_subvector_x64(ss1, ss2, ss1_size, ss2_size, result); - #endif - - - #ifdef __GNUC__ - - // the asm code is nearly the same as in AddVector - // only two instructions 'adc' are changed to 'sbb' - - uint dummy1, dummy2, dummy3; - uint rest = ss1_size - ss2_size; - - __asm__ __volatile__( - "mov %%rdx, %%r8 \n" - "xor %%rdx, %%rdx \n" // rdx = 0, cf = 0 - "1: \n" - "mov (%%rsi,%%rdx,8), %%rax \n" - "sbb (%%rbx,%%rdx,8), %%rax \n" - "mov %%rax, (%%rdi,%%rdx,8) \n" - - "inc %%rdx \n" - "dec %%rcx \n" - "jnz 1b \n" - - "adc %%rcx, %%rcx \n" // rcx has the cf state - - "or %%r8, %%r8 \n" - "jz 3f \n" - - "xor %%rbx, %%rbx \n" // ebx = 0 - "neg %%rcx \n" // setting cf from rcx - "mov %%r8, %%rcx \n" // rcx=rest and is != 0 - "2: \n" - "mov (%%rsi, %%rdx, 8), %%rax \n" - "sbb %%rbx, %%rax \n" - "mov %%rax, (%%rdi, %%rdx, 8) \n" - - "inc %%rdx \n" - "dec %%rcx \n" - "jnz 2b \n" - - "adc %%rcx, %%rcx \n" - "3: \n" - - : "=a" (dummy1), "=b" (dummy2), "=c" (c), "=d" (dummy3) - : "1" (ss2), "2" (ss2_size), "3" (rest), "S" (ss1), "D" (result) - : "%r8", "cc", "memory" ); - - #endif - - TTMATH_VECTOR_LOGC("UInt::SubVector", c, result, ss1_size) - - return c; - } - - - /*! - this method moves all bits into the left hand side - return value <- this <- c - - the lowest *bit* will be held the 'c' and - the state of one additional bit (on the left hand side) - will be returned - - for example: - let this is 001010000 - after Rcl2_one(1) there'll be 010100001 and Rcl2_one returns 0 - - ***this method is created only on a 64bit platform*** - */ - template - uint UInt::Rcl2_one(uint c) - { - sint b = value_size; - uint * p1 = table; - - - #ifndef __GNUC__ - c = ttmath_rcl_x64(p1,b,c); - #endif - - - #ifdef __GNUC__ - uint dummy, dummy2; - - __asm__ __volatile__( - - "xorq %%rdx, %%rdx \n" // rdx=0 - "negq %%rax \n" // CF=1 if rax!=0 , CF=0 if rax==0 - - "1: \n" - "rclq $1, (%%rbx, %%rdx, 8) \n" - - "incq %%rdx \n" - "decq %%rcx \n" - "jnz 1b \n" - - "adcq %%rcx, %%rcx \n" - - : "=c" (c), "=a" (dummy), "=d" (dummy2) - : "0" (b), "1" (c), "b" (p1) - : "cc", "memory" ); - - #endif - - TTMATH_LOGC("UInt::Rcl2_one", c) - - return c; - } - - - /*! - this method moves all bits into the right hand side - c -> this -> return value - - the highest *bit* will be held the 'c' and - the state of one additional bit (on the right hand side) - will be returned - - for example: - let this is 000000010 - after Rcr2_one(1) there'll be 100000001 and Rcr2_one returns 0 - - ***this method is created only on a 64bit platform*** - */ - template - uint UInt::Rcr2_one(uint c) - { - sint b = value_size; - uint * p1 = table; - - - #ifndef __GNUC__ - c = ttmath_rcr_x64(p1,b,c); - #endif - - - #ifdef __GNUC__ - uint dummy; - - __asm__ __volatile__( - - "negq %%rax \n" // CF=1 if rax!=0 , CF=0 if rax==0 - - "1: \n" - "rcrq $1, -8(%%rbx, %%rcx, 8) \n" - - "decq %%rcx \n" - "jnz 1b \n" - - "adcq %%rcx, %%rcx \n" - - : "=c" (c), "=a" (dummy) - : "0" (b), "1" (c), "b" (p1) - : "cc", "memory" ); - - #endif - - TTMATH_LOGC("UInt::Rcr2_one", c) - - return c; - } - - - - /*! - this method moves all bits into the left hand side - return value <- this <- c - - the lowest *bits* will be held the 'c' and - the state of one additional bit (on the left hand side) - will be returned - - for example: - let this is 001010000 - after Rcl2(3, 1) there'll be 010000111 and Rcl2 returns 1 - - ***this method is created only on a 64bit platform*** - */ - template - uint UInt::Rcl2(uint bits, uint c) - { - TTMATH_ASSERT( bits>0 && bits this -> return value - - the highest *bits* will be held the 'c' and - the state of one additional bit (on the right hand side) - will be returned - - for example: - let this is 000000010 - after Rcr2(2, 1) there'll be 110000000 and Rcr2 returns 1 - - ***this method is created only on a 64bit platform*** - */ - template - uint UInt::Rcr2(uint bits, uint c) - { - TTMATH_ASSERT( bits>0 && bits - sint UInt::FindLeadingBitInWord(uint x) - { - sint result; - - - #ifndef __GNUC__ - - unsigned long nIndex = 0; - - if( _BitScanReverse64(&nIndex,x) == 0 ) - result = -1; - else - result = nIndex; - - #endif - - - #ifdef __GNUC__ - uint dummy; - - __asm__ ( - - "movq $-1, %1 \n" - "bsrq %2, %0 \n" - "cmovz %1, %0 \n" - - : "=r" (result), "=&r" (dummy) - : "r" (x) - : "cc" ); - - #endif - - - return result; - } - - - /* - this method returns the number of the highest set bit in one 64-bit word - if the 'x' is zero this method returns '-1' - - ***this method is created only on a 64bit platform*** - */ - template - sint UInt::FindLowestBitInWord(uint x) - { - sint result; - - - #ifndef __GNUC__ - - unsigned long nIndex = 0; - - if( _BitScanForward64(&nIndex,x) == 0 ) - result = -1; - else - result = nIndex; - - #endif - - - #ifdef __GNUC__ - uint dummy; - - __asm__ ( - - "movq $-1, %1 \n" - "bsfq %2, %0 \n" - "cmovz %1, %0 \n" - - : "=r" (result), "=&r" (dummy) - : "r" (x) - : "cc" ); - - #endif - - - return result; - } - - - /*! - this method sets a special bit in the 'value' - and returns the last state of the bit (zero or one) - - ***this method is created only on a 64bit platform*** - - bit is from <0,63> - - e.g. - uint x = 100; - uint bit = SetBitInWord(x, 3); - now: x = 108 and bit = 0 - */ - template - uint UInt::SetBitInWord(uint & value, uint bit) - { - TTMATH_ASSERT( bit < TTMATH_BITS_PER_UINT ) - - uint old_bit; - uint v = value; - - - #ifndef __GNUC__ - old_bit = _bittestandset64((__int64*)&value,bit) != 0; - #endif - - - #ifdef __GNUC__ - - __asm__ ( - - "btsq %%rbx, %%rax \n" - "setc %%bl \n" - "movzx %%bl, %%rbx \n" - - : "=a" (v), "=b" (old_bit) - : "0" (v), "1" (bit) - : "cc" ); - - #endif - - value = v; - - return old_bit; - } - - - /*! - * - * Multiplication - * - * - */ - - - /*! - multiplication: result_high:result_low = a * b - - result_high - higher word of the result - - result_low - lower word of the result - - this methos never returns a carry - this method is used in the second version of the multiplication algorithms - - ***this method is created only on a 64bit platform*** - */ - template - void UInt::MulTwoWords(uint a, uint b, uint * result_high, uint * result_low) - { - /* - we must use these temporary variables in order to inform the compilator - that value pointed with result1 and result2 has changed - - this has no effect in visual studio but it's usefull when - using gcc and options like -O - */ - uint result1_; - uint result2_; - - - #ifndef __GNUC__ - result1_ = _umul128(a,b,&result2_); - #endif - - - #ifdef __GNUC__ - - __asm__ ( - - "mulq %%rdx \n" - - : "=a" (result1_), "=d" (result2_) - : "0" (a), "1" (b) - : "cc" ); - - #endif - - - *result_low = result1_; - *result_high = result2_; - } - - - - - /*! - * - * Division - * - * - */ - - - /*! - this method calculates 64bits word a:b / 32bits c (a higher, b lower word) - r = a:b / c and rest - remainder - - ***this method is created only on a 64bit platform*** - - * - * WARNING: - * if r (one word) is too small for the result or c is equal zero - * there'll be a hardware interruption (0) - * and probably the end of your program - * - */ - template - void UInt::DivTwoWords(uint a,uint b, uint c, uint * r, uint * rest) - { - uint r_; - uint rest_; - /* - these variables have similar meaning like those in - the multiplication algorithm MulTwoWords - */ - - TTMATH_ASSERT( c != 0 ) - - - #ifndef __GNUC__ - - ttmath_div_x64(&a,&b,c); - r_ = a; - rest_ = b; - - #endif - - - #ifdef __GNUC__ - - __asm__ ( - - "divq %%rcx \n" - - : "=a" (r_), "=d" (rest_) - : "d" (a), "a" (b), "c" (c) - : "cc" ); - - #endif - - - *r = r_; - *rest = rest_; - } - -} //namespace - - -#endif //ifdef TTMATH_PLATFORM64 -#endif //ifndef TTMATH_NOASM -#endif - - diff --git a/include/geos/algorithm/ttmath/ttmathuint_x86_64_msvc.asm b/include/geos/algorithm/ttmath/ttmathuint_x86_64_msvc.asm deleted file mode 100644 index 2f23a635c9..0000000000 --- a/include/geos/algorithm/ttmath/ttmathuint_x86_64_msvc.asm +++ /dev/null @@ -1,551 +0,0 @@ -; -; This file is a part of TTMath Bignum Library -; and is distributed under the 3-Clause BSD Licence. -; Author: Christian Kaiser , Tomasz Sowa -; - -; -; Copyright (c) 2009-2017, Christian Kaiser, Tomasz Sowa -; All rights reserved. -; -; Redistribution and use in source and binary forms, with or without -; modification, are permitted provided that the following conditions are met: -; -; * Redistributions of source code must retain the above copyright notice, -; this list of conditions and the following disclaimer. -; -; * Redistributions in binary form must reproduce the above copyright -; notice, this list of conditions and the following disclaimer in the -; documentation and/or other materials provided with the distribution. -; -; * Neither the name Christian Kaiser nor the names of contributors to this -; project may be used to endorse or promote products derived -; from this software without specific prior written permission. -; -; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -; ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -; LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -; SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -; CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -; ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -; THE POSSIBILITY OF SUCH DAMAGE. -; - -; -; compile with debug info: ml64.exe /c /Zd /Zi ttmathuint_x86_64_msvc.asm -; compile without debug info: ml64.exe /c ttmathuint_x86_64_msvc.asm -; this creates ttmathuint_x86_64_msvc.obj file which can be linked with your program -; - -; doxygen info is put to ttmathuint_x86_64.h file - - -PUBLIC ttmath_adc_x64 -PUBLIC ttmath_addindexed_x64 -PUBLIC ttmath_addindexed2_x64 -PUBLIC ttmath_addvector_x64 - -PUBLIC ttmath_sbb_x64 -PUBLIC ttmath_subindexed_x64 -PUBLIC ttmath_subvector_x64 - -PUBLIC ttmath_rcl_x64 -PUBLIC ttmath_rcr_x64 - -PUBLIC ttmath_rcl2_x64 -PUBLIC ttmath_rcr2_x64 - -PUBLIC ttmath_div_x64 - -; -; Microsoft x86_64 convention: http://msdn.microsoft.com/en-us/library/9b372w95.aspx -; -; "rax, rcx, rdx, r8-r11 are volatile." -; "rbx, rbp, rdi, rsi, r12-r15 are nonvolatile." -; - - -.CODE - - - ALIGN 8 - -;---------------------------------------- - -ttmath_adc_x64 PROC - ; rcx = p1 - ; rdx = p2 - ; r8 = nSize - ; r9 = nCarry - - xor rax, rax - xor r11, r11 - sub rax, r9 ; sets CARRY if r9 != 0 - - ALIGN 16 - loop1: - mov rax,qword ptr [rdx + r11 * 8] - adc qword ptr [rcx + r11 * 8], rax - lea r11, [r11+1] - dec r8 - jnz loop1 - - setc al - movzx rax, al - - ret - -ttmath_adc_x64 ENDP - -;---------------------------------------- - - ALIGN 8 - -;---------------------------------------- - -ttmath_addindexed_x64 PROC - - ; rcx = p1 - ; rdx = nSize - ; r8 = nPos - ; r9 = nValue - - xor rax, rax ; rax = result - sub rdx, r8 ; rdx = remaining count of uints - - add qword ptr [rcx + r8 * 8], r9 - jc next1 - - ret - -next1: - mov r9, 1 - - ALIGN 16 -loop1: - dec rdx - jz done_with_cy - lea r8, [r8+1] - add qword ptr [rcx + r8 * 8], r9 - jc loop1 - - ret - -done_with_cy: - lea rax, [rax+1] ; rax = 1 - - ret - -ttmath_addindexed_x64 ENDP - -;---------------------------------------- - - ALIGN 8 - -;---------------------------------------- - -ttmath_addindexed2_x64 PROC - - ; rcx = p1 (pointer) - ; rdx = b (value size) - ; r8 = nPos - ; r9 = nValue1 - ; [rsp+0x28] = nValue2 - - xor rax, rax ; return value - mov r11, rcx ; table - sub rdx, r8 ; rdx = remaining count of uints - mov r10, [rsp+028h] ; r10 = nValue2 - - add qword ptr [r11 + r8 * 8], r9 - lea r8, [r8+1] - lea rdx, [rdx-1] - adc qword ptr [r11 + r8 * 8], r10 - jc next - ret - - ALIGN 16 -loop1: - lea r8, [r8+1] - add qword ptr [r11 + r8 * 8], 1 - jc next - ret - -next: - dec rdx ; does not modify CY too... - jnz loop1 - lea rax, [rax+1] - ret - -ttmath_addindexed2_x64 ENDP - - - -;---------------------------------------- - - ALIGN 8 - -;---------------------------------------- - - -ttmath_addvector_x64 PROC - ; rcx = ss1 - ; rdx = ss2 - ; r8 = ss1_size - ; r9 = ss2_size - ; [rsp+0x28] = result - - mov r10, [rsp+028h] - sub r8, r9 - xor r11, r11 ; r11=0, cf=0 - - ALIGN 16 - loop1: - mov rax, qword ptr [rcx + r11 * 8] - adc rax, qword ptr [rdx + r11 * 8] - mov qword ptr [r10 + r11 * 8], rax - inc r11 - dec r9 - jnz loop1 - - adc r9, r9 ; r9 has the cf state - - or r8, r8 - jz done - - neg r9 ; setting cf from r9 - mov r9, 0 ; don't use xor here (cf is used) - loop2: - mov rax, qword ptr [rcx + r11 * 8] - adc rax, r9 - mov qword ptr [r10 + r11 * 8], rax - inc r11 - dec r8 - jnz loop2 - - adc r8, r8 - mov rax, r8 - - ret - -done: - mov rax, r9 - ret - -ttmath_addvector_x64 ENDP - - -;---------------------------------------- - - ALIGN 8 - -;---------------------------------------- - -ttmath_sbb_x64 PROC - - ; rcx = p1 - ; rdx = p2 - ; r8 = nCount - ; r9 = nCarry - - xor rax, rax - xor r11, r11 - sub rax, r9 ; sets CARRY if r9 != 0 - - ALIGN 16 - loop1: - mov rax,qword ptr [rdx + r11 * 8] - sbb qword ptr [rcx + r11 * 8], rax - lea r11, [r11+1] - dec r8 - jnz loop1 - - setc al - movzx rax, al - - ret - -ttmath_sbb_x64 ENDP - -;---------------------------------------- - - ALIGN 8 - -;---------------------------------------- - -ttmath_subindexed_x64 PROC - ; rcx = p1 - ; rdx = nSize - ; r8 = nPos - ; r9 = nValue - - sub rdx, r8 ; rdx = remaining count of uints - - ALIGN 16 -loop1: - sub qword ptr [rcx + r8 * 8], r9 - jnc done - - lea r8, [r8+1] - mov r9, 1 - dec rdx - jnz loop1 - - mov rax, 1 - ret - -done: - xor rax, rax - ret - -ttmath_subindexed_x64 ENDP - - - -;---------------------------------------- - - ALIGN 8 - -;---------------------------------------- - -; the same asm code as in addvector_x64 only two instructions 'adc' changed to 'sbb' - -ttmath_subvector_x64 PROC - ; rcx = ss1 - ; rdx = ss2 - ; r8 = ss1_size - ; r9 = ss2_size - ; [rsp+0x28] = result - - mov r10, [rsp+028h] - sub r8, r9 - xor r11, r11 ; r11=0, cf=0 - - ALIGN 16 - loop1: - mov rax, qword ptr [rcx + r11 * 8] - sbb rax, qword ptr [rdx + r11 * 8] - mov qword ptr [r10 + r11 * 8], rax - inc r11 - dec r9 - jnz loop1 - - adc r9, r9 ; r9 has the cf state - - or r8, r8 - jz done - - neg r9 ; setting cf from r9 - mov r9, 0 ; don't use xor here (cf is used) - loop2: - mov rax, qword ptr [rcx + r11 * 8] - sbb rax, r9 - mov qword ptr [r10 + r11 * 8], rax - inc r11 - dec r8 - jnz loop2 - - adc r8, r8 - mov rax, r8 - - ret - -done: - mov rax, r9 - ret - -ttmath_subvector_x64 ENDP - - - - -;---------------------------------------- - - ALIGN 8 - -;---------------------------------------- - -ttmath_rcl_x64 PROC - ; rcx = p1 - ; rdx = b - ; r8 = nLowestBit - - mov r11, rcx ; table - xor r10, r10 - neg r8 ; CY set if r8 <> 0 - - ALIGN 16 -loop1: - rcl qword ptr [r11 + r10 * 8], 1 - lea r10, [r10+1] - dec rdx - jnz loop1 - - setc al - movzx rax, al - - ret - -ttmath_rcl_x64 ENDP - -;---------------------------------------- - - ALIGN 8 - -;---------------------------------------- - -ttmath_rcr_x64 PROC - ; rcx = p1 - ; rdx = nSize - ; r8 = nLowestBit - - xor r10, r10 - neg r8 ; CY set if r8 <> 0 - - ALIGN 16 -loop1: - rcr qword ptr -8[rcx + rdx * 8], 1 - dec rdx - jnz loop1 - - setc al - movzx rax, al - - ret - -ttmath_rcr_x64 ENDP - -;---------------------------------------- - - ALIGN 8 - -;---------------------------------------- - -ttmath_div_x64 PROC - - ; rcx = &Hi - ; rdx = &Lo - ; r8 = nDiv - - mov r11, rcx - mov r10, rdx - - mov rdx, qword ptr [r11] - mov rax, qword ptr [r10] - div r8 - mov qword ptr [r10], rdx ; remainder - mov qword ptr [r11], rax ; value - - ret - -ttmath_div_x64 ENDP - -;---------------------------------------- - - ALIGN 8 - -;---------------------------------------- - -ttmath_rcl2_x64 PROC - ; rcx = p1 - ; rdx = nSize - ; r8 = bits - ; r9 = c - - push rbx - - mov r10, rcx ; r10 = p1 - xor rax, rax - - mov rcx, 64 - sub rcx, r8 - - mov r11, -1 - shr r11, cl ; r11 = mask - - mov rcx, r8 ; rcx = count of bits - - mov rbx, rax ; rbx = old value = 0 - or r9, r9 - cmovnz rbx, r11 ; if (c) then old value = mask - - mov r9, rax ; r9 = index (0..nSize-1) - - ALIGN 16 -loop1: - rol qword ptr [r10+r9*8], cl - mov rax, qword ptr [r10+r9*8] - and rax, r11 - xor qword ptr [r10+r9*8], rax - or qword ptr [r10+r9*8], rbx - mov rbx, rax - - lea r9, [r9+1] - dec rdx - - jnz loop1 - - and rax, 1 - pop rbx - ret - -ttmath_rcl2_x64 ENDP - -;---------------------------------------- - - ALIGN 8 - -;---------------------------------------- - -ttmath_rcr2_x64 PROC - ; rcx = p1 - ; rdx = nSize - ; r8 = bits - ; r9 = c - - push rbx - mov r10, rcx ; r10 = p1 - xor rax, rax - - mov rcx, 64 - sub rcx, r8 - - mov r11, -1 - shl r11, cl ; r11 = mask - - mov rcx, r8 ; rcx = count of bits - - mov rbx, rax ; rbx = old value = 0 - or r9, r9 - cmovnz rbx, r11 ; if (c) then old value = mask - - mov r9, rdx ; r9 = index (0..nSize-1) - lea r9, [r9-1] - - ALIGN 16 -loop1: - ror qword ptr [r10+r9*8], cl - mov rax, qword ptr [r10+r9*8] - and rax, r11 - xor qword ptr [r10+r9*8], rax - or qword ptr [r10+r9*8], rbx - mov rbx, rax - - lea r9, [r9-1] - dec rdx - - jnz loop1 - - rol rax, 1 - and rax, 1 - pop rbx - - ret - -ttmath_rcr2_x64 ENDP - -END diff --git a/include/geos/math/DD.h b/include/geos/math/DD.h new file mode 100644 index 0000000000..7bcbb18382 --- /dev/null +++ b/include/geos/math/DD.h @@ -0,0 +1,204 @@ +/********************************************************************** + * + * GEOS - Geometry Engine Open Source + * http://geos.osgeo.org + * + * Copyright (C) 2020 Crunchy Data + * + * This is free software; you can redistribute and/or modify it under + * the terms of the GNU Lesser General Public Licence as published + * by the Free Software Foundation. + * See the COPYING file for more information. + * + **********************************************************************/ + +/** + * Implements extended-precision floating-point numbers + * which maintain 106 bits (approximately 30 decimal digits) of precision. + *

+ * A DoubleDouble uses a representation containing two double-precision values. + * A number x is represented as a pair of doubles, x.hi and x.lo, + * such that the number represented by x is x.hi + x.lo, where + *

+ *    |x.lo| <= 0.5*ulp(x.hi)
+ * 
+ * and ulp(y) means "unit in the last place of y". + * The basic arithmetic operations are implemented using + * convenient properties of IEEE-754 floating-point arithmetic. + *

+ * The range of values which can be represented is the same as in IEEE-754. + * The precision of the representable numbers + * is twice as great as IEEE-754 double precision. + *

+ * The correctness of the arithmetic algorithms relies on operations + * being performed with standard IEEE-754 double precision and rounding. + * This is the Java standard arithmetic model, but for performance reasons + * Java implementations are not + * constrained to using this standard by default. + * Some processors (notably the Intel Pentium architecture) perform + * floating point operations in (non-IEEE-754-standard) extended-precision. + * A JVM implementation may choose to use the non-standard extended-precision + * as its default arithmetic mode. + * To prevent this from happening, this code uses the + * Java strictfp modifier, + * which forces all operations to take place in the standard IEEE-754 rounding model. + *

+ * The API provides both a set of value-oriented operations + * and a set of mutating operations. + * Value-oriented operations treat DoubleDouble values as + * immutable; operations on them return new objects carrying the result + * of the operation. This provides a simple and safe semantics for + * writing DoubleDouble expressions. However, there is a performance + * penalty for the object allocations required. + * The mutable interface updates object values in-place. + * It provides optimum memory performance, but requires + * care to ensure that aliasing errors are not created + * and constant values are not changed. + *

+ * For example, the following code example constructs three DD instances: + * two to hold the input values and one to hold the result of the addition. + *

+ *     DD a = new DD(2.0);
+ *     DD b = new DD(3.0);
+ *     DD c = a.add(b);
+ * 
+ * In contrast, the following approach uses only one object: + *
+ *     DD a = new DD(2.0);
+ *     a.selfAdd(3.0);
+ * 
+ *

+ * This implementation uses algorithms originally designed variously by + * Knuth, Kahan, Dekker, and Linnainmaa. + * Douglas Priest developed the first C implementation of these techniques. + * Other more recent C++ implementation are due to Keith M. Briggs and David Bailey et al. + * + *

References

+ *
    + *
  • Priest, D., Algorithms for Arbitrary Precision Floating Point Arithmetic, + * in P. Kornerup and D. Matula, Eds., Proc. 10th Symposium on Computer Arithmetic, + * IEEE Computer Society Press, Los Alamitos, Calif., 1991. + *
  • Yozo Hida, Xiaoye S. Li and David H. Bailey, + * Quad-Double Arithmetic: Algorithms, Implementation, and Application, + * manuscript, Oct 2000; Lawrence Berkeley National Laboratory Report BNL-46996. + *
  • David Bailey, High Precision Software Directory; + * http://crd.lbl.gov/~dhbailey/mpdist/index.html + *
+ * + * + * @author Martin Davis + * + */ + +#ifndef GEOS_MATH_DD_H +#define GEOS_MATH_DD_H + +#include + +namespace geos { +namespace math { // geos.math + +/** + * \class DD + * + * \brief + * Wrapper for DoubleDouble higher precision mathematics + * operations. + */ +class GEOS_DLL DD { + private: + static constexpr double SPLIT = 134217729.0; // 2^27+1, for IEEE double + double hi; + double lo; + + int magnitude(double x) const; + int signum() const; + DD rint() const; + + + public: + DD(double p_hi, double p_lo) : hi(p_hi), lo(p_lo) {}; + DD(double x) : hi(x), lo(0.0) {}; + DD(const DD &dd) : hi(dd.hi), lo(dd.lo) {}; + DD() : hi(0.0), lo(0.0) {}; + + bool operator==(const DD &rhs) const + { + return hi == rhs.hi && lo == rhs.lo; + } + + bool operator!=(const DD &rhs) const + { + return hi != rhs.hi || lo != rhs.lo; + } + + bool operator<(const DD &rhs) const + { + return (hi < rhs.hi) || (hi == rhs.hi && lo < rhs.lo); + } + + bool operator<=(const DD &rhs) const + { + return (hi < rhs.hi) || (hi == rhs.hi && lo <= rhs.lo); + } + + bool operator>(const DD &rhs) const + { + return (hi > rhs.hi) || (hi == rhs.hi && lo > rhs.lo); + } + + bool operator>=(const DD &rhs) const + { + return (hi > rhs.hi) || (hi == rhs.hi && lo >= rhs.lo); + } + + friend DD operator+ (const DD &lhs, const DD &rhs); + friend DD operator+ (const DD &lhs, double rhs); + friend DD operator- (const DD &lhs, const DD &rhs); + friend DD operator- (const DD &lhs, double rhs); + friend DD operator* (const DD &lhs, const DD &rhs); + friend DD operator* (const DD &lhs, double rhs); + friend DD operator/ (const DD &lhs, const DD &rhs); + friend DD operator/ (const DD &lhs, double rhs); + + static DD determinant(const DD &x1, const DD &y1, const DD &x2, const DD &y2); + static DD determinant(double x1, double y1, double x2, double y2); + static DD abs(const DD &d); + static DD pow(const DD &d, int exp); + static DD trunc(const DD &d); + + bool isNaN() const; + bool isNegative() const; + bool isPositive() const; + bool isZero() const; + double doubleValue() const; + double ToDouble() const { return doubleValue(); } + int intValue() const; + DD negate() const; + DD reciprocal() const; + DD floor() const; + DD ceil() const; + + void selfAdd(const DD &d); + void selfAdd(double p_hi, double p_lo); + void selfAdd(double y); + + void selfSubtract(const DD &d); + void selfSubtract(double p_hi, double p_lo); + void selfSubtract(double y); + + void selfMultiply(double p_hi, double p_lo); + void selfMultiply(const DD &d); + void selfMultiply(double y); + + void selfDivide(double p_hi, double p_lo); + void selfDivide(const DD &d); + void selfDivide(double y); +}; + + +} // namespace geos::math +} // namespace geos + + +#endif // GEOS_MATH_DD_H diff --git a/include/geos/math/Makefile.am b/include/geos/math/Makefile.am new file mode 100644 index 0000000000..5396b95171 --- /dev/null +++ b/include/geos/math/Makefile.am @@ -0,0 +1,11 @@ +# +# This file is part of project GEOS (http://trac.osgeo.org/geos/) +# +SUBDIRS = + +EXTRA_DIST = + +geosdir = $(includedir)/geos/math + +geos_HEADERS = \ + DD.h diff --git a/src/Makefile.am b/src/Makefile.am index 1bba8e87ef..ea465248f8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -7,6 +7,7 @@ SUBDIRS = \ index \ io \ linearref \ + math \ noding \ operation \ planargraph \ @@ -39,6 +40,7 @@ libgeos_la_LIBADD = \ index/libindex.la \ io/libio.la \ linearref/liblinearref.la \ + math/libmath.la \ noding/libnoding.la \ operation/liboperation.la \ planargraph/libplanargraph.la \ diff --git a/src/algorithm/CGAlgorithmsDD.cpp b/src/algorithm/CGAlgorithmsDD.cpp index 1ec67c8276..57f8d20927 100644 --- a/src/algorithm/CGAlgorithmsDD.cpp +++ b/src/algorithm/CGAlgorithmsDD.cpp @@ -35,7 +35,7 @@ namespace { double constexpr DP_SAFE_EPSILON = 1e-15; inline int -OrientationDD(DD const& dd) +OrientationDD(const DD &dd) { static DD const zero(0.0); if(dd < zero) { @@ -49,10 +49,7 @@ OrientationDD(DD const& dd) return CGAlgorithmsDD::STRAIGHT; } -// inline std::string ToStringDD(DD const& dd) -// { -// return dd.ToString(); -// } + } namespace geos { diff --git a/src/algorithm/InteriorPointArea.cpp b/src/algorithm/InteriorPointArea.cpp index c455948bad..12368985f7 100644 --- a/src/algorithm/InteriorPointArea.cpp +++ b/src/algorithm/InteriorPointArea.cpp @@ -200,7 +200,6 @@ class InteriorPointPolygon { // edge intersects scan line, so add a crossing double xInt = intersection(p0, p1, scanY); crossings.push_back(xInt); - //checkIntersectionDD(p0, p1, scanY, xInt); } void findBestMidpoint(vector& crossings) diff --git a/src/geom/LineString.cpp b/src/geom/LineString.cpp index 65f86a0d79..ac5d7fe67f 100644 --- a/src/geom/LineString.cpp +++ b/src/geom/LineString.cpp @@ -45,7 +45,7 @@ using namespace geos::algorithm; namespace geos { namespace geom { // geos::geom -LineString::~LineString(){}; +LineString::~LineString(){} /*protected*/ LineString::LineString(const LineString& ls) diff --git a/src/math/DD.cpp b/src/math/DD.cpp new file mode 100644 index 0000000000..673e921757 --- /dev/null +++ b/src/math/DD.cpp @@ -0,0 +1,403 @@ +/********************************************************************** + * + * GEOS - Geometry Engine Open Source + * http://geos.osgeo.org + * + * Copyright (C) 2020 Crunchy Data + * + * This is free software; you can redistribute and/or modify it under + * the terms of the GNU Lesser General Public Licence as published + * by the Free Software Foundation. + * See the COPYING file for more information. + * + **********************************************************************/ + +#include + +#include +#include + +namespace geos { +namespace math { // geos.util + + +/* private */ +int +DD::magnitude(double x) const +{ + double xAbs = std::fabs(x); + double xLog10 = std::log(xAbs) / std::log(10); + int xMag = (int) std::floor(xLog10); + /** + * Since log computation is inexact, there may be an off-by-one error + * in the computed magnitude. + * Following tests that magnitude is correct, and adjusts it if not + */ + double xApprox = std::pow(10, xMag); + if (xApprox * 10 <= xAbs) + xMag += 1; + + return xMag; +} + +/* public */ +bool DD::isNaN() const +{ + return std::isnan(hi); +} +/* public */ +bool DD::isNegative() const +{ + return hi < 0.0 || (hi == 0.0 && lo < 0.0); +} +/* public */ +bool DD::isPositive() const +{ + return hi > 0.0 || (hi == 0.0 && lo > 0.0); +} +/* public */ +bool DD::isZero() const +{ + return hi == 0.0 && lo == 0.0; +} + +/* public */ +double DD::doubleValue() const +{ + return hi + lo; +} + +/* public */ +int DD::intValue() const +{ + return (int) hi; +} + +/* public */ +void DD::selfAdd(const DD &y) +{ + return selfAdd(y.hi, y.lo); +} + +/* public */ +void DD::selfAdd(double yhi, double ylo) +{ + double H, h, T, t, S, s, e, f; + S = hi + yhi; + T = lo + ylo; + e = S - hi; + f = T - lo; + s = S-e; + t = T-f; + s = (yhi-e)+(hi-s); + t = (ylo-f)+(lo-t); + e = s+T; H = S+e; h = e+(S-H); e = t+h; + + double zhi = H + e; + double zlo = e + (H - zhi); + hi = zhi; + lo = zlo; + return; +} + +/* public */ +void DD::selfAdd(double y) +{ + double H, h, S, s, e, f; + S = hi + y; + e = S - hi; + s = S - e; + s = (y - e) + (hi - s); + f = s + lo; + H = S + f; + h = f + (S - H); + hi = H + h; + lo = h + (H - hi); + return; +} + +/* public */ +DD operator+(const DD &lhs, const DD &rhs) +{ + DD rv(lhs.hi, lhs.lo); + rv.selfAdd(rhs); + return rv; +} + +/* public */ +DD operator+(const DD &lhs, double rhs) +{ + DD rv(lhs.hi, lhs.lo); + rv.selfAdd(rhs); + return rv; +} + +/* public */ +void DD::selfSubtract(const DD &d) +{ + return selfAdd(-1*d.hi, -1*d.lo); +} + +/* public */ +void DD::selfSubtract(double p_hi, double p_lo) +{ + return selfAdd(-1*p_hi, -1*p_lo); +} + +/* public */ +void DD::selfSubtract(double y) +{ + return selfAdd(-1*y, 0.0); +} + +/* public */ +DD operator-(const DD &lhs, const DD &rhs) +{ + DD rv(lhs.hi, lhs.lo); + rv.selfSubtract(rhs); + return rv; +} + +/* public */ +DD operator-(const DD &lhs, double rhs) +{ + DD rv(lhs.hi, lhs.lo); + rv.selfSubtract(rhs); + return rv; +} + +/* public */ +void DD::selfMultiply(double yhi, double ylo) +{ + double hx, tx, hy, ty, C, c; + C = SPLIT * hi; hx = C-hi; c = SPLIT * yhi; + hx = C-hx; tx = hi-hx; hy = c-yhi; + C = hi*yhi; hy = c-hy; ty = yhi-hy; + c = ((((hx*hy-C)+hx*ty)+tx*hy)+tx*ty)+(hi*ylo+lo*yhi); + double zhi = C+c; hx = C-zhi; + double zlo = c+hx; + hi = zhi; + lo = zlo; + return; +} + +/* public */ +void DD::selfMultiply(DD const &d) +{ + return selfMultiply(d.hi, d.lo); +} + +/* public */ +void DD::selfMultiply(double y) +{ + return selfMultiply(y, 0.0); +} + +/* public */ +DD operator*(const DD &lhs, const DD &rhs) +{ + DD rv(lhs.hi, lhs.lo); + rv.selfMultiply(rhs); + return rv; +} + +/* public */ +DD operator*(const DD &lhs, double rhs) +{ + DD rv(lhs.hi, lhs.lo); + rv.selfMultiply(rhs); + return rv; +} + + +/* public */ +void DD::selfDivide(double yhi, double ylo) +{ + double hc, tc, hy, ty, C, c, U, u; + C = hi/yhi; c = SPLIT*C; hc =c-C; + u = SPLIT*yhi; hc = c-hc; + tc = C-hc; hy = u-yhi; U = C * yhi; + hy = u-hy; ty = yhi-hy; + u = (((hc*hy-U)+hc*ty)+tc*hy)+tc*ty; + c = ((((hi-U)-u)+lo)-C*ylo)/yhi; + u = C+c; + hi = u; + lo = (C-u)+c; + return; +} + +/* public */ +void DD::selfDivide(const DD &d) +{ + return selfDivide(d.hi, d.lo); +} + +/* public */ +void DD::selfDivide(double y) +{ + return selfDivide(y, 0.0); +} + +/* public */ +DD operator/(const DD &lhs, const DD &rhs) +{ + DD rv(lhs.hi, lhs.lo); + rv.selfDivide(rhs); + return rv; +} + +/* public */ +DD operator/(const DD &lhs, double rhs) +{ + DD rv(lhs.hi, lhs.lo); + rv.selfDivide(rhs); + return rv; +} + +/* public */ +DD DD::negate() const +{ + DD rv(hi, lo); + if (rv.isNaN()) + { + return rv; + } + rv.hi = -hi; + rv.lo = -lo; + return rv; +} + +/* public static */ +DD DD::reciprocal() const +{ + double hc, tc, hy, ty, C, c, U, u; + C = 1.0/hi; + c = SPLIT*C; + hc = c-C; + u = SPLIT*hi; + hc = c-hc; tc = C-hc; hy = u-hi; U = C*hi; hy = u-hy; ty = hi-hy; + u = (((hc*hy-U)+hc*ty)+tc*hy)+tc*ty; + c = ((((1.0-U)-u))-C*lo)/hi; + double zhi = C+c; + double zlo = (C-zhi)+c; + return DD(zhi, zlo); +} + +DD DD::floor() const +{ + DD rv(hi, lo); + if (isNaN()) return rv; + double fhi = std::floor(hi); + double flo = 0.0; + // Hi is already integral. Floor the low word + if (fhi == hi) { + flo = std::floor(lo); + } + // do we need to renormalize here? + rv.hi = fhi; + rv.lo = flo; + return rv; +} + +DD DD::ceil() const +{ + DD rv(hi, lo); + if (isNaN()) return rv; + double fhi = std::ceil(hi); + double flo = 0.0; + // Hi is already integral. Ceil the low word + if (fhi == hi) { + flo = std::ceil(lo); + // do we need to renormalize here? + } + rv.hi = fhi; + rv.lo = flo; + return rv; +} + +int DD::signum() const +{ + if (hi > 0) return 1; + if (hi < 0) return -1; + if (lo > 0) return 1; + if (lo < 0) return -1; + return 0; +} + +DD DD::rint() const +{ + DD rv(hi, lo); + if (isNaN()) return rv; + return (rv + 0.5).floor(); +} + +/* public static */ +DD DD::trunc(const DD &d) +{ + DD rv(d); + if (rv.isNaN()) return rv; + if (rv.isPositive()) + return rv.floor(); + return rv.ceil(); +} + +/* public static */ +DD DD::abs(const DD &d) +{ + DD rv(d); + if (rv.isNaN()) return rv; + if (rv.isNegative()) + return rv.negate(); + + return rv; +} + +/* public static */ +DD DD::determinant(const DD &x1, const DD &y1, const DD &x2, const DD &y2) +{ + return (x1 * y2) - (y1 * x2); +} + +/* public static */ +DD DD::determinant(double x1, double y1, double x2, double y2) +{ + return determinant(DD(x1), DD(y1), DD(x2), DD(y2) ); +} + +/** +* Computes the value of this number raised to an integral power. +* Follows semantics of Java Math.pow as closely as possible. +*/ +/* public static */ +DD DD::pow(const DD &d, int exp) +{ + if (exp == 0.0) + return DD(1.0); + + DD r(d); + DD s(1.0); + int n = std::abs(exp); + + if (n > 1) { + /* Use binary exponentiation */ + while (n > 0) { + if (n % 2 == 1) { + s.selfMultiply(r); + } + n /= 2; + if (n > 0) + r = r*r; + } + } else { + s = r; + } + + /* Compute the reciprocal if n is negative. */ + if (exp < 0) + return s.reciprocal(); + return s; +} + + +} +} diff --git a/src/math/Makefile.am b/src/math/Makefile.am new file mode 100644 index 0000000000..c30e97eac5 --- /dev/null +++ b/src/math/Makefile.am @@ -0,0 +1,13 @@ +# +# This file is part of project GEOS (http://trac.osgeo.org/geos/) +# +SUBDIRS = + +noinst_LTLIBRARIES = libmath.la + +AM_CPPFLAGS = -I$(top_srcdir)/include + +libmath_la_SOURCES = \ + DD.cpp + +libmath_la_LIBADD = diff --git a/tests/unit/Makefile.am b/tests/unit/Makefile.am index 88c4816f99..3c836fc8ee 100644 --- a/tests/unit/Makefile.am +++ b/tests/unit/Makefile.am @@ -151,6 +151,7 @@ geos_unit_SOURCES = \ io/WKTWriterTest.cpp \ io/WriterTest.cpp \ linearref/LengthIndexedLineTest.cpp \ + math/DDTest.cpp \ noding/BasicSegmentStringTest.cpp \ noding/NodedSegmentStringTest.cpp \ noding/OrientedCoordinateArrayTest.cpp \ diff --git a/tests/unit/math/DDTest.cpp b/tests/unit/math/DDTest.cpp new file mode 100644 index 0000000000..00a29b8ffb --- /dev/null +++ b/tests/unit/math/DDTest.cpp @@ -0,0 +1,414 @@ +// +// Test Suite for geos::util::UniqueCoordinateArrayFilter class. + +// geos + +#include +#include + +// tut +#include +#include + +// std +#include +#include + +using namespace geos::math; + +namespace tut { +// +// Test Group +// + +// Common data used in test cases. +struct test_dd_data { + + double eps; + DD pi; + DD e; + + + void ensure_dd_equals(const char *str, const DD &d1, const DD &d2, double tolerance) + { + DD delta = DD::abs(d1 - d2); + double diff = delta.doubleValue(); + ensure(str, diff <= tolerance); + } + + void checkTrunc(const DD &x, const DD &expected) + { + DD trunc = DD::trunc(x); + ensure("checkTrunc", trunc == expected); + } + + void checkDeterminant(double x1, double y1, double x2, double y2, double expected, double errBound) + { + DD det = DD::determinant(x1, y1, x2, y2); + //ensure_equals("1", Angle::angle(Coordinate(10, 0)), 0.0, TOL); + ensure_dd_equals("checkDeterminant", det, DD(expected), errBound); + } + + void checkDeterminantDD(double x1, double y1, double x2, double y2, double expected, double errBound) + { + DD det = DD::determinant(DD(x1), DD(y1), DD(x2), DD(y2)); + ensure_dd_equals("checkDeterminantDD", det, DD(expected), errBound); + } + + void checkAddMult2(const DD &dd) + { + DD sum = dd + dd; + DD prod = dd * DD(2.0); + ensure_dd_equals("checkAddMult2", sum, prod, 0.0); + } + + void checkMultiplyDivide(const DD &a, const DD &b, double errBound) + { + DD a2 = (a * b) / b; + ensure_dd_equals("checkMultiplyDivide", a, a2, errBound); + } + + void checkDivideMultiply(const DD &a, const DD &b, double errBound) + { + DD a2 = (a / b) * b; + ensure_dd_equals("checkDivideMultiply", a, a2, errBound); + } + + /** + * Computes (a+b)^2 in two different ways and compares the result. + * For correct results, a and b should be integers. + */ + void checkBinomialSquare(double a, double b) + { + // binomial square + DD add(a); + DD bdd(b); + DD aPlusb = add + bdd; + DD abSq = aPlusb * aPlusb; + + // expansion + DD a2dd = add * add; + DD b2dd = bdd * bdd; + DD ab = add * bdd; + DD sum = b2dd + ab + ab; + DD diff = abSq - a2dd; + DD delta = diff - sum; + + ensure("isSame", diff == sum); + ensure("isDeltaZero", delta.isZero()); + } + + void checkBinomial2(double a, double b) + { + // binomial product + DD add(a); + DD bdd(b); + DD aPlusb = add + bdd; + DD aSubb = add - bdd; + DD abProd = aPlusb * aSubb; + + // expansion + DD a2dd = add * add; + DD b2dd = bdd * bdd; + + // this should equal b^2 + DD diff = (abProd - a2dd).negate(); + DD delta = diff - b2dd; + + ensure("isSame", diff == b2dd); + ensure("isDeltaZero", delta.isZero()); + } + + void checkReciprocal(double x, double errBound) + { + DD xdd(x); + DD rr = xdd.reciprocal().reciprocal(); + double err = (xdd - rr).doubleValue(); + ensure("checkReciprocal", err <= errBound); + } + + DD slowPow(const DD &x, int exp) + { + if (exp == 0) + return DD(1.0); + + int n = std::abs(exp); + // MD - could use binary exponentiation for better precision & speed + DD pow(x); + for (int i = 1; i < n; i++) { + pow = pow * x; + } + if (exp < 0) { + return pow.reciprocal(); + } + return pow; + } + + void checkPow(double x, int exp, double errBound) + { + DD xdd(x); + DD pow = DD::pow(xdd, exp); + DD pow2 = slowPow(xdd, exp); + double err = (pow - pow2).doubleValue(); + ensure("checkPow", err <= errBound); + } + + + DD arctan(DD x) + { + DD t = x; + DD t2 = t*t; + DD at(0.0); + DD two(2.0); + int k = 0; + DD d(1.0); + int sign = 1; + while (t.doubleValue() > eps) { + k++; + if (sign < 0) + at = at - (t / d); + else + at = at + (t / d); + + d = d + two; + t = t * t2; + sign = -sign; + } + return at; + } + + /** + * Uses Taylor series to compute e + * + * e = 1 + 1 + 1/2! + 1/3! + 1/4! + ... + */ + DD computeEByTaylorSeries() + { + DD s(2.0); + DD t(1.0); + double n = 1.0; + int i = 0; + while(t.doubleValue() > eps) + { + i++; + n += 1.0; + t = t / DD(n); + s = s + t; + } + return s; + } + + /** + * Uses Machin's arctangent formula to compute Pi: + * + * Pi / 4 = 4 arctan(1/5) - arctan(1/239) + */ + + DD computePiByMachin() + { + DD t1 = DD(1.0) / DD(5.0); + DD t2 = DD(1.0) / DD(239.0); + DD pi4 = (DD(4.0) * arctan(t1)) - arctan(t2); + DD pi = DD(4.0) * pi4; + return pi; + } + + test_dd_data(): + eps(1.23259516440783e-32), /* = 2^-106 */ + pi(DD(3.141592653589793116e+00, 1.224646799147353207e-16)), + e(DD(2.718281828459045091e+00, 1.445646891729250158e-16)) + {} + +}; + +typedef test_group group; +typedef group::object object; + +group test_dd_group("geos::math::DD"); + +// +// Test Cases +// + +// Test PI calculation +template<> +template<> +void object::test<1> +() +{ + DD testPi = computePiByMachin(); + double err = std::abs((testPi - pi).doubleValue()); + // std::cout << "Difference from PI = " << err << std::endl; + ensure("Test PI calculation", err < 8*eps); +} + +// Test E calculation +template<> +template<> +void object::test<2> +() +{ + DD testE = computeEByTaylorSeries(); + double err = std::abs((testE - e).doubleValue()); + // std::cout << "Difference from E = " << err << std::endl; + ensure("Test E calculation", err < eps); +} + + +// Test NaN +template<> +template<> +void object::test<3> +() +{ + DD nan = DD(1.0) / DD(0.0); + ensure("isNan", nan.isNaN()); + ensure("isNan", (DD(1.0) * nan).isNaN()); +} + +// testAddMult2 +template<> +template<> +void object::test<4> +() +{ + checkAddMult2(DD(3.0)); + checkAddMult2(DD(pi)); +} + + +// testMultiplyDivide +template<> +template<> +void object::test<5> +() +{ + checkMultiplyDivide(DD(pi), DD(e), 1e-30); + checkMultiplyDivide(DD(DD(2.0)*pi), DD(e), 1e-30); + checkMultiplyDivide(DD(DD(0.5)*pi), DD(e), 1e-30); + checkMultiplyDivide(DD(39.4), DD(10), 1e-30); +} + + +// testDivideMultiply +template<> +template<> +void object::test<6> +() +{ + checkDivideMultiply(DD(pi), DD(e), 1e-30); + checkDivideMultiply(DD(39.4), DD(10), 1e-30); +} + + +// testTrunc +template<> +template<> +void object::test<7> +() +{ + checkTrunc(DD(1e16) - DD(1), DD(1e16) - DD(1)); + // the appropriate error bound is determined empirically + checkTrunc(DD(pi), DD(3)); + checkTrunc(DD(999.999), DD(999)); + + checkTrunc(DD(e).negate(), DD(-2)); + checkTrunc(DD(-999.999), DD(-999)); +} + +// testPow +template<> +template<> +void object::test<8> +() +{ + checkPow(0, 3, 16 * eps); + checkPow(0, 3, 16 * eps); + checkPow(14, 3, 16 * eps); + checkPow(3, -5, 16 * eps); + checkPow(-3, 5, 16 * eps); + checkPow(-3, -5, 16 * eps); + checkPow(0.12345, -5, 1e5 * eps); +} + + +// testReciprocal +template<> +template<> +void object::test<9> +() +{ + checkReciprocal(3.0, 0); + checkReciprocal(99.0, 1e-29); + checkReciprocal(999.0, 0); + checkReciprocal(314159269.0, 0); +} + +// testDeterminant +template<> +template<> +void object::test<10> +() +{ + checkDeterminant(3, 8, 4, 6, -14, 0); + checkDeterminantDD(3, 8, 4, 6, -14, 0); +} + +// testDeterminantRobust +template<> +template<> +void object::test<11> +() +{ + checkDeterminant(1.0e9, 1.0e9 - 1, 1.0e9 - 1, 1.0e9 - 2, -1, 0); + checkDeterminantDD(1.0e9, 1.0e9 - 1, 1.0e9 - 1, 1.0e9 - 2, -1, 0); +} + + +// testBinom +template<> +template<> +void object::test<12> +() +{ + checkBinomialSquare(100.0, 1.0); + checkBinomialSquare(1000.0, 1.0); + checkBinomialSquare(10000.0, 1.0); + checkBinomialSquare(100000.0, 1.0); + checkBinomialSquare(1000000.0, 1.0); + checkBinomialSquare(1e8, 1.0); + checkBinomialSquare(1e10, 1.0); + checkBinomialSquare(1e14, 1.0); + // Following call will fail, because it requires 32 digits of precision + // checkBinomialSquare(1e16, 1.0); + + checkBinomialSquare(1e14, 291.0); + checkBinomialSquare(5e14, 291.0); + checkBinomialSquare(5e14, 345291.0); +} + +// testBinom2 +template<> +template<> +void object::test<13> +() +{ + checkBinomial2(100.0, 1.0); + checkBinomial2(1000.0, 1.0); + checkBinomial2(10000.0, 1.0); + checkBinomial2(100000.0, 1.0); + checkBinomial2(1000000.0, 1.0); + checkBinomial2(1e8, 1.0); + checkBinomial2(1e10, 1.0); + checkBinomial2(1e14, 1.0); + + checkBinomial2(1e14, 291.0); + + checkBinomial2(5e14, 291.0); + checkBinomial2(5e14, 345291.0); +} + + + +} // namespace tut +