33 Commits
0.8.2 ... 0.8.4

Author SHA1 Message Date
3231780a85 changed: version of the library: 0.8.4
git-svn-id: svn://ttmath.org/publicrep/ttmath/trunk@138 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-05-08 19:13:25 +00:00
1bae0d6cb8 changed: in ttmathtypes.h
'typedef unsigned long long int ulint' has been put inside '#ifdef TTMATH_NOASM'
         in order to not confuse a compiler while compiling with strict iso c++
         (errors about not defining 'long long' in the c++ standard)


git-svn-id: svn://ttmath.org/publicrep/ttmath/trunk@137 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-05-08 18:40:32 +00:00
277dd72fb6 fixed: UInt::AddInt() in no-asm code has incorrect assertion
changed: UInt::SubInt() in no-asm code is a little faster now
changed: small cosmetic changes in commentaries
deleted: some debug #ifdef's from UInt::Div() (in no-asm code)



git-svn-id: svn://ttmath.org/publicrep/ttmath/trunk@136 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-05-08 18:14:00 +00:00
a7a7eb7808 fixed: deleted default values for variables in some methods (file ttmathuint_x86.h)
(they should only be put in declaration)


git-svn-id: svn://ttmath.org/publicrep/ttmath/trunk@128 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-05-05 07:47:10 +00:00
e665f91682 fixed: the problem with GCC optimization on x86_64
sometimes when using -O2 or -O3 GCC doesn't set correctly
         the stack pointer (actually the stack is used for other things)
         and you can't use instructions like push/pop in assembler code.
         All the asm code in x86_64 have been rewritten, now instructions
         push/pop are not used, other thing which have access to stack 
         (like "m" (mask) constraints in Rcl2 and Rcr2) have also gone away,
         now the library works well with -O2 and -O3 and the asm code
         is a little faster



git-svn-id: svn://ttmath.org/publicrep/ttmath/trunk@127 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-05-05 07:20:10 +00:00
85945b2bb0 added: ttmathuint_x86.h, ttmathuint_x86_64.h, ttmathuint_noasm.h,
all the methods which are using assembler code have been 
         rewritten to no-asm forms, now we have:
         1. asm for x86      file: ttmathuint_x86.h
         2. asm for x86_64   file: ttmathuint_x86_64.h
         3. no asm           file: ttmathuint_noasm.h
            (it's used when macro TTMATH_NOASM is defined)
            The third form can be used on x86 and x86_64 as well and
            on other platforms with a little effort.
            (Temporarily I left there some '#ifdef's for debugging.)



git-svn-id: svn://ttmath.org/publicrep/ttmath/trunk@126 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-05-04 20:51:12 +00:00
1efe39686b added: UInt::PrintLog(const char * msg, std::ostream & output)
used for debugging purposes by macro TTMATH_LOG(msg)
         (it is used in nearly all methods in UInt class)
added:   macro TTMATH_DEBUG_LOG: when defined then TTMATH_LOG() 
         put some debug information (to std::cout)



git-svn-id: svn://ttmath.org/publicrep/ttmath/trunk@125 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-05-01 14:53:21 +00:00
d8b829f4c5 changed: version of the library: 0.8.3 now
git-svn-id: svn://ttmath.org/publicrep/ttmath/trunk@120 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-04-06 16:34:19 +00:00
fca1bc1a33 added: Objects::IsDefined(const std::string & name)
returning true if such an object is defined


git-svn-id: svn://ttmath.org/publicrep/ttmath/trunk@117 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-04-02 05:21:49 +00:00
c65857297b fixed: the parser didn't correctly treat operators for changing the base
(radix) -- operators '#' and '&', e.g.:
       '#sin(1)' was equal '0' -- there was a zero from '#' and then
       it was multipied by 'sin(1)'
       the parser didn't check whether Big::FromString() has actually
       read a proper value -- the method Big::FromString() didn't have
       something to report such a situation
fixed: Big::FromString() when the base is 10, the method reads the scientific
       part only if such a part it correctly supplied, e.g:
       '1234e10', '1234e+10', '1234e-5'
       previous '1234e' was treated as: '1234e0' (now parsing stops on 'e' and
       the 'e' can be parsed by other parsers, e.g. the mathematical
       parser -- now in the parser would be: '1234e' = '1234 * e' = '3354,3597...' )
added: to Int::FromString(): parameter 'const char ** after_source = 0'
       if exists it's pointing at the end of the parsed string
added: to UInt::FromString(), Int::FromString(), Big::FromString():
       parameter 'bool * value_read = 0' - (if exists) tells
       whether something has actually been read (at least one digit)
added: the parser checks itself for the operators for changing the base
       (operators '#' and '&')
changed: in the parser: the form with operators '#' and '&' is as follows:
       [-|+][#|&]numeric_value
       previous was: [-|+][#|&][-|+]numeric_value
removed: Big::FromString() this method doesn't longer recognize operators
       for changing the base ('#' and '&')
changed: in the parser: the short form of multiplication has the same
       priority as the normal multiplication, e.g.:
       '2x^3' = 2 * (x^3)
       previous the priority was greater than powering priority
       previous: '2x^3' = (2*x) ^ 3



git-svn-id: svn://ttmath.org/publicrep/ttmath/trunk@113 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-03-28 17:40:36 +00:00
f530635262 changed: doxygen.cfg changed lines ends: dos mode to unix mode (\r\n to \n)
git-svn-id: svn://ttmath.org/publicrep/ttmath/trunk@112 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-03-27 22:35:41 +00:00
9327b4ebd4 changed: updated CHANGELOG to previous commit
git-svn-id: svn://ttmath.org/publicrep/ttmath/trunk@111 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-03-27 22:31:54 +00:00
d695785cbb fixed: in function DegToRad(const ValueType & x, ErrorCode * err = 0) it is better
to make division first and then mutliplication -- the result is more
       accurate especially when x is: 90,180,270 or 360
added: global template functions in ttmath.h:
       ValueType GradToRad(const ValueType & x, ErrorCode * err = 0)
       ValueType RadToGrad(const ValueType & x, ErrorCode * err = 0)
       ValueType DegToGrad(const ValueType & x, ErrorCode * err = 0)
       ValueType DegToGrad(const ValueType & d, const ValueType & m,
                           const ValueType & s, ErrorCode * err = 0)
       ValueType GradToDeg(const ValueType & x, ErrorCode * err = 0)
added: Parser::SetDegRadGrad(int angle) - 0 deg, 1 rad (default), 2 grad
       this affects following functions (in the parser only): sin, cos, tan, cot,
       asin, acos, atan, acot
added: functions to the parser: gradtorad(grad), radtograd(rad), degtograd(deg),
       degtograd(d,m,s), gradtodeg(grad)
removed: Big::Ln() and Big::Log() some old info was removed


git-svn-id: svn://ttmath.org/publicrep/ttmath/trunk@110 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-03-27 22:26:51 +00:00
85d1b87ac0 added: '#ifndef __GNUC__' to Big::Pow() where is using '#pragma warning'
in order to not confuse GCC


git-svn-id: svn://ttmath.org/publicrep/ttmath/trunk@109 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-03-25 02:01:42 +00:00
bfdc6d3df3 fixed: Big::Pow(const Big<exp, man> & pow)
it's using PowInt() only when pow.exponent is in range (-man*TTMATH_BITS_PER_UINT; 0]
       previously the powering 'hung' on an input like this: "(1+ 1e-10000) ^ 10e100000000"
       (the was 10e100000000 iterations in PowInt())


git-svn-id: svn://ttmath.org/publicrep/ttmath/trunk@108 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-03-25 01:12:00 +00:00
5668fbecf5 changed: current info in CHANGELOG
git-svn-id: svn://ttmath.org/publicrep/ttmath/trunk@107 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-03-24 21:10:17 +00:00
3899b8631c fixed: template Big::FromBig(const Big<another_exp, another_man> & another)
didn't correctly set the exponent (when the mantisses had different size -
       when 'man' was different from 'another_man')
       this had impact on operator= too
       sample:
       Big<2,3> a = 100;
       Big<3,5> b;
       b = a; // b had a wrong value


git-svn-id: svn://ttmath.org/publicrep/ttmath/trunk@106 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-03-24 20:34:33 +00:00
460608859c added: 'constgen' directory -- there is a program there to generate some constants used in ttmathbig.h
changed: the size of built-in variables (constants) in ttmathbig.h
         now they consist of 256 32bit words
         macro TTMATH_BUILTIN_VARIABLES_SIZE is equal: 256u on a 32bit platform and 128ul on a 64bit platform
added:   macro CONSTANTSGENERATOR which is useful for generating constants
         (it's used by 'gen' program in 'constgen' directory)
         after declaring this macro the methods: ExpSurrounding0() and LnSurrounding1() will be public visible
         and the inner loop can do more iterations than TTMATH_ARITHMETIC_MAX_LOOP
changed: in methods: ExpSurrounding0() and LnSurrounding1() - the way of comparising with the last word
         (now we're comparing not with the last state but with a state from a few words back)



git-svn-id: svn://ttmath.org/publicrep/ttmath/trunk@105 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-03-12 20:54:46 +00:00
978815f12d fixed: there was a TTMATH_REREFENCE_ASSERT error in Big::PowUInt() caused by: start.Mul(start)
fixed:   Big::Add incorrectly rounded 'this' when both exponents were equal
         it caused that sometimes when adding a zero the result has changed
         this had impact among other things on FromString() method
         "0,8" had different binary representation from "0,80"
changed: renamed: Big::PowUInt(UInt<pow_size> pow) -> Big::Pow(UInt<pow_size> pow)
         it returns 2 when there is: 0^0
changed: renamed: Big::PowInt(Int<pow_size> pow) -> Big::Pow(Int<pow_size> pow)
         it returns 2 when there is: 0^0 or 0^(-something)
changed: renamed: Big::PowBUInt() -> PowUInt(), Big::PowBInt() -> Big::PowInt()
         they return 2 when the arguments are incorrect (like above)
changed: UInt::SetBitInWord(uint & value, uint bit) is taking the first argument by a reference now,
         the specific bit is set in the 'value' and the method returns the last state of the bit (zero or one)
added:   UInt::GetBit(uint bit_index) - returning the state of the specific bit
changed: UInt::SetBit(uint bit_index) - it's using TTMATH_ASSERT now
changed: Big::Mod2() - it's using mantissa.GetBit() now
added:   Big::operator=(double) and Big::Big(double)
added:   TTMATH_ASSERT somewhere in ttmathuint64.h
added:   UInt::Pow(UInt<value_size> pow) and Int::Pow(Int<value_size> pow)


git-svn-id: svn://ttmath.org/publicrep/ttmath/trunk@104 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-03-11 19:05:13 +00:00
404727f3de changed: small changes in: UInt:: RclMoveAllWords, UInt::RcrMoveAllWords, UInt::SetBitInWord(),
UInt::FindLeadingBitInWord, UInt::SetBitInWord
fixed:   UInt::Div() didn't return a correct result when the divisor was equal 1
         there was an error in UInt::DivInt() - when the divisor was 1 it returned
         zero and the carry was set
         this error was from the beginning of the TTMath library


git-svn-id: svn://ttmath.org/publicrep/ttmath/trunk@103 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-03-07 22:54:42 +00:00
4aebe9aa18 fixed: UInt::Rcr2_one used edx but there was not a push/pop instruction
(it was in the intel syntax, edx changed to ecx)


git-svn-id: svn://ttmath.org/publicrep/ttmath/trunk@102 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-03-04 22:04:36 +00:00
e18201ba35 changed: UInt::Div3_Normalize - faster now
git-svn-id: svn://ttmath.org/publicrep/ttmath/trunk@101 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-03-03 20:41:00 +00:00
5b24101a83 added: macros TTMATH_ASSERT to: UInt::AddInt UInt::AddTwoInts UInt::SubInt UInt::SetBitInWord
fixed:   UInt::FindLeadingBitInWord(x) didn't correctly return result -1 when the x was 0
         the mistake made by Thomas Braby, it was not in the 0.8.2 release
changed: tests: we do not test for lahf/sahf instructions now (in 64bit code)
         we don't use these instructions



git-svn-id: svn://ttmath.org/publicrep/ttmath/trunk@97 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-02-17 11:37:12 +00:00
6da0386a2d added: tests: addtwoints for 64bits
git-svn-id: svn://ttmath.org/publicrep/ttmath/trunk@96 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-02-16 18:11:38 +00:00
c7c859fc76 changed: UInt::FromString(...) skips the input digits when the value is too big
added: tests: addtwoints (only 32bit)


git-svn-id: svn://ttmath.org/publicrep/ttmath/trunk@95 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-02-16 17:57:34 +00:00
1d81dc75ff fixed: RclMoveAllWords() and RcrMoveAllWords() sometimes didn't return
the proper carry, (when 'bits' was greater than or equal to 'value_size')
        this had impact on Rcl() and Rcr(), they also returned the wrong carry


git-svn-id: svn://ttmath.org/publicrep/ttmath/trunk@85 e52654a7-88a9-db11-a3e9-0013d4bc506e
2008-10-31 20:43:08 +00:00
712bfc9c3b added: UInt::Rcl2_one(c) and UInt::Rcr2_one(c)
they are much faster than UInt::Rcl2(1,c) and Rcr2(1,c)
changed: UInt::Rcl() and UInt::Rcr()
       we don't longer make the things with moving a half in the left and a half in the right
       we simply use Rcl2_one() and Rcl2() /Rcr2_one() and Rcr2()/


git-svn-id: svn://ttmath.org/publicrep/ttmath/trunk@84 e52654a7-88a9-db11-a3e9-0013d4bc506e
2008-10-30 23:38:24 +00:00
91e7badb62 changed: asm code in: UInt::Sub, UInt::SubInt (32 and 64bit)
(much faster now)
changed: asm code in: UInt::Rcl2, UInt::Rcr2 (32 and 64bit)
         previous versions of Rcl2 and Rcr2 had O(n2) complexity,
         now they have O(n) and are much faster
changed: now we do not use LAHF and SAHF instructions (both in 32 and 64 bit code)


git-svn-id: svn://ttmath.org/publicrep/ttmath/trunk@83 e52654a7-88a9-db11-a3e9-0013d4bc506e
2008-10-29 21:54:27 +00:00
cfd719cca2 changed: asm code in UInt::Add, UInt::AddInt, AddTwoInts
32 and 64 bits, much faster now
added:   tests for UInt::AddInt
fixed:   tests: test_lahf() returned incorrect value for 32bit platform


git-svn-id: svn://ttmath.org/publicrep/ttmath/trunk@82 e52654a7-88a9-db11-a3e9-0013d4bc506e
2008-10-25 20:05:51 +00:00
f1115a2ce9 added: test of the LAHF and SAHF instructions
(on a 64bit platform)


git-svn-id: svn://ttmath.org/publicrep/ttmath/trunk@81 e52654a7-88a9-db11-a3e9-0013d4bc506e
2008-10-23 20:17:40 +00:00
ca51020fe6 changed: 64bit asm code didn't want to compile
there were used 'lahf' and 'sahf' instructions
         probably they are supported in a new version of GCC
         with '-msahf' option but GCC 4.2.1 has no such option
         at the moment I'm using opcodes:
            lahf -> 9f
            sahf -> 9e
         Warning! these instructions are not on all 64bit processors
         from: http://gcc.gnu.org/onlinedocs/gcc/i386-and-x86_002d64-Options.html
         "Early Intel CPUs with Intel 64 lacked LAHF and SAHF instructions supported
          by AMD64 until introduction of Pentium 4 G1 step in December 2005."
changed: UInt::Add on 64bit platform
changed: UInt::Add on 32bit platform (a little)


git-svn-id: svn://ttmath.org/publicrep/ttmath/trunk@80 e52654a7-88a9-db11-a3e9-0013d4bc506e
2008-10-22 18:56:04 +00:00
f8f324f98f changed: UInt::FromString, added a parametr 'after_source'
which is pointing at the end of the parsing string
added:   initial import of tests: testing UInt::Add method
         (not finished)


git-svn-id: svn://ttmath.org/publicrep/ttmath/trunk@79 e52654a7-88a9-db11-a3e9-0013d4bc506e
2008-10-21 17:42:41 +00:00
cdd95f602c some optimisations made in assembler code by thomasbraby at zoom.co.uk
(not verified yet)
modified files: ttmathuint.h ttmathuint64.h
I've changed a little the intel syntax (it didn't want to compile)


git-svn-id: svn://ttmath.org/publicrep/ttmath/trunk@78 e52654a7-88a9-db11-a3e9-0013d4bc506e
2008-10-17 09:57:36 +00:00
22 changed files with 5727 additions and 2762 deletions

120
CHANGELOG
View File

@@ -1,3 +1,123 @@
Version 0.8.4 (2009.05.08):
* fixed: UInt::DivInt() didn't check whether the divisor is zero
there was a hardware interruption when the divisor was zero
(now the method returns one)
* fixed: the problem with GCC optimization on x86_64
sometimes when using -O2 or -O3 GCC doesn't set correctly
the stack pointer (actually the stack is used for other things)
and you can't use instructions like push/pop in assembler code.
All the asm code in x86_64 have been rewritten, now instructions
push/pop are not used, other thing which have access to stack
(like "m" (mask) constraints in Rcl2 and Rcr2) have also gone away,
now the library works well with -O2 and -O3 and the asm code
is a little faster
* added: UInt::PrintLog(const char * msg, std::ostream & output)
used (for debugging purposes) by macro TTMATH_LOG(msg)
(it is used in nearly all methods in UInt class)
* added: macro TTMATH_DEBUG_LOG: when defined then TTMATH_LOG()
put some debug information (to std::cout)
* added: ttmathuint_x86.h, ttmathuint_x86_64.h, ttmathuint_noasm.h,
all the methods which are using assembler code have been
rewritten to no-asm forms, now we have:
1. asm for x86 file: ttmathuint_x86.h
2. asm for x86_64 file: ttmathuint_x86_64.h
3. no asm file: ttmathuint_noasm.h
(it's used when macro TTMATH_NOASM is defined)
The third form can be used on x86 and x86_64 as well and
on other platforms with a little effort.
Version 0.8.3 (2009.04.06):
* fixed: RclMoveAllWords() and RcrMoveAllWords() sometimes didn't return
the proper carry, (when 'bits' was greater than or equal to 'value_size')
this had impact on Rcl() and Rcr(), they also returned the wrong carry
* fixed: UInt::Div() didn't return a correct result when the divisor was equal 1
there was an error in UInt::DivInt() - when the divisor was 1 it returned
zero and the carry was set
* fixed: there was a TTMATH_REREFENCE_ASSERT error in Big::PowUInt() caused by: start.Mul(start)
* fixed: Big::Add incorrectly rounded 'this' when both exponents were equal
it caused that sometimes when adding a zero the result has changed
this had impact among other things on FromString() method
"0,8" had different binary representation from "0,80"
* fixed: template Big::FromBig(const Big<another_exp, another_man> & another)
didn't correctly set the exponent (when the mantisses had different size -
when 'man' was different from 'another_man')
this had impact on operator= too
sample:
Big<2,3> a = 100;
Big<3,5> b;
b = a; // b had a wrong value
* fixed: Big::Pow(const Big<exp, man> & pow)
it's using PowInt() only when pow.exponent is in range (-man*TTMATH_BITS_PER_UINT; 0]
previously the powering 'hung' on an input like this: "(1+ 1e-10000) ^ 10e100000000"
(there was 10e100000000 iterations in PowInt())
* fixed: in function DegToRad(const ValueType & x, ErrorCode * err = 0) it is better
to make division first and then mutliplication -- the result is more
accurate especially when x is: 90,180,270 or 360
* fixed: the parser didn't correctly treat operators for changing the base
(radix) -- operators '#' and '&', e.g.:
'#sin(1)' was equal '0' -- there was a zero from '#' and then
it was multipied by 'sin(1)'
the parser didn't check whether Big::FromString() has actually
read a proper value -- the method Big::FromString() didn't have
something to report such a situation
* fixed: Big::FromString() when the base is 10, the method reads the scientific
part only if such a part it correctly supplied, e.g:
'1234e10', '1234e+10', '1234e-5'
previous '1234e' was treated as: '1234e0' (now parsing stops on 'e' and
the 'e' can be parsed by other parsers, e.g. the mathematical
parser -- now in the parser would be: '1234e' = '1234 * e' = '3354,3597...' )
* changed: renamed: Big::PowUInt(UInt<pow_size> pow) -> Big::Pow(UInt<pow_size> pow)
it returns 2 when there is: 0^0
* changed: renamed: Big::PowInt(Int<pow_size> pow) -> Big::Pow(Int<pow_size> pow)
it returns 2 when there is: 0^0 or 0^(-something)
* changed: renamed: Big::PowBUInt() -> PowUInt(), Big::PowBInt() -> Big::PowInt()
they return 2 when the arguments are incorrect (like above)
* changed: UInt::SetBitInWord(uint & value, uint bit) is taking the first argument by a reference now,
the specific bit is set in the 'value' and the method returns the last state of the bit (zero or one)
* changed: UInt::SetBit(uint bit_index) - it's using TTMATH_ASSERT now
* changed: the size of built-in variables (constants) in ttmathbig.h
now they consist of 256 32bit words
macro TTMATH_BUILTIN_VARIABLES_SIZE is equal: 256u on a 32bit platform and 128ul on a 64bit platform
* changed: the asm code in ttmathuint.h and ttmathuint64.h has been completely rewritten
now UInt<> is faster about 15-30% than UInt<> from 0.8.2
this has impact on Big<> too - it's faster about 10% now
* changed: in the parser: the form with operators '#' and '&' is as follows:
[-|+][#|&]numeric_value
previous was: [-|+][#|&][-|+]numeric_value
* changed: in the parser: the short form of multiplication has the same
priority as the normal multiplication, e.g.:
'2x^3' = 2 * (x^3)
previous the priority was greater than powering priority
previous: '2x^3' = (2*x) ^ 3
* added: UInt::GetBit(uint bit_index) - returning the state of the specific bit
* added: Big::operator=(double) and Big::Big(double)
* added: UInt::Pow(UInt<value_size> pow) and Int::Pow(Int<value_size> pow)
* added: global template functions in ttmath.h:
ValueType GradToRad(const ValueType & x, ErrorCode * err = 0)
ValueType RadToGrad(const ValueType & x, ErrorCode * err = 0)
ValueType DegToGrad(const ValueType & x, ErrorCode * err = 0)
ValueType DegToGrad(const ValueType & d, const ValueType & m,
const ValueType & s, ErrorCode * err = 0)
ValueType GradToDeg(const ValueType & x, ErrorCode * err = 0)
* added: Parser::SetDegRadGrad(int angle) - 0 deg, 1 rad (default), 2 grad
this affects following functions (in the parser only): sin, cos, tan, cot,
asin, acos, atan, acot
* added: functions to the parser: gradtorad(grad), radtograd(rad), degtograd(deg),
degtograd(d,m,s), gradtodeg(grad)
* added: UInt::FromString, added a parametr 'after_source'
which is pointing at the end of the parsed string
* added: Int::FromString(): parameter 'const char ** after_source = 0'
if exists it's pointing at the end of the parsed string
* added: to UInt::FromString(), Int::FromString(), Big::FromString():
parameter 'bool * value_read = 0' - (if exists) tells
whether something has actually been read (at least one digit)
* added: Objects::IsDefined(const std::string & name)
returning true if such an object is defined
* removed: Big::FromString() this method doesn't longer recognize operators
for changing the base ('#' and '&')
Version 0.8.2 (2008.06.18): Version 0.8.2 (2008.06.18):
* added: UInt::BitNot2() this method has been proposed by * added: UInt::BitNot2() this method has been proposed by
Arek <kmicicc AnTispam users.sourceforge.net> Arek <kmicicc AnTispam users.sourceforge.net>

View File

@@ -1,4 +1,4 @@
Copyright (c) 2006-2008, Tomasz Sowa Copyright (c) 2006-2009, Tomasz Sowa
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without

4
README
View File

@@ -21,6 +21,6 @@ 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 to do is to use 'include' directive of the preprocessor. How big the
values can be is set directly in the source code by the programmer. values can be is set directly in the source code by the programmer.
Author: Tomasz Sowa <t.sowa@slimaczek.pl> Author: Tomasz Sowa <t.sowa@ttmath.org>
Project pages: http://ttmath.slimaczek.pl Project pages: http://www.ttmath.org
http://sourceforge.net/projects/ttmath http://sourceforge.net/projects/ttmath

27
constgen/Makefile Normal file
View File

@@ -0,0 +1,27 @@
o = main.o
CC = g++
CFLAGS = -s -O2 -DCONSTANTSGENERATOR
name = gen
.SUFFIXES: .cpp .o
.cpp.o:
$(CC) -c $(CFLAGS) $<
all: $(name)
$(name): $(o)
$(CC) -o $(name) $(CFLAGS) $(o)
main.o: main.cpp
clean:
rm -f *.o
rm -f *.s
rm -f $(name)
rm -f $(name).exe

126
constgen/main.cpp Normal file
View File

@@ -0,0 +1,126 @@
/*
* This file is a part of TTMath Bignum Library
* and is distributed under the (new) BSD licence.
* Author: Tomasz Sowa <t.sowa@slimaczek.pl>
*/
/*
* 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.
*/
/*
this simple program is used to make constants which then are put into ttmathbig.h
*/
#include "../ttmath/ttmath.h"
#include <iostream>
void CalcPi()
{
ttmath::Big<1,400> pi;
// 3100 digits after commna, taken from: http://zenwerx.com/pi.php
pi = "3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679"
"8214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196"
"4428810975665933446128475648233786783165271201909145648566923460348610454326648213393607260249141273"
"7245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094"
"3305727036575959195309218611738193261179310511854807446237996274956735188575272489122793818301194912"
"9833673362440656643086021394946395224737190702179860943702770539217176293176752384674818467669405132"
"0005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235"
"4201995611212902196086403441815981362977477130996051870721134999999837297804995105973173281609631859"
"5024459455346908302642522308253344685035261931188171010003137838752886587533208381420617177669147303"
"5982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989"
"3809525720106548586327886593615338182796823030195203530185296899577362259941389124972177528347913151"
"5574857242454150695950829533116861727855889075098381754637464939319255060400927701671139009848824012"
"8583616035637076601047101819429555961989467678374494482553797747268471040475346462080466842590694912"
"9331367702898915210475216205696602405803815019351125338243003558764024749647326391419927260426992279"
"6782354781636009341721641219924586315030286182974555706749838505494588586926995690927210797509302955"
"3211653449872027559602364806654991198818347977535663698074265425278625518184175746728909777727938000"
"8164706001614524919217321721477235014144197356854816136115735255213347574184946843852332390739414333"
"4547762416862518983569485562099219222184272550254256887671790494601653466804988627232791786085784383"
"8279679766814541009538837863609506800642251252051173929848960841284886269456042419652850222106611863"
"0674427862203919494504712371378696095636437191728746776465757396241389086583264599581339047802759009"
"9465764078951269468398352595709825822620522489407726719478268482601476990902640136394437455305068203"
"4962524517493996514314298091906592509372216964615157098583874105978859597729754989301617539284681382"
"6868386894277415599185592524595395943104997252468084598727364469584865383673622262609912460805124388"
"4390451244136549762780797715691435997700129616089441694868555848406353422072225828488648158456028506"
"0168427394522674676788952521385225499546667278239864565961163548862305774564980355936345681743241125"
"1507606947945109659609402522887971089314566913686722874894056010150330861792868092087476091782493858"
"9009714909675985261365549781893129784821682998948722658804857564014270477555132379641451523746234364"
"5428584447952658678210511413547357395231134271661021359695362314429524849371871101457654035902799344"
"0374200731057853906219838744780847848968332144571386875194350643021845319104848100537061468067491927"
"8191197939952061419663428754440643745123718192179998391015919561814675142691239748940907186494231961"
"5679452080951465502252316038819301420937621378559566389377870830390697920773467221825625996615014215";
std::cout << "---------------- PI ----------------" << std::endl;
pi.mantissa.PrintTable(std::cout);
}
void CalcE()
{
ttmath::Big<1,400> e;
ttmath::uint steps;
// macro CONSTANTSGENERATOR has to be defined
e.ExpSurrounding0(1, &steps);
std::cout << "---------------- e ----------------" << std::endl;
e.mantissa.PrintTable(std::cout);
std::cout << "ExpSurrounding0(1): " << steps << " iterations" << std::endl;
}
void CalcLn(int x)
{
ttmath::Big<1,400> ln;
ttmath::uint steps;
// macro CONSTANTSGENERATOR has to be defined
ln.LnSurrounding1(x, &steps);
std::cout << "---------------- ln(" << x << ") ----------------" << std::endl;
ln.mantissa.PrintTable(std::cout);
std::cout << "LnSurrounding1(" << x << "): " << steps << " iterations" << std::endl;
}
int main()
{
CalcPi();
CalcE();
CalcLn(2);
CalcLn(10);
return 0;
}

View File

@@ -32,20 +32,21 @@ MyBig atemp;
if( !atemp.Add(b) ) if( !atemp.Add(b) )
std::cout << "a + b = " << atemp << std::endl; std::cout << "a + b = " << atemp << std::endl;
else else
std::cout << "a + b = (carry) " << atemp << std::endl; std::cout << "a + b = (carry)" << std::endl;
// it have no sense to print 'atemp' (it's undefined)
atemp = a; atemp = a;
if( !atemp.Sub(b) ) if( !atemp.Sub(b) )
std::cout << "a - b = " << atemp << std::endl; std::cout << "a - b = " << atemp << std::endl;
else else
std::cout << "a - b = (carry) " << atemp << std::endl; std::cout << "a - b = (carry)" << std::endl;
atemp = a; atemp = a;
if( !atemp.Mul(b) ) if( !atemp.Mul(b) )
std::cout << "a * b = " << atemp << std::endl; std::cout << "a * b = " << atemp << std::endl;
else else
std::cout << "a * b = (carry: the result is too big) " << std::endl; std::cout << "a * b = (carry)" << std::endl;
// it have no sense to print 'atemp' (it's undefined)
atemp = a; atemp = a;
if( !atemp.Div(b) ) if( !atemp.Div(b) )
@@ -68,9 +69,8 @@ MyBig a,b;
// 'a' will have the max value which can be held in this type // 'a' will have the max value which can be held in this type
a.SetMax(); a.SetMax();
// at the moment conversions from double (or float etc.) are not supported // conversion from double
// you cannot do that: b = 456.32f b = 456.32;
b = "456.32";
// Look at the value 'a' and the product from a+b and a-b // Look at the value 'a' and the product from a+b and a-b
// Don't worry this is the nature of floating point numbers // Don't worry this is the nature of floating point numbers
@@ -89,9 +89,9 @@ a * b = 12193540837712.2708
a / b = 0.0012499665458095765 a / b = 0.0012499665458095765
Calculating with a carry Calculating with a carry
a = 1.624801256070839555e+646457012 a = 1.624801256070839555e+646457012
b = 456.32 b = 456.31999999999999
a + b = 1.624801256070839555e+646457012 a + b = 1.624801256070839555e+646457012
a - b = 1.624801256070839555e+646457012 a - b = 1.624801256070839555e+646457012
a * b = (carry: the result is too big) a * b = (carry)
a / b = 3.56066193914542329e+646457009 a / b = 3.56066193914542334e+646457009
*/ */

31
tests/Makefile Normal file
View File

@@ -0,0 +1,31 @@
CC = g++
o = main.o uinttest.o
CFLAGS = -Wall -O2 -s
ttmath = ..
name = tests
.SUFFIXES: .cpp .o
.cpp.o:
$(CC) -c $(CFLAGS) -I$(ttmath) $<
all: $(name)
$(name): $(o)
$(CC) -o $(name) $(CFLAGS) -I$(ttmath) $(o)
main.o: main.cpp uinttest.h
uinttest.o: uinttest.cpp uinttest.h
clean:
rm -f *.o
rm -f $(name)
rm -f $(name).exe

68
tests/main.cpp Normal file
View File

@@ -0,0 +1,68 @@
/*
* This file is a part of TTMath Bignum Library
* and is distributed under the (new) BSD licence.
* Author: Tomasz Sowa <t.sowa@slimaczek.pl>
*/
/*
* 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.
*/
#include <iostream>
#include <ttmath/ttmath.h>
#include "uinttest.h"
const char uint_tests_file[] = "tests.uint32";
void test_uint()
{
UIntTest test;
test.set_file_name(uint_tests_file);
test.go();
}
int main()
{
using namespace ttmath;
test_uint();
return 0;
}

92
tests/tests.uint32 Normal file
View File

@@ -0,0 +1,92 @@
# Add
# min_bits max_bits a b result carry
add 32 0 0 0 0 0
add 32 0 1 1 2 0
add 32 0 2342234 3563456 5905690 0
add 32 0 254455 3453435 3707890 0
add 32 0 4294967295 0 4294967295 0
add 32 32 4294967295 1 0 1
add 32 32 4294967295 0 4294967295 0
add 64 64 18446744073709551615 1 0 1
add 64 64 18446744073709551615 0 18446744073709551615 0
add 96 96 79228162514264337593543950335 1 0 1
add 96 96 79228162514264337593543950335 0 79228162514264337593543950335 0
add 128 128 340282366920938463463374607431768211455 1 0 1
add 128 128 340282366920938463463374607431768211455 0 340282366920938463463374607431768211455 0
add 160 160 1461501637330902918203684832716283019655932542975 1 0 1
add 160 160 1461501637330902918203684832716283019655932542975 0 1461501637330902918203684832716283019655932542975 0
add 192 192 6277101735386680763835789423207666416102355444464034512895 1 0 1
add 192 192 6277101735386680763835789423207666416102355444464034512895 0 6277101735386680763835789423207666416102355444464034512895 0
# AddInt
# min_bits max_bits bits_per_int a b(int) index result carry
addint 32 0 32 0 0 0 0 0
addint 32 0 32 1000 2000 0 3000 0
addint 64 0 32 562342345 1423445 1 6113650284997065 0
addint 64 0 32 5342342455 3423553423 0 8765895878 0
addint 96 0 32 478895734 46756734 2 862509505820513898647477878 0
addint 128 0 32 27370506140054471803784984408165997441 24543 3 27372450636847059393422542757339093889 0
addint 128 128 32 340282366841711102552375003685868034945 2234543 3 177038656721750864719686733515479937 1
addint 160 160 32 1461501637330902918124457471805283415910032366465 3 3 158457126631793409034731674497 1
addint 192 0 32 6277101735386680763835789423128439055191355840718134336385 3354 1 6277101735386680763835789423128439055191355855123454647169 0
addint 192 192 32 6277101735386680763835789423128439055191355840718134336385 3354 5 4901876491607848387655079701569502248322251848964993 1
addint 64 0 64 0 0 0 0 0
addint 64 0 64 5342342 345534234 0 350876576 0
addint 64 0 64 5342342455 34235534234 0 39577876689 0
addint 64 64 64 18446744073709550615 2000 0 999 1
addint 128 0 64 42895062544824211012058135 3453234 0 42895062544824211015511369 0
addint 128 0 64 42895062544824211012058135 456234234 1 8458931214807741031021280279 0
addint 128 128 64 340282366920938426569886460012664978455 45623 1 804702316727431770143767 1
addint 192 192 64 6277101735386680763835789423207666379208867297044931279895 45623234 1 841563227924816702308613143 1
addint 192 192 64 6277101735386679588840776445207152040176347835149297122327 45623234 2 15523607057094857017675614218510090830281178135 1
addint 192 192 64 6277101735386680763835789423207666416102355444464034512895 1 0 0 1
# AddTwoInts
# a the value
# c lower word
# b higher word
# index - index of the lower (c) word
# if there is a carry the result is skipped
# min_bits max_bits bits_per_int a b(int) c(int) index result carry
addtwoints 64 0 32 0 0 0 0 0 0
addtwoints 64 0 32 23542345 3453245 2356252356 0 14831576719870221 0
addtwoints 64 64 32 4563456879824345332 3453245255 3673623543 0 0 1
addtwoints 96 0 32 345345634564352344231 1231354534 345324551 1 22714482299528678798871855271 0
addtwoints 96 96 32 33333336690445123453645645123 4241542514 145235414 1 0 1
addtwoints 128 0 32 921345787234870984751756 2356245656 3423623455 2 186681013820253010515426931265335245452 0
addtwoints 128 128 32 259817508127340892734075234234345345346 3452345324 452354345 2 0 1
addtwoints 160 0 32 458674036702857083457018457034 435236456 1451234242 1 466702732224470435083940719562 0
addtwoints 160 0 32 258672084570198475012875019876674534523452543562 935245345 736765636 3 576919584276960743542382023227664277469907669578 0
addtwoints 192 0 32 2398670187501982374012837086745045 3253453245 234567536 4 4754927244626858434362642830810490464530603685767816794581 0
addtwoints 192 192 32 1734564564356435667546738087098769876387468736123143453646 3456345245 3256347435 4 0 1
addtwoints 128 0 64 0 0 0 0 0 0
addtwoints 128 0 64 14513452345 234512412345 8473567534 0 4325990452636459442359440119399 0
addtwoints 128 128 64 325434534534536347567567356714513452345 4324546234512412345 8473567534 0 0 1
addtwoints 192 0 64 8786356223462562562561234 4356879827345 34745638455 1 1482569380039046311960318103044992688410168990618834 0
addtwoints 192 0 64 875687458745872039847234234048572306857602 12341234356 3472568734534 1 4199505313073142510985676024483326499863441546882 0
addtwoints 192 192 64 6234554767823878635622346242564564564564564564562562561234 457644356879827345 34844576655 1 0 1

424
tests/uinttest.cpp Normal file
View File

@@ -0,0 +1,424 @@
/*
* This file is a part of TTMath Bignum Library
* and is distributed under the (new) BSD licence.
* Author: Tomasz Sowa <t.sowa@slimaczek.pl>
*/
/*
* 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.
*/
#include "uinttest.h"
void UIntTest::set_file_name(const std::string & f)
{
file_name = f;
}
bool UIntTest::read_uint(uuint & result)
{
UInt<1> temp;
int c = temp.FromString(pline, 10, &pline);
result = temp.ToUInt();
if( c )
{
std::cerr << " carry from reading uint" << std::endl;
return false;
}
return true;
}
template<uuint type_size>
bool UIntTest::read_uint(UInt<type_size> & result)
{
int c = result.FromString(pline, 10, &pline);
if( c )
{
std::cerr << " carry from UInt<>::FromString()" << std::endl;
return false;
}
return true;
}
bool UIntTest::check_minmax_bits(int type_size)
{
uuint min_bits;
uuint max_bits;
read_uint(min_bits);
read_uint(max_bits);
if( min_bits != 0 && type_size * TTMATH_BITS_PER_UINT < (unsigned int)min_bits )
return false;
if( max_bits != 0 && type_size * TTMATH_BITS_PER_UINT > (unsigned int)max_bits )
return false;
return true;
}
bool UIntTest::check_minmax_bits_bitperint(int type_size)
{
if( !check_minmax_bits(type_size) )
return false;
uuint bits;
read_uint(bits);
if( TTMATH_BITS_PER_UINT != bits )
return false;
return true;
}
bool UIntTest::check_end()
{
skip_white_characters();
if( *pline!='#' && *pline!= 0 )
{
std::cerr << "syntax error" << std::endl;
return false;
}
return true;
}
template<uuint type_size>
bool UIntTest::check_result_carry(const ttmath::UInt<type_size> & result, const ttmath::UInt<type_size> & new_result,
int carry, int new_carry)
{
bool ok = true;
if( new_carry != carry )
{
std::cerr << "Incorrect carry: " << new_carry << " (expected: " << carry << ")" << std::endl;
ok = false;
}
if( new_result != result )
{
std::cerr << "Incorrect result: " << new_result << " (expected: " << result << ")" << std::endl;
ok = false;
}
return ok;
}
template<uuint type_size>
bool UIntTest::check_result_or_carry(const ttmath::UInt<type_size> & result, const ttmath::UInt<type_size> & new_result,
int carry, int new_carry)
{
if( new_carry != carry )
{
std::cerr << "Incorrect carry: " << new_carry << " (expected: " << carry << ")" << std::endl;
return false;
}
if( new_carry == 1 )
return true;
if( new_result != result )
{
std::cerr << "Incorrect result: " << new_result << " (expected: " << result << ")" << std::endl;
return false;
}
return true;
}
template<uuint type_size>
void UIntTest::test_add()
{
UInt<type_size> a,b,result, new_result;
if( !check_minmax_bits(type_size) )
return;
read_uint(a);
read_uint(b);
read_uint(result);
uuint carry;
read_uint(carry);
std::cerr << '[' << row << "] Add<" << type_size << ">: ";
if( !check_end() )
return;
new_result = a;
int new_carry = new_result.Add(b);
if( check_result_carry(result, new_result, carry, new_carry) )
std::cerr << "ok" << std::endl;
}
template<uuint type_size>
void UIntTest::test_addint()
{
UInt<type_size> a, result, new_result;
if( !check_minmax_bits_bitperint(type_size) )
return;
uuint b, index, carry;
read_uint(a);
read_uint(b);
read_uint(index);
read_uint(result);
read_uint(carry);
std::cerr << '[' << row << "] AddInt<" << type_size << ">: ";
if( !check_end() )
return;
new_result = a;
int new_carry = new_result.AddInt(b, index);
if( check_result_carry(result, new_result, carry, new_carry) )
std::cerr << "ok" << std::endl;
}
template<uuint type_size>
void UIntTest::test_addtwoints()
{
UInt<type_size> a, result, new_result;
if( !check_minmax_bits_bitperint(type_size) )
return;
std::cerr << '[' << row << "] AddTwoInts<" << type_size << ">: ";
uuint b, c, index, carry;
read_uint(a);
read_uint(b);
read_uint(c);
read_uint(index);
read_uint(result);
read_uint(carry);
if( !check_end() )
return;
if( index >= type_size - 1 )
{
std::cerr << "index too large" << std::endl;
return;
}
new_result = a;
int new_carry = new_result.AddTwoInts(b, c, index);
if( check_result_or_carry(result, new_result, carry, new_carry) )
std::cerr << "ok" << std::endl;
}
int UIntTest::upper_char(int c)
{
if( c>='a' && c<='z' )
return c - 'a' + 'A';
return c;
}
bool UIntTest::is_white(int c)
{
if( c==' ' || c=='\t' || c==13 )
return true;
return false;
}
void UIntTest::skip_white_characters()
{
while( is_white(*pline) )
++pline;
}
bool UIntTest::read_method()
{
skip_white_characters();
if( *pline == '#' )
return false;
method.clear();
for(int c = upper_char(*pline) ; c>='A'&& c<='Z' ; c = upper_char(*pline) )
{
method += c;
++pline;
}
if( method.empty() )
{
skip_white_characters();
if( *pline == 0 )
return false;
else
{
std::cerr << '[' << row << "] ";
std::cerr << "syntax error" << std::endl;
return false;
}
}
return true;
}
void UIntTest::test_method()
{
const char * p = pline;
if( method == "ADD" )
{
pline = p; test_add<1>();
pline = p; test_add<2>();
pline = p; test_add<3>();
pline = p; test_add<4>();
pline = p; test_add<5>();
pline = p; test_add<6>();
pline = p; test_add<7>();
pline = p; test_add<8>();
pline = p; test_add<9>();
}
else
if( method == "ADDINT" )
{
pline = p; test_addint<1>();
pline = p; test_addint<2>();
pline = p; test_addint<3>();
pline = p; test_addint<4>();
pline = p; test_addint<5>();
pline = p; test_addint<6>();
pline = p; test_addint<7>();
pline = p; test_addint<8>();
pline = p; test_addint<9>();
}
else
if( method == "ADDTWOINTS" )
{
pline = p; test_addtwoints<1>();
pline = p; test_addtwoints<2>();
pline = p; test_addtwoints<3>();
pline = p; test_addtwoints<4>();
pline = p; test_addtwoints<5>();
pline = p; test_addtwoints<6>();
pline = p; test_addtwoints<7>();
pline = p; test_addtwoints<8>();
pline = p; test_addtwoints<9>();
}
else
{
std::cerr << '[' << row << "] ";
std::cerr << "method " << method << " is not supported" << std::endl;
}
}
bool UIntTest::check_line()
{
std::getline(file, line);
pline = line.c_str();
if( read_method() )
test_method();
if( file.eof() )
return false;
return true;
}
void UIntTest::go()
{
file.open(file_name.c_str());
if( !file )
{
std::cerr << "I can't open the input file" << std::endl;
return;
}
row = 1;
while( check_line() )
++row;
}

105
tests/uinttest.h Normal file
View File

@@ -0,0 +1,105 @@
/*
* This file is a part of TTMath Bignum Library
* and is distributed under the (new) BSD licence.
* Author: Tomasz Sowa <t.sowa@slimaczek.pl>
*/
/*
* 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 headerfileuinttest
#define headerfileuinttest
#include <string>
#include <fstream>
#include <iostream>
#include <ttmath/ttmath.h>
using namespace ttmath;
typedef ttmath::uint uuint;
class UIntTest
{
std::string file_name;
// current line from the file
std::string line;
const char * pline;
std::ifstream file;
std::string method;
int row;
public:
void set_file_name(const std::string & f);
void go();
bool read_uint(uuint & result);
template<uuint type_size>
bool read_uint(UInt<type_size> & result);
template<uuint type_size> void test_add();
template<uuint type_size> void test_addint();
template<uuint type_size> void test_addtwoints();
template<uuint type_size> bool check_result_carry(const ttmath::UInt<type_size> & result, const ttmath::UInt<type_size> & new_result,
int carry, int new_carry);
template<uuint type_size> bool check_result_or_carry(const ttmath::UInt<type_size> & result, const ttmath::UInt<type_size> & new_result,
int carry, int new_carry);
int upper_char(int c);
bool is_white(int c);
void skip_white_characters();
bool read_method();
void test_method();
bool check_line();
bool check_minmax_bits(int type_size);
bool check_minmax_bits_bitperint(int type_size);
bool check_end();
};
#endif

View File

@@ -1,11 +1,11 @@
/* /*
* This file is a part of TTMath Mathematical Library * This file is a part of TTMath Bignum Library
* and is distributed under the (new) BSD licence. * and is distributed under the (new) BSD licence.
* Author: Tomasz Sowa <t.sowa@slimaczek.pl> * Author: Tomasz Sowa <t.sowa@slimaczek.pl>
*/ */
/* /*
* Copyright (c) 2006-2008, Tomasz Sowa * Copyright (c) 2006-2009, Tomasz Sowa
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -53,6 +53,13 @@
namespace ttmath namespace ttmath
{ {
/*
*
* functions defined here are used only with Big<> types
*
*
*/
/* /*
* *
@@ -416,7 +423,7 @@ namespace ttmath
if( c ) if( c )
// Sin is from <-1,1> and cannot make an overflow // Sin is from <-1,1> and cannot make an overflow
// but the carry can be from the Taylor series // but the carry can be from the Taylor series
// (then we only breaks our calculations) // (then we only break our calculations)
break; break;
if( addition ) if( addition )
@@ -1347,7 +1354,7 @@ namespace ttmath
/* /*
* *
* functions for converting between degrees and radians * functions for converting between degrees, radians and gradians
* *
* *
*/ */
@@ -1361,14 +1368,18 @@ namespace ttmath
template<class ValueType> template<class ValueType>
ValueType DegToRad(const ValueType & x, ErrorCode * err = 0) ValueType DegToRad(const ValueType & x, ErrorCode * err = 0)
{ {
ValueType result, delimiter; ValueType result, temp;
uint c = 0; uint c = 0;
result.SetPi(); result = x;
c += result.Mul(x);
delimiter = 180; // it is better to make division first and then multiplication
c += result.Div(delimiter); // 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 ) if( err )
*err = c ? err_overflow : err_ok; *err = c ? err_overflow : err_ok;
@@ -1468,6 +1479,128 @@ namespace ttmath
} }
/*!
this function converts gradians to radians
it returns: x * pi / 200
*/
template<class ValueType>
ValueType GradToRad(const ValueType & x, ErrorCode * err = 0)
{
ValueType result, temp;
uint c = 0;
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<class ValueType>
ValueType RadToGrad(const ValueType & x, ErrorCode * err = 0)
{
ValueType result, delimiter;
uint c = 0;
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<class ValueType>
ValueType DegToGrad(const ValueType & x, ErrorCode * err = 0)
{
ValueType result, temp;
uint c = 0;
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<class ValueType>
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<class ValueType>
ValueType GradToDeg(const ValueType & x, ErrorCode * err = 0)
{
ValueType result, temp;
uint c = 0;
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 * another functions

View File

@@ -1,11 +1,11 @@
/* /*
* This file is a part of TTMath Mathematical Library * This file is a part of TTMath Bignum Library
* and is distributed under the (new) BSD licence. * and is distributed under the (new) BSD licence.
* Author: Tomasz Sowa <t.sowa@slimaczek.pl> * Author: Tomasz Sowa <t.sowa@slimaczek.pl>
*/ */
/* /*
* Copyright (c) 2006-2008, Tomasz Sowa * Copyright (c) 2006-2009, Tomasz Sowa
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -212,20 +212,35 @@ private:
0x99c32718, 0x6af4e23c, 0x1a946834, 0xb6150bda, 0x2583e9ca, 0x2ad44ce8, 0xdbbbc2db, 0x04de8ef9, 0x99c32718, 0x6af4e23c, 0x1a946834, 0xb6150bda, 0x2583e9ca, 0x2ad44ce8, 0xdbbbc2db, 0x04de8ef9,
0x2e8efc14, 0x1fbecaa6, 0x287c5947, 0x4e6bc05d, 0x99b2964f, 0xa090c3a2, 0x233ba186, 0x515be7ed, 0x2e8efc14, 0x1fbecaa6, 0x287c5947, 0x4e6bc05d, 0x99b2964f, 0xa090c3a2, 0x233ba186, 0x515be7ed,
0x1f612970, 0xcee2d7af, 0xb81bdd76, 0x2170481c, 0xd0069127, 0xd5b05aa9, 0x93b4ea98, 0x8d8fddc1, 0x1f612970, 0xcee2d7af, 0xb81bdd76, 0x2170481c, 0xd0069127, 0xd5b05aa9, 0x93b4ea98, 0x8d8fddc1,
0x86ffb7dc, 0x90a6c08f, 0x4df435c9, 0x34028492, 0x36c3fab4, 0xd27c7026, 0xc1d4dcb2, 0x602646df // (last one was: 0x602646de) 0x86ffb7dc, 0x90a6c08f, 0x4df435c9, 0x34028492, 0x36c3fab4, 0xd27c7026, 0xc1d4dcb2, 0x602646de,
// 0xc9751e76, ... 0xc9751e76, 0x3dba37bd, 0xf8ff9406, 0xad9e530e, 0xe5db382f, 0x413001ae, 0xb06a53ed, 0x9027d831,
// (the last word was rounded up because the next one is 0xc9751e76 -- first bit is one 0xc..) 0x179727b0, 0x865a8918, 0xda3edbeb, 0xcf9b14ed, 0x44ce6cba, 0xced4bb1b, 0xdb7f1447, 0xe6cc254b,
// 128 32bit words for the mantissa -- about 1232 valid digits (decimal) 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
// the value of PI is comming from the website "Paul's 8192 Digits of Pi" // 3101 digits were taken from this website
// http://www.escape.com/~paulg53/math/pi/8192.html // (later the digits were compared with:
// 2999 digits were taken from this website // http://www.eveandersson.com/pi/digits/1000000 and http://www.geom.uiuc.edu/~huberty/math5337/groupe/digits.html )
// (later they were compared with http://zenwerx.com/pi.php) // and they were set into Big<1,400> type (using operator=(const char*) on a 32bit platform)
// and they were set into Big<1,300> type (using operator=(const char*) on 32bit platform) // and then the first 256 words were taken into this table
// and then the first 128 words were taken into this table // (TTMATH_BUILTIN_VARIABLES_SIZE on 32bit platform should have the value 256,
// (TTMATH_BUILTIN_VARIABLES_SIZE on 32bit platform should have the value 128, // and on 64bit platform value 128 (256/2=128))
// and on 64bit platform value 64 (128/2=64))
mantissa.SetFromTable(temp_table, sizeof(temp_table) / sizeof(int)); mantissa.SetFromTable(temp_table, sizeof(temp_table) / sizeof(int));
} }
@@ -288,17 +303,34 @@ public:
0xac7d5f42, 0xd69f6d18, 0x7763cf1d, 0x55034004, 0x87f55ba5, 0x7e31cc7a, 0x7135c886, 0xefb4318a, 0xac7d5f42, 0xd69f6d18, 0x7763cf1d, 0x55034004, 0x87f55ba5, 0x7e31cc7a, 0x7135c886, 0xefb4318a,
0xed6a1e01, 0x2d9e6832, 0xa907600a, 0x918130c4, 0x6dc778f9, 0x71ad0038, 0x092999a3, 0x33cb8b7a, 0xed6a1e01, 0x2d9e6832, 0xa907600a, 0x918130c4, 0x6dc778f9, 0x71ad0038, 0x092999a3, 0x33cb8b7a,
0x1a1db93d, 0x7140003c, 0x2a4ecea9, 0xf98d0acc, 0x0a8291cd, 0xcec97dcf, 0x8ec9b55a, 0x7f88a46b, 0x1a1db93d, 0x7140003c, 0x2a4ecea9, 0xf98d0acc, 0x0a8291cd, 0xcec97dcf, 0x8ec9b55a, 0x7f88a46b,
0x4db5a851, 0xf44182e1, 0xc68a007e, 0x5e0dd902, 0x0bfd64b6, 0x45036c7a, 0x4e677d2c, 0x38532a3a 0x4db5a851, 0xf44182e1, 0xc68a007e, 0x5e0dd902, 0x0bfd64b6, 0x45036c7a, 0x4e677d2c, 0x38532a3a,
//0x23ba4442,... 0x23ba4442, 0xcaf53ea6, 0x3bb45432, 0x9b7624c8, 0x917bdd64, 0xb1c0fd4c, 0xb38e8c33, 0x4c701c3a,
// 128 32bit words for the mantissa -- about 1232 valid digits (decimal) 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,300> on 32bit platform // above value was calculated using Big<1,400> type on a 32bit platform
// and then the first 128 words were taken, // and then the first 256 words were taken,
// the calculating was made by using ExpSurrounding0(1) method // the calculating was made by using ExpSurrounding0(1) method
// which took 1110 iterations // which took 1420 iterations
// (TTMATH_BUILTIN_VARIABLES_SIZE on 32bit platform should have the value 128, // (the result was compared with e taken from http://antwrp.gsfc.nasa.gov/htmltest/gifcity/e.2mil)
// and on 64bit platform value 64 (128/2=64)) // (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)); mantissa.SetFromTable(temp_table, sizeof(temp_table) / sizeof(int));
exponent = -sint(man)*sint(TTMATH_BITS_PER_UINT) + 2; exponent = -sint(man)*sint(TTMATH_BITS_PER_UINT) + 2;
@@ -328,18 +360,35 @@ public:
0x57339ba2, 0xbeba7d05, 0x2ac5b61c, 0xc4e9207c, 0xef2f0ce2, 0xd7373958, 0xd7622658, 0x901e646a, 0x57339ba2, 0xbeba7d05, 0x2ac5b61c, 0xc4e9207c, 0xef2f0ce2, 0xd7373958, 0xd7622658, 0x901e646a,
0x95184460, 0xdc4e7487, 0x156e0c29, 0x2413d5e3, 0x61c1696d, 0xd24aaebd, 0x473826fd, 0xa0c238b9, 0x95184460, 0xdc4e7487, 0x156e0c29, 0x2413d5e3, 0x61c1696d, 0xd24aaebd, 0x473826fd, 0xa0c238b9,
0x0ab111bb, 0xbd67c724, 0x972cd18b, 0xfbbd9d42, 0x6c472096, 0xe76115c0, 0x5f6f7ceb, 0xac9f45ae, 0x0ab111bb, 0xbd67c724, 0x972cd18b, 0xfbbd9d42, 0x6c472096, 0xe76115c0, 0x5f6f7ceb, 0xac9f45ae,
0xcecb72f1, 0x9c38339d, 0x8f682625, 0x0dea891e, 0xf07afff3, 0xa892374e, 0x175eb4af, 0xc8daadd9 // (last one was: 0xc8daadd8) 0xcecb72f1, 0x9c38339d, 0x8f682625, 0x0dea891e, 0xf07afff3, 0xa892374e, 0x175eb4af, 0xc8daadd8,
// 0x85db6ab0, ... 0x85db6ab0, 0x3a49bd0d, 0xc0b1b31d, 0x8a0e23fa, 0xc5e5767d, 0xf95884e0, 0x6425a415, 0x26fac51c,
// (the last word was rounded up because the next one is 0x85db6ab0 -- first bit is one 0x8..) 0x3ea8449f, 0xe8f70edd, 0x062b1a63, 0xa6c4c60c, 0x52ab3316, 0x1e238438, 0x897a39ce, 0x78b63c9f,
// 128 32bit words for the mantissa -- about 1232 valid digits (decimal) 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,300> on 32bit platform // above value was calculated using Big<1,400> type on a 32bit platform
// and then the first 128 words were taken, // and then the first 256 words were taken,
// the calculating was made by using LnSurrounding1(2) method // the calculating was made by using LnSurrounding1(2) method
// which took 3030 iterations // which took 4035 iterations
// (TTMATH_BUILTIN_VARIABLES_SIZE on 32bit platform should have the value 128, // (the result was compared with ln(2) taken from http://ja0hxv.calico.jp/pai/estart.html)
// and on 64bit platform value 64 (128/2=64)) // (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)); mantissa.SetFromTable(temp_table, sizeof(temp_table) / sizeof(int));
exponent = -sint(man)*sint(TTMATH_BITS_PER_UINT); exponent = -sint(man)*sint(TTMATH_BITS_PER_UINT);
@@ -379,21 +428,38 @@ public:
0xed69b13d, 0xc1a03730, 0xb6524dc1, 0x8c167e86, 0x99d6d20e, 0xa2defd2b, 0xd006f8b4, 0xbe145a2a, 0xed69b13d, 0xc1a03730, 0xb6524dc1, 0x8c167e86, 0x99d6d20e, 0xa2defd2b, 0xd006f8b4, 0xbe145a2a,
0xdf3ccbb3, 0x189da49d, 0xbc1261c8, 0xb3e4daad, 0x6a36cecc, 0xb2d5ae5b, 0x89bf752f, 0xb5dfb353, 0xdf3ccbb3, 0x189da49d, 0xbc1261c8, 0xb3e4daad, 0x6a36cecc, 0xb2d5ae5b, 0x89bf752f, 0xb5dfb353,
0xff3065c4, 0x0cfceec8, 0x1be5a9a9, 0x67fddc57, 0xc4b83301, 0x006bf062, 0x4b40ed7a, 0x56c6cdcd, 0xff3065c4, 0x0cfceec8, 0x1be5a9a9, 0x67fddc57, 0xc4b83301, 0x006bf062, 0x4b40ed7a, 0x56c6cdcd,
0xa2d6fe91, 0x388e9e3e, 0x48a93f5f, 0x5e3b6eb4, 0xb81c4a5b, 0x53d49ea6, 0x8e668aea, 0xba83c7f9 // (last one was: 0xba83c7f8) 0xa2d6fe91, 0x388e9e3e, 0x48a93f5f, 0x5e3b6eb4, 0xb81c4a5b, 0x53d49ea6, 0x8e668aea, 0xba83c7f8,
///0xfb5f06c3, ... 0xfb5f06c3, 0x58ac8f70, 0xfa9d8c59, 0x8c574502, 0xbaf54c96, 0xc84911f0, 0x0482d095, 0x1a0af022,
//(the last word was rounded up because the next one is 0xfb5f06c3 -- first bit is one 0xf..) 0xabbab080, 0xec97efd3, 0x671e4e0e, 0x52f166b6, 0xcd5cd226, 0x0dc67795, 0x2e1e34a3, 0xf799677f,
// 128 32bit words for the mantissa -- about 1232 valid digits (decimal) 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,300> on 32bit platform // above value was calculated using Big<1,400> type on a 32bit platform
// and then the first 128 32bit words were taken, // and then the first 256 32bit words were taken,
// the calculating was made by using LnSurrounding1(10) method // the calculating was made by using LnSurrounding1(10) method
// which took 16555 iterations // 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 formula used in LnSurrounding1(x) converges badly when
// the x is greater than one but in fact we can use it, only the // the x is greater than one but in fact we can use it, only the
// number of iterations will be greater) // number of iterations will be greater)
// (TTMATH_BUILTIN_VARIABLES_SIZE on 32bit platform should have the value 128, // (TTMATH_BUILTIN_VARIABLES_SIZE on 32bit platform should have the value 256,
// and on 64bit platform value 64 (128/2=64)) // and on 64bit platform value 128 (256/2=128))
mantissa.SetFromTable(temp_table, sizeof(temp_table) / sizeof(int)); mantissa.SetFromTable(temp_table, sizeof(temp_table) / sizeof(int));
exponent = -sint(man)*sint(TTMATH_BITS_PER_UINT) + 2; exponent = -sint(man)*sint(TTMATH_BITS_PER_UINT) + 2;
@@ -561,9 +627,9 @@ public:
} }
if( exp_offset > mantissa_size_in_bits ) if( exp_offset >= mantissa_size_in_bits )
{ {
// the second value is too short for taking into consideration in the sum // the second value is too small for taking into consideration in the sum
return 0; return 0;
} }
else else
@@ -572,13 +638,6 @@ public:
// (2) moving 'exp_offset' times // (2) moving 'exp_offset' times
ss2.mantissa.Rcr( exp_offset.ToInt(), 0 ); ss2.mantissa.Rcr( exp_offset.ToInt(), 0 );
} }
else
{
// (3)
// exp_offset == mantissa_size_in_bits
// we're rounding 'this' about one (up or down depending on a ss2 sign)
ss2.mantissa.SetOne();
}
if( IsSign() == ss2.IsSign() ) if( IsSign() == ss2.IsSign() )
@@ -594,8 +653,8 @@ public:
{ {
// values have different signs // values have different signs
// there shouldn't be a carry here because // there shouldn't be a carry here because
// (1) (2) and (3) guarantee that the mantissa of this // (1) (2) guarantee that the mantissa of this
// is greater than the mantissa of the ss2 // is greater than or equal to the mantissa of the ss2
uint c_temp = mantissa.Sub(ss2.mantissa); uint c_temp = mantissa.Sub(ss2.mantissa);
TTMATH_ASSERT( c_temp == 0 ) TTMATH_ASSERT( c_temp == 0 )
@@ -653,7 +712,7 @@ public:
if( exp_offset >= mantissa_size_in_bits ) if( exp_offset >= mantissa_size_in_bits )
{ {
// the second value is too short // the second value is too small
SetZero(); SetZero();
return 0; return 0;
} }
@@ -700,7 +759,7 @@ public:
} }
if( exp_offset >= mantissa_size_in_bits ) if( exp_offset >= mantissa_size_in_bits )
// the second value is too short // the second value is too small
return 0; return 0;
// exp_offset < mantissa_size_in_bits, moving 'exp_offset' times // exp_offset < mantissa_size_in_bits, moving 'exp_offset' times
@@ -745,7 +804,7 @@ public:
} }
if( exp_offset >= mantissa_size_in_bits ) if( exp_offset >= mantissa_size_in_bits )
// the second value is too short // the second value is too small
return 0; return 0;
// exp_offset < mantissa_size_in_bits, moving 'exp_offset' times // exp_offset < mantissa_size_in_bits, moving 'exp_offset' times
@@ -944,7 +1003,7 @@ public:
-12.6 mod -3 = -0.6 -12.6 mod -3 = -0.6
it means: it means:
in other words: this(old) = ss2 * q + this(new)(result) in other words: this(old) = ss2 * q + this(new -- result)
*/ */
uint Mod(const Big<exp, man> & ss2) uint Mod(const Big<exp, man> & ss2)
{ {
@@ -966,18 +1025,23 @@ public:
/*! /*!
power this = this ^ pow power this = this ^ pow
pow without a sign (pow without a sign)
binary algorithm (r-to-l) binary algorithm (r-to-l)
return values:
0 - ok
1 - carry
2 - incorrect arguments (0^0)
*/ */
template<uint pow_size> template<uint pow_size>
uint PowUInt(UInt<pow_size> pow) uint Pow(UInt<pow_size> pow)
{ {
if(pow.IsZero() && IsZero()) if(pow.IsZero() && IsZero())
// we don't define zero^zero // we don't define zero^zero
return 1; return 2;
Big<exp, man> start(*this); Big<exp, man> start(*this), start_temp;
Big<exp, man> result; Big<exp, man> result;
result.SetOne(); result.SetOne();
@@ -987,7 +1051,8 @@ public:
if( result.Mul(start) ) if( result.Mul(start) )
return 1; return 1;
if( start.Mul(start) ) start_temp = start;
if( start.Mul(start_temp) )
return 1; return 1;
pow.Rcr(1); pow.Rcr(1);
@@ -1001,27 +1066,31 @@ public:
/*! /*!
power this = this ^ pow power this = this ^ pow
p can be with a sign
p can be negative p can be negative
return values:
0 - ok
1 - carry
2 - incorrect arguments 0^0 or 0^(-something)
*/ */
template<uint pow_size> template<uint pow_size>
uint PowInt(Int<pow_size> pow) uint Pow(Int<pow_size> pow)
{ {
if( !pow.IsSign() ) if( !pow.IsSign() )
return PowUInt(pow); return Pow( UInt<pow_size>(pow) );
if( IsZero() ) if( IsZero() )
// if 'p' is negative then // if 'p' is negative then
// 'this' must be different from zero // 'this' must be different from zero
return 1; return 2;
if( pow.ChangeSign() ) if( pow.ChangeSign() )
return 1; return 1;
Big<exp, man> t(*this); Big<exp, man> t(*this);
if( t.PowUInt(pow) ) uint c_temp = t.Pow( UInt<pow_size>(pow) );
return 1; if( c_temp > 0 )
return c_temp;
SetOne(); SetOne();
if( Div(t) ) if( Div(t) )
@@ -1032,33 +1101,40 @@ public:
/*! /*!
this method returns true if 'this' mod 2 is equal one this method returns: 'this' mod 2
(either zero or one)
this method is much faster than using Mod( object_with_value_two )
*/ */
bool Mod2() const uint Mod2() const
{ {
if( exponent>sint(0) || exponent<=-sint(man*TTMATH_BITS_PER_UINT) ) if( exponent>sint(0) || exponent<=-sint(man*TTMATH_BITS_PER_UINT) )
return false; return 0;
sint exp_int = exponent.ToInt(); sint exp_int = exponent.ToInt();
// 'exp_int' is negative (or zero), we set its as positive // 'exp_int' is negative (or zero), we set it as positive
exp_int = -exp_int; exp_int = -exp_int;
// !!! here we'll use a new method (method for testing a bit) return mantissa.GetBit(exp_int);
uint value = mantissa.table[ exp_int / TTMATH_BITS_PER_UINT ];
value >>= (uint(exp_int) % TTMATH_BITS_PER_UINT);
return bool(value & 1);
} }
/*! /*!
power this = this ^ abs([pow]) power this = this ^ abs([pow])
pow without a sign and without a fraction 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 PowBUInt(Big<exp, man> pow) uint PowUInt(Big<exp, man> pow)
{ {
if( pow.IsZero() && IsZero() ) if( pow.IsZero() && IsZero() )
return 1; return 2;
if( pow.IsSign() ) if( pow.IsSign() )
pow.Abs(); pow.Abs();
@@ -1070,7 +1146,7 @@ public:
e_one.SetOne(); e_one.SetOne();
one.SetOne(); one.SetOne();
result.SetOne(); result = one;
while( pow >= one ) while( pow >= one )
{ {
@@ -1093,24 +1169,30 @@ public:
/*! /*!
power this = this ^ [pow] power this = this ^ [pow]
pow without a fraction pow is treated as a value without a fraction
pow can be negative pow can be negative
return values:
0 - ok
1 - carry
2 - incorrect arguments 0^0 or 0^(-something)
*/ */
uint PowBInt(const Big<exp, man> & pow) uint PowInt(const Big<exp, man> & pow)
{ {
TTMATH_REFERENCE_ASSERT( pow ) TTMATH_REFERENCE_ASSERT( pow )
if( !pow.IsSign() ) if( !pow.IsSign() )
return PowBUInt(pow); return PowUInt(pow);
if( IsZero() ) if( IsZero() )
// if 'pow' is negative then // if 'pow' is negative then
// 'this' must be different from zero // 'this' must be different from zero
return 1; return 2;
Big<exp, man> temp(*this); Big<exp, man> temp(*this);
if( temp.PowBUInt(pow) ) uint c_temp = temp.PowUInt(pow);
return 1; if( c_temp > 0 )
return c_temp;
SetOne(); SetOne();
if( Div(temp) ) if( Div(temp) )
@@ -1122,13 +1204,13 @@ public:
/*! /*!
power this = this ^ pow power this = this ^ pow
this *must* be greater than zero (this > 0) this must be greater than zero (this > 0)
pow can be negative and with fraction pow can be negative and with fraction
return values: return values:
0 - ok 0 - ok
1 - carry 1 - carry
2 - incorrect argument ('this') 2 - incorrect argument ('this' <= 0)
*/ */
uint PowFrac(const Big<exp, man> & pow) uint PowFrac(const Big<exp, man> & pow)
{ {
@@ -1147,6 +1229,7 @@ public:
} }
/*! /*!
power this = this ^ pow power this = this ^ pow
pow can be negative and with fraction pow can be negative and with fraction
@@ -1171,14 +1254,14 @@ public:
return 0; return 0;
} }
Big<exp, man> pow_frac( pow ); if( pow.exponent>-int(man*TTMATH_BITS_PER_UINT) && pow.exponent<=0 )
pow_frac.RemainFraction(); {
Big<exp, man> pow_frac( pow );
pow_frac.RemainFraction();
if( pow_frac.IsZero() ) if( pow_frac.IsZero() )
return PowBInt( pow ); return PowInt( pow );
}
// pow is with fraction (not integer)
// result = e^(pow * ln(this) ) where 'this' must be greater than 0
return PowFrac(pow); return PowFrac(pow);
} }
@@ -1186,12 +1269,16 @@ public:
private: private:
#ifdef CONSTANTSGENERATOR
public:
#endif
/*! /*!
Exponent this = exp(x) = e^x where x is in (-1,1) 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!) + ... we're using the formula exp(x) = 1 + (x)/(1!) + (x^2)/(2!) + (x^3)/(3!) + ...
*/ */
void ExpSurrounding0(const Big<exp,man> & x) void ExpSurrounding0(const Big<exp,man> & x, uint * steps = 0)
{ {
TTMATH_REFERENCE_ASSERT( x ) TTMATH_REFERENCE_ASSERT( x )
@@ -1204,22 +1291,20 @@ private:
denominator.SetOne(); denominator.SetOne();
denominator_i.SetOne(); denominator_i.SetOne();
// this is only to avoid getting a warning about an uninitialized object
// gcc 4.1.2 reports: 'old_value.info' may be used uninitialized in this function
// (in fact we will initialize it later when the condition 'testing' is fulfilled)
old_value.info = 0;
// every 'step_test' times we make a test // every 'step_test' times we make a test
const uint step_test = 5; const uint step_test = 5;
uint i;
old_value = *this;
// we begin from 1 in order to not testing at the start // we begin from 1 in order to not testing at the beginning
for(uint i=1 ; i<=TTMATH_ARITHMETIC_MAX_LOOP ; ++i) #ifdef CONSTANTSGENERATOR
for(i=1 ; true ; ++i)
#else
for(i=1 ; i<=TTMATH_ARITHMETIC_MAX_LOOP ; ++i)
#endif
{ {
bool testing = ((i % step_test) == 0); bool testing = ((i % step_test) == 0);
if( testing )
old_value = *this;
next_part = numerator; next_part = numerator;
if( next_part.Div( denominator ) ) if( next_part.Div( denominator ) )
@@ -1232,9 +1317,12 @@ private:
Add( next_part ); Add( next_part );
if( testing && old_value==*this ) if( testing && old_value==*this )
// we've added a next part of the formula but the result // we've added next few parts of the formula but the result
// is still the same then we break the loop // is still the same then we break the loop
break; break;
else
old_value = *this;
// we set the denominator and the numerator for a next part of the formula // we set the denominator and the numerator for a next part of the formula
if( denominator_i.Add(one) ) if( denominator_i.Add(one) )
@@ -1247,10 +1335,11 @@ private:
if( numerator.Mul(x) ) if( numerator.Mul(x) )
break; break;
} }
if( steps )
*steps = i;
} }
public: public:
@@ -1318,7 +1407,7 @@ public:
else else
{ {
ExpSurrounding0(m); ExpSurrounding0(m);
c += PowBUInt(e_); c += PowUInt(e_);
} }
return (c==0)? 0 : 1; return (c==0)? 0 : 1;
@@ -1329,13 +1418,17 @@ public:
private: private:
#ifdef CONSTANTSGENERATOR
public:
#endif
/*! /*!
Natural logarithm this = ln(x) where x in range <1,2) Natural logarithm this = ln(x) where x in range <1,2)
we're using the formula: 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 + ... ] 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<exp,man> & x) void LnSurrounding1(const Big<exp,man> & x, uint * steps = 0)
{ {
Big<exp,man> old_value, next_part, denominator, one, two, x1(x), x2(x); Big<exp,man> old_value, next_part, denominator, one, two, x1(x), x2(x);
@@ -1360,16 +1453,19 @@ private:
denominator.SetOne(); denominator.SetOne();
SetZero(); SetZero();
// this is only to avoid getting a warning about an uninitialized object old_value = *this;
// gcc 4.1.2 reports: 'old_value.info' may be used uninitialized in this function
// (in fact we will initialize it later when the condition 'testing' is fulfilled)
old_value.info = 0;
// every 'step_test' times we make a test // every 'step_test' times we make a test
const uint step_test = 5; const uint step_test = 5;
uint i;
#ifdef CONSTANTSGENERATOR
for(i=1 ; true ; ++i)
#else
// we begin from 1 in order to not testing at the beginning // we begin from 1 in order to not testing at the beginning
for(uint i=1 ; i<=TTMATH_ARITHMETIC_MAX_LOOP ; ++i) for(i=1 ; i<=TTMATH_ARITHMETIC_MAX_LOOP ; ++i)
#endif
{ {
bool testing = ((i % step_test) == 0); bool testing = ((i % step_test) == 0);
@@ -1381,9 +1477,6 @@ private:
// it means there are too many parts of the formula // it means there are too many parts of the formula
break; break;
if( testing )
old_value = *this;
// there shouldn't be a carry here // there shouldn't be a carry here
Add(next_part); Add(next_part);
@@ -1391,6 +1484,8 @@ private:
// we've added next (step_test) parts of the formula but the result // we've added next (step_test) parts of the formula but the result
// is still the same then we break the loop // is still the same then we break the loop
break; break;
else
old_value = *this;
if( x1.Mul(x2) ) if( x1.Mul(x2) )
// if there is a carry here the result we return as good // if there is a carry here the result we return as good
@@ -1403,6 +1498,9 @@ private:
// this = this * 2 // this = this * 2
// ( there can't be a carry here because we calculate the logarithm between <1,2) ) // ( there can't be a carry here because we calculate the logarithm between <1,2) )
exponent.AddOne(); exponent.AddOne();
if( steps )
*steps = i;
} }
@@ -1427,8 +1525,6 @@ public:
0 - ok 0 - ok
1 - overflow 1 - overflow
2 - incorrect argument (x<=0) 2 - incorrect argument (x<=0)
parts: look at the LnSurrounding1() method
*/ */
uint Ln(const Big<exp,man> & x) uint Ln(const Big<exp,man> & x)
{ {
@@ -1460,7 +1556,7 @@ public:
/*! /*!
Logarithm with a base 'base' -- this = Log(x) with a base 'base' Logarithm from 'x' with a 'base'
we're using the formula: we're using the formula:
Log(x) with 'base' = ln(x) / ln(base) Log(x) with 'base' = ln(x) / ln(base)
@@ -1470,12 +1566,6 @@ public:
1 - overflow 1 - overflow
2 - incorrect argument (x<=0) 2 - incorrect argument (x<=0)
3 - incorrect base (a<=0 lub a=1) 3 - incorrect base (a<=0 lub a=1)
parts: look at the LnSurrounding1() method
we pass this value only into 'ln(x)' method
because if we passed 'parts' into 'ln(base)' as well then
the error (after dividing) would be too great
*/ */
uint Log(const Big<exp,man> & x, const Big<exp,man> & base) uint Log(const Big<exp,man> & x, const Big<exp,man> & base)
{ {
@@ -1502,7 +1592,6 @@ public:
// there can be only a carry // there can be only a carry
uint c = Ln(x); uint c = Ln(x);
// we don't pass the 'parts' here (the error after dividing would be to great)
c += denominator.Ln(base); c += denominator.Ln(base);
c += Div(denominator); c += Div(denominator);
@@ -1514,7 +1603,7 @@ public:
/*! /*!
* *
* convertion methods * converting methods
* *
*/ */
@@ -1532,6 +1621,7 @@ public:
uint man_len_min = (man < another_man)? man : another_man; uint man_len_min = (man < another_man)? man : another_man;
uint i; uint i;
uint c = 0;
for( i = 0 ; i<man_len_min ; ++i ) for( i = 0 ; i<man_len_min ; ++i )
mantissa.table[man-1-i] = another.mantissa.table[another_man-1-i]; mantissa.table[man-1-i] = another.mantissa.table[another_man-1-i];
@@ -1539,10 +1629,34 @@ public:
for( ; i<man ; ++i ) for( ; i<man ; ++i )
mantissa.table[man-1-i] = 0; mantissa.table[man-1-i] = 0;
// mantissa is standardized
//c += Standardizing();
return 0; // MS Visual Express 2005 reports a warning (in the lines with 'uint man_diff = ...'):
// warning C4307: '*' : integral constant overflow
// but we're using 'if( man > another_man )' and 'if( man < another_man )' and there'll be no such a situation here
#ifndef __GNUC__
#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);
}
#ifndef __GNUC__
#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 (c == 0 )? 0 : 1;
} }
@@ -1760,7 +1874,7 @@ public:
// error but I leave it at the moment as is // error but I leave it at the moment as is
TTMATH_ASSERT( sizeof(double) == 8 ) TTMATH_ASSERT( sizeof(double) == 8 )
// I am not sure what will be on a plaltform which has // I am not sure what will be on a platform which has
// a different endianness... but we use this library only // a different endianness... but we use this library only
// on x86 and amd (intel) 64 bits (as there's a lot of assembler code) // on x86 and amd (intel) 64 bits (as there's a lot of assembler code)
union union
@@ -1793,7 +1907,7 @@ public:
// where "1.F" is intended to represent the binary number // where "1.F" is intended to represent the binary number
// created by prefixing F with an implicit leading 1 and a binary point. // created by prefixing F with an implicit leading 1 and a binary point.
FromDouble_SetExpAndMan(bool(temp.u[1] & 0x80000000u), FromDouble_SetExpAndMan((temp.u[1] & 0x80000000u) != 0,
e - 1023 - man*TTMATH_BITS_PER_UINT + 1, 0x80000000u, e - 1023 - man*TTMATH_BITS_PER_UINT + 1, 0x80000000u,
m1, m2); m1, m2);
@@ -1815,7 +1929,7 @@ public:
m.table[0] = m2; m.table[0] = m2;
uint moved = m.CompensationToLeft(); uint moved = m.CompensationToLeft();
FromDouble_SetExpAndMan(bool(temp.u[1] & 0x80000000u), FromDouble_SetExpAndMan((temp.u[1] & 0x80000000u) != 0,
e - 1022 - man*TTMATH_BITS_PER_UINT + 1 - moved, 0, e - 1022 - man*TTMATH_BITS_PER_UINT + 1 - moved, 0,
m.table[1], m.table[2]); m.table[1], m.table[2]);
} }
@@ -1906,7 +2020,7 @@ public:
// where "1.F" is intended to represent the binary number // where "1.F" is intended to represent the binary number
// created by prefixing F with an implicit leading 1 and a binary point. // created by prefixing F with an implicit leading 1 and a binary point.
FromDouble_SetExpAndMan(bool(temp.u & 0x8000000000000000ul), FromDouble_SetExpAndMan((temp.u & 0x8000000000000000ul) != 0,
e - 1023 - man*TTMATH_BITS_PER_UINT + 1, e - 1023 - man*TTMATH_BITS_PER_UINT + 1,
0x8000000000000000ul, m); 0x8000000000000000ul, m);
@@ -2118,6 +2232,17 @@ public:
} }
/*!
an operator= for converting 'double' to this class
*/
Big<exp, man> & operator=(double value)
{
FromDouble(value);
return *this;
}
/*! /*!
a constructor for converting 'sint' to this class a constructor for converting 'sint' to this class
*/ */
@@ -2135,6 +2260,15 @@ public:
} }
/*!
a constructor for converting 'double' to this class
*/
Big(double value)
{
FromDouble(value);
}
#ifdef TTMATH_PLATFORM64 #ifdef TTMATH_PLATFORM64
/*! /*!
@@ -3091,39 +3225,48 @@ public:
a method for converting a string into its value a method for converting a string into its value
it returns 1 if the value will be too big -- we cannot pass it into the range it returns 1 if the value will be too big -- we cannot pass it into the range
of our class Big<exp,man> of our class Big<exp,man> (or if the base is incorrect)
that means only digits before the comma operator can make this value too big, that means only digits before the comma operator can make this value too big,
all digits after the comma we can ignore all digits after the comma we can ignore
'source' - pointer to the string for parsing 'source' - pointer to the string for parsing
if 'after_source' is set that when this method have finished its job if 'after_source' is set that when this method finishes
it set the pointer to the new first character after parsed value 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) uint FromString(const char * source, uint base = 10, const char ** after_source = 0, bool * value_read = 0)
{ {
bool is_sign; bool is_sign;
bool value_read_temp = false;
if( base<2 || base>16 ) if( base<2 || base>16 )
{ {
if( after_source ) if( after_source )
*after_source = source; *after_source = source;
if( value_read )
*value_read = value_read_temp;
return 1; return 1;
} }
SetZero(); SetZero();
FromString_TestNewBase( source, base );
FromString_TestSign( source, is_sign ); FromString_TestSign( source, is_sign );
uint c = FromString_ReadPartBeforeComma( source, base ); uint c = FromString_ReadPartBeforeComma( source, base, value_read_temp );
if( FromString_TestCommaOperator(source) ) if( FromString_TestCommaOperator(source) )
c += FromString_ReadPartAfterComma( source, base ); c += FromString_ReadPartAfterComma( source, base, value_read_temp );
if( base==10 && FromString_TestScientific(source) ) if( value_read_temp && base == 10 )
c += FromString_ReadPartScientific( source ); c += FromString_ReadScientificIfExists( source );
if( is_sign && !IsZero() ) if( is_sign && !IsZero() )
ChangeSign(); ChangeSign();
@@ -3131,6 +3274,9 @@ public:
if( after_source ) if( after_source )
*after_source = source; *after_source = source;
if( value_read )
*value_read = value_read_temp;
return (c==0)? 0 : 1; return (c==0)? 0 : 1;
} }
@@ -3139,30 +3285,6 @@ public:
private: private:
/*!
we're testing whether a user wants to change the base
if there's a '#' character it means that the user wants the base to be 16,
if '&' the base will be 2
*/
void FromString_TestNewBase( const char * & source, uint & base )
{
UInt<man>::SkipWhiteCharacters(source);
if( *source == '#' )
{
base = 16;
++source;
}
else
if( *source == '&' )
{
base = 2;
++source;
}
}
/*! /*!
we're testing whether the value is with the sign we're testing whether the value is with the sign
@@ -3208,7 +3330,7 @@ private:
this method reads the first part of a string this method reads the first part of a string
(before the comma operator) (before the comma operator)
*/ */
uint FromString_ReadPartBeforeComma( const char * & source, uint base ) uint FromString_ReadPartBeforeComma( const char * & source, uint base, bool & value_read )
{ {
sint character; sint character;
Big<exp, man> temp; Big<exp, man> temp;
@@ -3218,6 +3340,8 @@ private:
for( ; (character=UInt<man>::CharToDigit(*source, base)) != -1 ; ++source ) for( ; (character=UInt<man>::CharToDigit(*source, base)) != -1 ; ++source )
{ {
value_read = true;
temp = character; temp = character;
if( Mul(base_) ) if( Mul(base_) )
@@ -3235,7 +3359,7 @@ private:
this method reads the second part of a string this method reads the second part of a string
(after the comma operator) (after the comma operator)
*/ */
uint FromString_ReadPartAfterComma( const char * & source, uint base ) uint FromString_ReadPartAfterComma( const char * & source, uint base, bool & value_read )
{ {
sint character; sint character;
uint c = 0, index = 1; uint c = 0, index = 1;
@@ -3243,15 +3367,16 @@ private:
// we don't remove any white characters here // we don't remove any white characters here
// this is only to avoid getting a warning about an uninitialized object // this is only to avoid getting a warning about an uninitialized object 'old_value' which GCC reports
// gcc 4.1.2 reports: 'old_value.info' may be used uninitialized in this function
// (in fact we will initialize it later when the condition 'testing' is fulfilled) // (in fact we will initialize it later when the condition 'testing' is fulfilled)
old_value.info = 0; old_value.SetZero();
power.SetOne(); power.SetOne();
for( ; (character=UInt<man>::CharToDigit(*source, base)) != -1 ; ++source, ++index ) for( ; (character=UInt<man>::CharToDigit(*source, base)) != -1 ; ++source, ++index )
{ {
value_read = true;
part = character; part = character;
if( power.Mul( base_ ) ) if( power.Mul( base_ ) )
@@ -3287,6 +3412,29 @@ private:
} }
/*!
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
*/
int FromString_ReadScientificIfExists(const char * & source)
{
int c = 0;
bool scientific_read = false;
const char * 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' we're testing whether is there the character 'e'
@@ -3311,21 +3459,24 @@ private:
this method reads the exponent (after 'e' character) when there's a scientific 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 format of value and only when we're using the base equals 10
*/ */
uint FromString_ReadPartScientific( const char * & source ) uint FromString_ReadPartScientific( const char * & source, bool & scientific_read )
{ {
uint c = 0; uint c = 0;
Big<exp, man> new_exponent, temp; Big<exp, man> new_exponent, temp;
bool was_sign = false; bool was_sign = false;
FromString_TestSign( source, was_sign ); FromString_TestSign( source, was_sign );
FromString_ReadPartScientific_ReadExponent( source, new_exponent ); c += FromString_ReadPartScientific_ReadExponent( source, new_exponent, scientific_read );
if( was_sign ) if( scientific_read )
new_exponent.ChangeSign(); {
if( was_sign )
new_exponent.ChangeSign();
temp = 10; temp = 10;
c += temp.PowBInt( new_exponent ); c += temp.Pow( new_exponent );
c += Mul(temp); c += Mul(temp);
}
return (c==0)? 0 : 1; return (c==0)? 0 : 1;
} }
@@ -3335,7 +3486,7 @@ private:
this method reads the value of the extra exponent when scientific format is used this method reads the value of the extra exponent when scientific format is used
(only when base == 10) (only when base == 10)
*/ */
uint FromString_ReadPartScientific_ReadExponent( const char * & source, Big<exp, man> & new_exponent ) uint FromString_ReadPartScientific_ReadExponent( const char * & source, Big<exp, man> & new_exponent, bool & scientific_read )
{ {
sint character; sint character;
Big<exp, man> base, temp; Big<exp, man> base, temp;
@@ -3347,6 +3498,8 @@ private:
for( ; (character=UInt<man>::CharToDigit(*source, 10)) != -1 ; ++source ) for( ; (character=UInt<man>::CharToDigit(*source, 10)) != -1 ; ++source )
{ {
scientific_read = true;
temp = character; temp = character;
if( new_exponent.Mul(base) ) if( new_exponent.Mul(base) )

View File

@@ -1,11 +1,11 @@
/* /*
* This file is a part of TTMath Mathematical Library * This file is a part of TTMath Bignum Library
* and is distributed under the (new) BSD licence. * and is distributed under the (new) BSD licence.
* Author: Tomasz Sowa <t.sowa@slimaczek.pl> * Author: Tomasz Sowa <t.sowa@slimaczek.pl>
*/ */
/* /*
* Copyright (c) 2006-2008, Tomasz Sowa * Copyright (c) 2006-2009, Tomasz Sowa
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -469,6 +469,70 @@ public:
private:
/*!
power this = this ^ pow
this can be negative
pow is >= 0
*/
uint Pow2(const Int<value_size> & pow)
{
bool was_sign = IsSign();
uint c = 0;
if( was_sign )
c += Abs();
uint c_temp = UInt<value_size>::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<value_size> pow)
{
if( !pow.IsSign() )
return Pow2(pow);
if( UInt<value_size>::IsZero() )
// if 'p' is negative then
// 'this' must be different from zero
return 2;
if( pow.ChangeSign() )
return 1;
Int<value_size> t(*this);
uint c_temp = t.Pow2(pow);
if( c_temp > 0 )
return c_temp;
UInt<value_size>::SetOne();
if( Div(t) )
return 1;
return 0;
}
/*! /*!
* *
@@ -583,7 +647,7 @@ public:
return 0; return 0;
} }
// converting from Int
/*! /*!
the default assignment operator the default assignment operator
@@ -650,7 +714,6 @@ public:
} }
// converting from UInt
/*! /*!
this operator converts an UInt<another_size> type to this class this operator converts an UInt<another_size> type to this class
@@ -696,7 +759,7 @@ public:
FromUInt(u); FromUInt(u);
} }
//
#ifdef TTMATH_PLATFORM64 #ifdef TTMATH_PLATFORM64
@@ -836,8 +899,12 @@ public:
existing first white characters will be ommited existing first white characters will be ommited
(between '-' and a first digit can be white characters too) (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) uint FromString(const char * s, uint b = 10, const char ** after_source = 0, bool * value_read = 0)
{ {
bool is_sign = false; bool is_sign = false;
@@ -854,7 +921,7 @@ public:
UInt<value_size>::SkipWhiteCharacters(++s); UInt<value_size>::SkipWhiteCharacters(++s);
} }
if( UInt<value_size>::FromString(s,b) ) if( UInt<value_size>::FromString(s,b,after_source,value_read) )
return 1; return 1;
if( is_sign ) if( is_sign )
@@ -865,12 +932,15 @@ public:
/* /*
the reference to mmin will be automatically converted to the reference the reference to mmin will be automatically converted to the reference
to a UInt type to UInt type
(this value can be equal mmin -- look at a description in ChangeSign()) (this value can be equal mmin -- look at a description in ChangeSign())
*/ */
if( UInt<value_size>::operator>( mmin ) ) if( UInt<value_size>::operator>( mmin ) )
return 1; return 1;
/*
if the value is equal mmin the method ChangeSign() does nothing (only returns 1 but we ignore it)
*/
ChangeSign(); ChangeSign();
} }
else else

View File

@@ -5,7 +5,7 @@
*/ */
/* /*
* Copyright (c) 2006-2008, Tomasz Sowa * Copyright (c) 2006-2009, Tomasz Sowa
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -130,6 +130,21 @@ public:
} }
/*!
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;
}
/*! /*!
this method adds one object (variable of function) into the table this method adds one object (variable of function) into the table
*/ */
@@ -258,7 +273,7 @@ public:
/*! /*!
this method sets the value of a specific object this method gets the value of a specific object
*/ */
ErrorCode GetValue(const std::string & name, std::string & value) const ErrorCode GetValue(const std::string & name, std::string & value) const
{ {
@@ -280,7 +295,7 @@ public:
/*! /*!
this method sets the value of a specific object this method gets the value of a specific object
(this version is used for not copying the whole string) (this version is used for not copying the whole string)
*/ */
ErrorCode GetValue(const std::string & name, const char ** value) const ErrorCode GetValue(const std::string & name, const char ** value) const
@@ -303,7 +318,7 @@ public:
/*! /*!
this method sets the value and the number of parameters this method gets the value and the number of parameters
of a specific object of a specific object
*/ */
ErrorCode GetValueAndParam(const std::string & name, std::string & value, int * param) const ErrorCode GetValueAndParam(const std::string & name, std::string & value, int * param) const

View File

@@ -5,7 +5,7 @@
*/ */
/* /*
* Copyright (c) 2006-2008, Tomasz Sowa * Copyright (c) 2006-2009, Tomasz Sowa
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -61,14 +61,14 @@ namespace ttmath
/*! /*!
\brief Mathematical parser \brief Mathematical parser
let x will be an input string means an expression for converting: let x will be an input string meaning an expression for converting:
x = [+|-]Value[operator[+|-]Value][operator[+|-]Value]... x = [+|-]Value[operator[+|-]Value][operator[+|-]Value]...
where: where:
an operator can be: an operator can be:
^ (pow) (almost the heighest priority, look below at 'short mul') ^ (pow) (the heighest priority)
* (mul) * (mul) (or multiplication without an operator -- short mul)
/ (div) (* and / have the same priority) / (div) (* and / have the same priority)
+ (add) + (add)
@@ -86,14 +86,22 @@ namespace ttmath
|| (logical or) (the lowest priority) || (logical or) (the lowest priority)
short mul: short mul:
or if the second Value (Var below) is either a variable or function there cannot be if the second Value (Var below) is either a variable or function there might not be
an operator between them, e.g. an operator between them, e.g.
[+|-]ValueVar is treated as [+|-]Value * Var and the multiplication "[+|-]Value Var" is treated as "[+|-]Value * Var" and the multiplication
has the greatest priority: 2^3m equals 2^(3*m) 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:
and Value can be: constant e.g. 100, can be preceded by operators for changing the base (radix): [#|&]
constant e.g. 100 # - hex
& - bin
sample: #10 = 16
&10 = 2
variable e.g. pi variable e.g. pi
another expression between brackets e.g (x) another expression between brackets e.g (x)
function e.g. sin(x) function e.g. sin(x)
@@ -112,7 +120,11 @@ namespace ttmath
for separating parameters for separating parameters
"1 < 2" (the result will be: 1) "1 < 2" (the result will be: 1)
"4 < 3" (the result will be: 0) "4 < 3" (the result will be: 0)
"2+x" (of course if the variable 'x' is defined) "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. etc.
we can also use a semicolon for separating any 'x' input strings we can also use a semicolon for separating any 'x' input strings
@@ -137,7 +149,7 @@ private:
pow (^) pow (^)
and 'shortmul' used when there is no any operators between and 'shortmul' used when there is no any operators between
a first parameter and a variable or function a first parameter and a variable or function
(the 'shortmul' has the greatest priority e.g. '5^3m' equals '5^(3*m)' ) (the 'shortmul' has the same priority as the normal multiplication )
*/ */
class MatOperator class MatOperator
{ {
@@ -182,6 +194,7 @@ private:
break; break;
case mul: case mul:
case shortmul:
case div: case div:
priority = 12; priority = 12;
break; break;
@@ -190,10 +203,6 @@ private:
priority = 14; priority = 14;
break; break;
case shortmul:
priority = 20;
break;
default: default:
Error( err_internal_error ); Error( err_internal_error );
break; break;
@@ -309,11 +318,21 @@ const char * pstring;
/*! /*!
the base of the mathematic system (for example it may be '10') the base (radix) of the mathematic system (for example it may be '10')
*/ */
int base; 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 a pointer to an object which tell us whether we should stop calculating or not
*/ */
@@ -406,7 +425,6 @@ typedef std::map<std::string, pfunction_var> VariablesTable;
VariablesTable variables_table; VariablesTable variables_table;
/*! /*!
you can't calculate the factorial if the argument is greater than 'factorial_max' you can't calculate the factorial if the argument is greater than 'factorial_max'
default value is zero which means there are not any limitations default value is zero which means there are not any limitations
@@ -423,8 +441,6 @@ static void Error(ErrorCode code)
} }
/*! /*!
this method skips the white character from the string this method skips the white character from the string
@@ -437,7 +453,6 @@ void SkipWhiteCharacters()
} }
/*! /*!
an auxiliary method for RecurrenceParsingVariablesOrFunction(...) an auxiliary method for RecurrenceParsingVariablesOrFunction(...)
*/ */
@@ -467,6 +482,7 @@ void RecurrenceParsingVariablesOrFunction_AddName(bool variable, const std::stri
visited_functions.insert( name ); visited_functions.insert( name );
} }
/*! /*!
an auxiliary method for RecurrenceParsingVariablesOrFunction(...) an auxiliary method for RecurrenceParsingVariablesOrFunction(...)
*/ */
@@ -478,6 +494,7 @@ void RecurrenceParsingVariablesOrFunction_DeleteName(bool variable, const std::s
visited_functions.erase( name ); visited_functions.erase( name );
} }
/*! /*!
this method returns the value of a variable or function this method returns the value of a variable or function
by creating a new instance of the mathematical parser by creating a new instance of the mathematical parser
@@ -612,7 +629,53 @@ private:
/*! /*!
'silnia' in polish language 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;
}
/*!
factorial
result = 1 * 2 * 3 * 4 * .... * x result = 1 * 2 * 3 * 4 * .... * x
*/ */
void Factorial(int sindex, int amount_of_args, ValueType & result) void Factorial(int sindex, int amount_of_args, ValueType & result)
@@ -645,7 +708,7 @@ void Sin(int sindex, int amount_of_args, ValueType & result)
if( amount_of_args != 1 ) if( amount_of_args != 1 )
Error( err_improper_amount_of_arguments ); Error( err_improper_amount_of_arguments );
result = ttmath::Sin(stack[sindex].value); result = ttmath::Sin( ConvertAngleToRad(stack[sindex].value) );
} }
void Cos(int sindex, int amount_of_args, ValueType & result) void Cos(int sindex, int amount_of_args, ValueType & result)
@@ -653,7 +716,7 @@ void Cos(int sindex, int amount_of_args, ValueType & result)
if( amount_of_args != 1 ) if( amount_of_args != 1 )
Error( err_improper_amount_of_arguments ); Error( err_improper_amount_of_arguments );
result = ttmath::Cos(stack[sindex].value); result = ttmath::Cos( ConvertAngleToRad(stack[sindex].value) );
} }
void Tan(int sindex, int amount_of_args, ValueType & result) void Tan(int sindex, int amount_of_args, ValueType & result)
@@ -662,7 +725,7 @@ void Tan(int sindex, int amount_of_args, ValueType & result)
Error( err_improper_amount_of_arguments ); Error( err_improper_amount_of_arguments );
ErrorCode err; ErrorCode err;
result = ttmath::Tan(stack[sindex].value, &err); result = ttmath::Tan(ConvertAngleToRad(stack[sindex].value), &err);
if(err != err_ok) if(err != err_ok)
Error( err ); Error( err );
@@ -674,7 +737,7 @@ void Cot(int sindex, int amount_of_args, ValueType & result)
Error( err_improper_amount_of_arguments ); Error( err_improper_amount_of_arguments );
ErrorCode err; ErrorCode err;
result = ttmath::Cot(stack[sindex].value, &err); result = ttmath::Cot(ConvertAngleToRad(stack[sindex].value), &err);
if(err != err_ok) if(err != err_ok)
Error( err ); Error( err );
@@ -779,10 +842,12 @@ void ASin(int sindex, int amount_of_args, ValueType & result)
Error( err_improper_amount_of_arguments ); Error( err_improper_amount_of_arguments );
ErrorCode err; ErrorCode err;
result = ttmath::ASin(stack[sindex].value, &err); ValueType temp = ttmath::ASin(stack[sindex].value, &err);
if(err != err_ok) if(err != err_ok)
Error( err ); Error( err );
result = ConvertRadToAngle(temp);
} }
@@ -792,10 +857,12 @@ void ACos(int sindex, int amount_of_args, ValueType & result)
Error( err_improper_amount_of_arguments ); Error( err_improper_amount_of_arguments );
ErrorCode err; ErrorCode err;
result = ttmath::ACos(stack[sindex].value, &err); ValueType temp = ttmath::ACos(stack[sindex].value, &err);
if(err != err_ok) if(err != err_ok)
Error( err ); Error( err );
result = ConvertRadToAngle(temp);
} }
@@ -804,7 +871,7 @@ void ATan(int sindex, int amount_of_args, ValueType & result)
if( amount_of_args != 1 ) if( amount_of_args != 1 )
Error( err_improper_amount_of_arguments ); Error( err_improper_amount_of_arguments );
result = ttmath::ATan(stack[sindex].value); result = ConvertRadToAngle(ttmath::ATan(stack[sindex].value));
} }
@@ -813,7 +880,7 @@ void ACot(int sindex, int amount_of_args, ValueType & result)
if( amount_of_args != 1 ) if( amount_of_args != 1 )
Error( err_improper_amount_of_arguments ); Error( err_improper_amount_of_arguments );
result = ttmath::ACot(stack[sindex].value); result = ConvertRadToAngle(ttmath::ACot(stack[sindex].value));
} }
@@ -954,6 +1021,72 @@ void DegToDeg(int sindex, int amount_of_args, ValueType & result)
Error( err ); Error( err );
} }
void GradToRad(int sindex, int amount_of_args, ValueType & result)
{
ErrorCode err;
if( amount_of_args != 1 )
Error( err_improper_amount_of_arguments );
result = ttmath::GradToRad(stack[sindex].value, &err);
if( err != err_ok )
Error( err );
}
void RadToGrad(int sindex, int amount_of_args, ValueType & result)
{
ErrorCode err;
if( amount_of_args != 1 )
Error( err_improper_amount_of_arguments );
result = ttmath::RadToGrad(stack[sindex].value, &err);
if( err != err_ok )
Error( err );
}
void DegToGrad(int sindex, int amount_of_args, ValueType & result)
{
ErrorCode err;
if( amount_of_args == 1 )
{
result = ttmath::DegToGrad(stack[sindex].value, &err);
}
else
if( amount_of_args == 3 )
{
result = ttmath::DegToGrad( stack[sindex].value, stack[sindex+2].value,
stack[sindex+4].value, &err);
}
else
Error( err_improper_amount_of_arguments );
if( err != err_ok )
Error( err );
}
void GradToDeg(int sindex, int amount_of_args, ValueType & result)
{
ErrorCode err;
if( amount_of_args != 1 )
Error( err_improper_amount_of_arguments );
result = ttmath::GradToDeg(stack[sindex].value, &err);
if( err != err_ok )
Error( err );
}
void Ceil(int sindex, int amount_of_args, ValueType & result) void Ceil(int sindex, int amount_of_args, ValueType & result)
{ {
if( amount_of_args != 1 ) if( amount_of_args != 1 )
@@ -1282,9 +1415,9 @@ void CallFunction(const std::string & function_name, int amount_of_args, int sin
function_name - name of the function function_name - name of the function
pf - pointer to the function (to the wrapper) pf - pointer to the function (to the wrapper)
*/ */
void InsertFunctionToTable(const std::string & function_name, pfunction pf) void InsertFunctionToTable(const char * function_name, pfunction pf)
{ {
functions_table.insert( std::make_pair(function_name, pf)); functions_table.insert( std::make_pair(std::string(function_name), pf));
} }
@@ -1295,9 +1428,9 @@ void InsertFunctionToTable(const std::string & function_name, pfunction pf)
variable_name - name of the function variable_name - name of the function
pf - pointer to the function pf - pointer to the function
*/ */
void InsertVariableToTable(const std::string & variable_name, pfunction_var pf) void InsertVariableToTable(const char * variable_name, pfunction_var pf)
{ {
variables_table.insert( std::make_pair(variable_name, pf)); variables_table.insert( std::make_pair(std::string(variable_name), pf));
} }
@@ -1309,60 +1442,64 @@ void CreateFunctionsTable()
/* /*
names of functions should consist of small letters names of functions should consist of small letters
*/ */
InsertFunctionToTable(std::string("factorial"), &Parser<ValueType>::Factorial); InsertFunctionToTable("factorial", &Parser<ValueType>::Factorial);
InsertFunctionToTable(std::string("abs"), &Parser<ValueType>::Abs); InsertFunctionToTable("abs", &Parser<ValueType>::Abs);
InsertFunctionToTable(std::string("sin"), &Parser<ValueType>::Sin); InsertFunctionToTable("sin", &Parser<ValueType>::Sin);
InsertFunctionToTable(std::string("cos"), &Parser<ValueType>::Cos); InsertFunctionToTable("cos", &Parser<ValueType>::Cos);
InsertFunctionToTable(std::string("tan"), &Parser<ValueType>::Tan); InsertFunctionToTable("tan", &Parser<ValueType>::Tan);
InsertFunctionToTable(std::string("tg"), &Parser<ValueType>::Tan); InsertFunctionToTable("tg", &Parser<ValueType>::Tan);
InsertFunctionToTable(std::string("cot"), &Parser<ValueType>::Cot); InsertFunctionToTable("cot", &Parser<ValueType>::Cot);
InsertFunctionToTable(std::string("ctg"), &Parser<ValueType>::Cot); InsertFunctionToTable("ctg", &Parser<ValueType>::Cot);
InsertFunctionToTable(std::string("int"), &Parser<ValueType>::Int); InsertFunctionToTable("int", &Parser<ValueType>::Int);
InsertFunctionToTable(std::string("round"), &Parser<ValueType>::Round); InsertFunctionToTable("round", &Parser<ValueType>::Round);
InsertFunctionToTable(std::string("ln"), &Parser<ValueType>::Ln); InsertFunctionToTable("ln", &Parser<ValueType>::Ln);
InsertFunctionToTable(std::string("log"), &Parser<ValueType>::Log); InsertFunctionToTable("log", &Parser<ValueType>::Log);
InsertFunctionToTable(std::string("exp"), &Parser<ValueType>::Exp); InsertFunctionToTable("exp", &Parser<ValueType>::Exp);
InsertFunctionToTable(std::string("max"), &Parser<ValueType>::Max); InsertFunctionToTable("max", &Parser<ValueType>::Max);
InsertFunctionToTable(std::string("min"), &Parser<ValueType>::Min); InsertFunctionToTable("min", &Parser<ValueType>::Min);
InsertFunctionToTable(std::string("asin"), &Parser<ValueType>::ASin); InsertFunctionToTable("asin", &Parser<ValueType>::ASin);
InsertFunctionToTable(std::string("acos"), &Parser<ValueType>::ACos); InsertFunctionToTable("acos", &Parser<ValueType>::ACos);
InsertFunctionToTable(std::string("atan"), &Parser<ValueType>::ATan); InsertFunctionToTable("atan", &Parser<ValueType>::ATan);
InsertFunctionToTable(std::string("atg"), &Parser<ValueType>::ATan); InsertFunctionToTable("atg", &Parser<ValueType>::ATan);
InsertFunctionToTable(std::string("acot"), &Parser<ValueType>::ACot); InsertFunctionToTable("acot", &Parser<ValueType>::ACot);
InsertFunctionToTable(std::string("actg"), &Parser<ValueType>::ACot); InsertFunctionToTable("actg", &Parser<ValueType>::ACot);
InsertFunctionToTable(std::string("sgn"), &Parser<ValueType>::Sgn); InsertFunctionToTable("sgn", &Parser<ValueType>::Sgn);
InsertFunctionToTable(std::string("mod"), &Parser<ValueType>::Mod); InsertFunctionToTable("mod", &Parser<ValueType>::Mod);
InsertFunctionToTable(std::string("if"), &Parser<ValueType>::If); InsertFunctionToTable("if", &Parser<ValueType>::If);
InsertFunctionToTable(std::string("or"), &Parser<ValueType>::Or); InsertFunctionToTable("or", &Parser<ValueType>::Or);
InsertFunctionToTable(std::string("and"), &Parser<ValueType>::And); InsertFunctionToTable("and", &Parser<ValueType>::And);
InsertFunctionToTable(std::string("not"), &Parser<ValueType>::Not); InsertFunctionToTable("not", &Parser<ValueType>::Not);
InsertFunctionToTable(std::string("degtorad"), &Parser<ValueType>::DegToRad); InsertFunctionToTable("degtorad", &Parser<ValueType>::DegToRad);
InsertFunctionToTable(std::string("radtodeg"), &Parser<ValueType>::RadToDeg); InsertFunctionToTable("radtodeg", &Parser<ValueType>::RadToDeg);
InsertFunctionToTable(std::string("degtodeg"), &Parser<ValueType>::DegToDeg); InsertFunctionToTable("degtodeg", &Parser<ValueType>::DegToDeg);
InsertFunctionToTable(std::string("ceil"), &Parser<ValueType>::Ceil); InsertFunctionToTable("gradtorad", &Parser<ValueType>::GradToRad);
InsertFunctionToTable(std::string("floor"), &Parser<ValueType>::Floor); InsertFunctionToTable("radtograd", &Parser<ValueType>::RadToGrad);
InsertFunctionToTable(std::string("sqrt"), &Parser<ValueType>::Sqrt); InsertFunctionToTable("degtograd", &Parser<ValueType>::DegToGrad);
InsertFunctionToTable(std::string("sinh"), &Parser<ValueType>::Sinh); InsertFunctionToTable("gradtodeg", &Parser<ValueType>::GradToDeg);
InsertFunctionToTable(std::string("cosh"), &Parser<ValueType>::Cosh); InsertFunctionToTable("ceil", &Parser<ValueType>::Ceil);
InsertFunctionToTable(std::string("tanh"), &Parser<ValueType>::Tanh); InsertFunctionToTable("floor", &Parser<ValueType>::Floor);
InsertFunctionToTable(std::string("tgh"), &Parser<ValueType>::Tanh); InsertFunctionToTable("sqrt", &Parser<ValueType>::Sqrt);
InsertFunctionToTable(std::string("coth"), &Parser<ValueType>::Coth); InsertFunctionToTable("sinh", &Parser<ValueType>::Sinh);
InsertFunctionToTable(std::string("ctgh"), &Parser<ValueType>::Coth); InsertFunctionToTable("cosh", &Parser<ValueType>::Cosh);
InsertFunctionToTable(std::string("root"), &Parser<ValueType>::Root); InsertFunctionToTable("tanh", &Parser<ValueType>::Tanh);
InsertFunctionToTable(std::string("asinh"), &Parser<ValueType>::ASinh); InsertFunctionToTable("tgh", &Parser<ValueType>::Tanh);
InsertFunctionToTable(std::string("acosh"), &Parser<ValueType>::ACosh); InsertFunctionToTable("coth", &Parser<ValueType>::Coth);
InsertFunctionToTable(std::string("atanh"), &Parser<ValueType>::ATanh); InsertFunctionToTable("ctgh", &Parser<ValueType>::Coth);
InsertFunctionToTable(std::string("atgh"), &Parser<ValueType>::ATanh); InsertFunctionToTable("root", &Parser<ValueType>::Root);
InsertFunctionToTable(std::string("acoth"), &Parser<ValueType>::ACoth); InsertFunctionToTable("asinh", &Parser<ValueType>::ASinh);
InsertFunctionToTable(std::string("actgh"), &Parser<ValueType>::ACoth); InsertFunctionToTable("acosh", &Parser<ValueType>::ACosh);
InsertFunctionToTable(std::string("bitand"), &Parser<ValueType>::BitAnd); InsertFunctionToTable("atanh", &Parser<ValueType>::ATanh);
InsertFunctionToTable(std::string("bitor"), &Parser<ValueType>::BitOr); InsertFunctionToTable("atgh", &Parser<ValueType>::ATanh);
InsertFunctionToTable(std::string("bitxor"), &Parser<ValueType>::BitXor); InsertFunctionToTable("acoth", &Parser<ValueType>::ACoth);
InsertFunctionToTable(std::string("band"), &Parser<ValueType>::BitAnd); InsertFunctionToTable("actgh", &Parser<ValueType>::ACoth);
InsertFunctionToTable(std::string("bor"), &Parser<ValueType>::BitOr); InsertFunctionToTable("bitand", &Parser<ValueType>::BitAnd);
InsertFunctionToTable(std::string("bxor"), &Parser<ValueType>::BitXor); InsertFunctionToTable("bitor", &Parser<ValueType>::BitOr);
InsertFunctionToTable(std::string("sum"), &Parser<ValueType>::Sum); InsertFunctionToTable("bitxor", &Parser<ValueType>::BitXor);
InsertFunctionToTable(std::string("avg"), &Parser<ValueType>::Avg); InsertFunctionToTable("band", &Parser<ValueType>::BitAnd);
InsertFunctionToTable("bor", &Parser<ValueType>::BitOr);
InsertFunctionToTable("bxor", &Parser<ValueType>::BitXor);
InsertFunctionToTable("sum", &Parser<ValueType>::Sum);
InsertFunctionToTable("avg", &Parser<ValueType>::Avg);
} }
@@ -1374,8 +1511,8 @@ void CreateVariablesTable()
/* /*
names of variables should consist of small letters names of variables should consist of small letters
*/ */
InsertVariableToTable(std::string("pi"), &ValueType::SetPi); InsertVariableToTable("pi", &ValueType::SetPi);
InsertVariableToTable(std::string("e"), &ValueType::SetE); InsertVariableToTable("e", &ValueType::SetE);
} }
@@ -1500,15 +1637,19 @@ return is_it_name_of_function;
/*! /*!
we're reading a numerical value directly from the string we're reading a numerical value directly from the string
*/ */
void ReadValue(Item & result) void ReadValue(Item & result, int reading_base)
{ {
const char * new_stack_pointer; const char * new_stack_pointer;
bool value_read;
int carry = result.value.FromString(pstring, base, &new_stack_pointer); int carry = result.value.FromString(pstring, reading_base, &new_stack_pointer, &value_read);
pstring = new_stack_pointer; pstring = new_stack_pointer;
if( carry ) if( carry )
Error( err_overflow ); Error( err_overflow );
if( !value_read )
Error( err_unknown_character );
} }
@@ -1537,6 +1678,24 @@ return c;
} }
/*!
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 base)
{
if( character == TTMATH_COMMA_CHARACTER_1 )
return true;
if( TTMATH_COMMA_CHARACTER_2 != 0 && character == TTMATH_COMMA_CHARACTER_2 )
return true;
if( CharToDigit(character, base) != -1 )
return true;
return false;
}
/*! /*!
we're reading the item we're reading the item
@@ -1596,19 +1755,33 @@ int character;
return 2; return 2;
} }
else else
if( character=='#' || character=='&' || if( character == '#' )
character==TTMATH_COMMA_CHARACTER_1 ||
(character==TTMATH_COMMA_CHARACTER_2 && TTMATH_COMMA_CHARACTER_2 != 0) ||
CharToDigit(character, base)!=-1 )
{ {
/* ++pstring;
warning: SkipWhiteCharacters();
if we're using for example the base equal 16
we can find a first character like 'e' that is not e=2.71.. // after '#' character we do not allow '-' or '+' (can be white characters)
but the value 14, for this case we must use something like var::e for variables if( ValueStarts(*pstring, 16) )
(not implemented yet) ReadValue( result, 16 );
*/ else
ReadValue( result ); 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 else
if( character>='a' && character<='z' ) if( character>='a' && character<='z' )
@@ -1911,9 +2084,9 @@ void TryRollingUpStack()
*/ */
int ReadValueVariableOrFunctionAndPushItIntoStack(Item & temp) int ReadValueVariableOrFunctionAndPushItIntoStack(Item & temp)
{ {
int kod = ReadValueVariableOrFunction( temp ); int code = ReadValueVariableOrFunction( temp );
if( kod == 0 ) if( code == 0 )
{ {
if( stack_index < stack.size() ) if( stack_index < stack.size() )
stack[stack_index] = temp; stack[stack_index] = temp;
@@ -1923,13 +2096,13 @@ int kod = ReadValueVariableOrFunction( temp );
++stack_index; ++stack_index;
} }
if( kod == 2 ) if( code == 2 )
// there was a final bracket, we didn't push it into the stack // there was a final bracket, we didn't push it into the stack
// (it'll be read by the 'ReadOperatorAndCheckFinalBracket' method next) // (it'll be read by the 'ReadOperatorAndCheckFinalBracket' method next)
kod = 0; code = 0;
return kod; return code;
} }
@@ -2218,6 +2391,7 @@ Parser(): default_stack_size(100)
puser_functions = 0; puser_functions = 0;
pfunction_local_variables = 0; pfunction_local_variables = 0;
base = 10; base = 10;
deg_rad_grad = 1;
error = err_ok; error = err_ok;
factorial_max.SetZero(); factorial_max.SetZero();
@@ -2237,6 +2411,7 @@ Parser<ValueType> & operator=(const Parser<ValueType> & p)
puser_functions = p.puser_functions; puser_functions = p.puser_functions;
pfunction_local_variables = 0; pfunction_local_variables = 0;
base = p.base; base = p.base;
deg_rad_grad = p.deg_rad_grad;
error = err_ok; error = err_ok;
factorial_max = p.factorial_max; factorial_max = p.factorial_max;
@@ -2274,6 +2449,18 @@ void SetBase(int 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 this method sets a pointer to the object which tell us whether we should stop
calculations calculations

View File

@@ -1,11 +1,11 @@
/* /*
* This file is a part of TTMath Mathematical Library * This file is a part of TTMath Bignum Library
* and is distributed under the (new) BSD licence. * and is distributed under the (new) BSD licence.
* Author: Tomasz Sowa <t.sowa@slimaczek.pl> * Author: Tomasz Sowa <t.sowa@slimaczek.pl>
*/ */
/* /*
* Copyright (c) 2006-2008, Tomasz Sowa * Copyright (c) 2006-2009, Tomasz Sowa
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -64,7 +64,7 @@
*/ */
#define TTMATH_MAJOR_VER 0 #define TTMATH_MAJOR_VER 0
#define TTMATH_MINOR_VER 8 #define TTMATH_MINOR_VER 8
#define TTMATH_REVISION_VER 2 #define TTMATH_REVISION_VER 4
#define TTMATH_PRERELEASE_VER 0 #define TTMATH_PRERELEASE_VER 0
@@ -83,7 +83,7 @@
gcc -DTTMATH_RELEASE -o myprogram myprogram.cpp gcc -DTTMATH_RELEASE -o myprogram myprogram.cpp
or by defining this macro in your code before using any header files of this library or by defining this macro in your code before using any header files of this library
if TTMATH_RELEASE is not set then TTMATH_DEBUG is set if TTMATH_RELEASE is not set then TTMATH_DEBUG is set automatically
*/ */
#ifndef TTMATH_RELEASE #ifndef TTMATH_RELEASE
#define TTMATH_DEBUG #define TTMATH_DEBUG
@@ -120,6 +120,20 @@ namespace ttmath
typedef unsigned int uint; typedef unsigned int uint;
typedef signed int sint; typedef signed int sint;
/*!
this type is twice bigger than uint
(64bit on a 32bit platforms)
although C++ Standard - ANSI ISO IEC 14882:2003 doesn't define such a type (long long)
but it is defined in C99 and in upcoming C++0x /3.9.1 (2)/ and many compilers support it
this type is used in UInt::MulTwoWords and UInt::DivTwoWords when macro TTMATH_NOASM is defined
but only on a 32bit platform
*/
#ifdef TTMATH_NOASM
typedef unsigned long long int ulint;
#endif
/*! /*!
how many bits there are in the uint type how many bits there are in the uint type
*/ */
@@ -141,7 +155,7 @@ namespace ttmath
which are kept in built-in variables for a Big<> type which are kept in built-in variables for a Big<> type
(these variables are defined in ttmathbig.h) (these variables are defined in ttmathbig.h)
*/ */
#define TTMATH_BUILTIN_VARIABLES_SIZE 128u #define TTMATH_BUILTIN_VARIABLES_SIZE 256u
#else #else
@@ -151,6 +165,15 @@ namespace ttmath
typedef unsigned long uint; typedef unsigned long uint;
typedef signed long sint; typedef signed long sint;
/*!
on 64bit platform we do not define ulint
sizeof(long long) is 8 (64bit) but we need 128bit
on 64 bit platform (when there is defined TTMATH_NOASM macro)
methods UInt::MulTwoWords and UInt::DivTwoWords are using other algorithms than those on 32 bit
*/
//typedef unsigned long long int ulint;
/*! /*!
how many bits there are in the uint type how many bits there are in the uint type
*/ */
@@ -172,7 +195,7 @@ namespace ttmath
which are kept in built-in variables for a Big<> type which are kept in built-in variables for a Big<> type
(these variables are defined in ttmathbig.h) (these variables are defined in ttmathbig.h)
*/ */
#define TTMATH_BUILTIN_VARIABLES_SIZE 64ul #define TTMATH_BUILTIN_VARIABLES_SIZE 128ul
#endif #endif
} }
@@ -407,6 +430,19 @@ namespace ttmath
#endif #endif
#ifdef TTMATH_DEBUG_LOG
#define TTMATH_LOG(msg) \
PrintLog(msg, std::cout);
#else
#define TTMATH_LOG(msg)
#endif
} // namespace } // namespace

File diff suppressed because it is too large Load Diff

View File

@@ -1,985 +0,0 @@
/*
* This file is a part of TTMath Mathematical Library
* and is distributed under the (new) BSD licence.
* Author: Tomasz Sowa <t.sowa@slimaczek.pl>
*/
/*
* Copyright (c) 2006-2008, 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.
*/
/*!
\file ttmathuint.h
\brief template class UInt<uint> for 64bit processors
*/
namespace ttmath
{
/*!
*
* basic mathematic functions
*
*/
#ifdef TTMATH_PLATFORM64
/*!
in 64bit platforms we must define additional operators and contructors
in order to allow a user initializing the objects in this way:
UInt<...> type = 20;
or
UInt<...> type;
type = 30;
decimal constants such as 20, 30 etc. are integer literal of type int,
if the value is greater it can even be long int,
0 is an octal integer of type int
(ISO 14882 p2.13.1 Integer literals)
*/
/*!
this operator converts the unsigned int type to this class
***this operator is created only on a 64bit platform***
it takes one argument of 32bit
*/
template<uint value_size>
UInt<value_size> & UInt<value_size>::operator=(unsigned int i)
{
FromUInt(uint(i));
return *this;
}
/*!
a constructor for converting the unsigned int to this class
***this constructor is created only on a 64bit platform***
it takes one argument of 32bit
*/
template<uint value_size>
UInt<value_size>::UInt(unsigned int i)
{
FromUInt(uint(i));
}
/*!
an operator for converting the signed int to this class
***this constructor is created only on a 64bit platform***
it takes one argument of 32bit
look at the description of UInt::operator=(sint)
*/
template<uint value_size>
UInt<value_size> & UInt<value_size>::operator=(signed int i)
{
FromUInt(uint(i));
return *this;
}
/*!
a constructor for converting the signed int to this class
***this constructor is created only on a 64bit platform***
it takes one argument of 32bit
look at the description of UInt::operator=(sint)
*/
template<uint value_size>
UInt<value_size>::UInt(signed int i)
{
FromUInt(uint(i));
}
/*!
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
*/
template<uint value_size>
void UInt<value_size>::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<temp_table_len; --i, ++temp_table_index)
{
table[i] = uint(temp_table[ temp_table_index ]) << 32;
++temp_table_index;
if( temp_table_index<temp_table_len )
table[i] |= temp_table[ temp_table_index ];
}
// rounding mantissa
if( temp_table_index < temp_table_len )
{
if( (temp_table[temp_table_index] & TTMATH_UINT_HIGHEST_BIT) != 0 )
{
/*
very simply rounding
if the bit from not used last word from temp_table is set to one
we're rouding the lowest word in the table
in fact there should be a normal addition but
we don't use Add() or AddTwoInts() because these methods
can set a carry and then there'll be a small problem
for optimization
*/
if( table[0] != TTMATH_UINT_MAX_VALUE )
++table[0];
}
}
// cleaning the rest of the mantissa
for( ; i >= 0 ; --i)
table[i] = 0;
}
/*!
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 value_size>
uint UInt<value_size>::Add(const UInt<value_size> & ss2, uint c)
{
register uint b = value_size;
register uint * p1 = table;
register uint * p2 = const_cast<uint*>(ss2.table);
#ifndef __GNUC__
#error "another compiler than GCC is currently not supported in 64bit mode"
#endif
#ifdef __GNUC__
/*
this part should be compiled with gcc
*/
__asm__ __volatile__(
"push %%rbx \n"
"push %%rcx \n"
"push %%rdx \n"
"movq $0, %%rax \n"
"subq %%rsi, %%rax \n"
"1: \n"
"movq (%%rbx),%%rax \n"
"adcq (%%rdx),%%rax \n"
"movq %%rax,(%%rbx) \n"
"inc %%rbx \n"
"inc %%rbx \n"
"inc %%rbx \n"
"inc %%rbx \n"
"inc %%rbx \n"
"inc %%rbx \n"
"inc %%rbx \n"
"inc %%rbx \n"
"inc %%rdx \n"
"inc %%rdx \n"
"inc %%rdx \n"
"inc %%rdx \n"
"inc %%rdx \n"
"inc %%rdx \n"
"inc %%rdx \n"
"inc %%rdx \n"
"loop 1b \n"
"movq $0, %%rax \n"
"adcq %%rax,%%rax \n"
"movq %%rax, %%rsi \n"
"pop %%rdx \n"
"pop %%rcx \n"
"pop %%rbx \n"
: "=S" (c)
: "0" (c), "c" (b), "b" (p1), "d" (p2)
: "%rax", "cc", "memory" );
#endif
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[3] it would be returned
*/
template<uint value_size>
uint UInt<value_size>::AddInt(uint value, uint index)
{
register uint b = value_size;
register uint * p1 = table;
register uint c;
#ifndef __GNUC__
#error "another compiler than GCC is currently not supported in 64bit mode"
#endif
#ifdef __GNUC__
__asm__ __volatile__(
"push %%rbx \n"
"push %%rcx \n"
"push %%rdx \n"
"subq %%rdx, %%rcx \n"
"leaq (%%rbx,%%rdx,8), %%rbx \n"
"movq %%rsi, %%rdx \n"
"clc \n"
"1: \n"
"movq (%%rbx), %%rax \n"
"adcq %%rdx, %%rax \n"
"movq %%rax, (%%rbx) \n"
"jnc 2f \n"
"movq $0, %%rdx \n"
"inc %%rbx \n"
"inc %%rbx \n"
"inc %%rbx \n"
"inc %%rbx \n"
"inc %%rbx \n"
"inc %%rbx \n"
"inc %%rbx \n"
"inc %%rbx \n"
"loop 1b \n"
"2: \n"
"movq $0, %%rax \n"
"adcq %%rax,%%rax \n"
"pop %%rdx \n"
"pop %%rcx \n"
"pop %%rbx \n"
: "=a" (c)
: "c" (b), "d" (index), "b" (p1), "S" (value)
: "cc", "memory" );
#endif
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 value_size>
uint UInt<value_size>::AddTwoInts(uint x2, uint x1, uint index)
{
register uint b = value_size;
register uint * p1 = table;
register uint c;
#ifndef __GNUC__
#error "another compiler than GCC is currently not supported in 64bit mode"
#endif
#ifdef __GNUC__
__asm__ __volatile__(
"push %%rbx \n"
"push %%rcx \n"
"push %%rdx \n"
"subq %%rdx, %%rcx \n"
"leaq (%%rbx,%%rdx,8), %%rbx \n"
"movq $0, %%rdx \n"
"movq (%%rbx), %%rax \n"
"addq %%rsi, %%rax \n"
"movq %%rax, (%%rbx) \n"
"inc %%rbx \n"
"inc %%rbx \n"
"inc %%rbx \n"
"inc %%rbx \n"
"inc %%rbx \n"
"inc %%rbx \n"
"inc %%rbx \n"
"inc %%rbx \n"
"movq (%%rbx), %%rax \n"
"adcq %%rdi, %%rax \n"
"movq %%rax, (%%rbx) \n"
"jnc 2f \n"
"dec %%rcx \n"
"dec %%rcx \n"
"jz 2f \n"
"1: \n"
"inc %%rbx \n"
"inc %%rbx \n"
"inc %%rbx \n"
"inc %%rbx \n"
"inc %%rbx \n"
"inc %%rbx \n"
"inc %%rbx \n"
"inc %%rbx \n"
"movq (%%rbx), %%rax \n"
"adcq %%rdx, %%rax \n"
"movq %%rax, (%%rbx) \n"
"jnc 2f \n"
"loop 1b \n"
"2: \n"
"movq $0, %%rax \n"
"adcq %%rax,%%rax \n"
"pop %%rdx \n"
"pop %%rcx \n"
"pop %%rbx \n"
: "=a" (c)
: "c" (b), "d" (index), "b" (p1), "S" (x1), "D" (x2)
: "cc", "memory" );
#endif
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 value_size>
uint UInt<value_size>::Sub(const UInt<value_size> & ss2, uint c)
{
register uint b = value_size;
register uint * p1 = table;
register uint * p2 = const_cast<uint*>(ss2.table);
#ifndef __GNUC__
#error "another compiler than GCC is currently not supported in 64bit mode"
#endif
#ifdef __GNUC__
__asm__ __volatile__(
"push %%rbx \n"
"push %%rcx \n"
"push %%rdx \n"
"movq $0, %%rax \n"
"subq %%rsi, %%rax \n"
"1: \n"
"movq (%%rbx),%%rax \n"
"sbbq (%%rdx),%%rax \n"
"movq %%rax,(%%rbx) \n"
"inc %%rbx \n"
"inc %%rbx \n"
"inc %%rbx \n"
"inc %%rbx \n"
"inc %%rbx \n"
"inc %%rbx \n"
"inc %%rbx \n"
"inc %%rbx \n"
"inc %%rdx \n"
"inc %%rdx \n"
"inc %%rdx \n"
"inc %%rdx \n"
"inc %%rdx \n"
"inc %%rdx \n"
"inc %%rdx \n"
"inc %%rdx \n"
"loop 1b \n"
"movq $0, %%rax \n"
"adcq %%rax,%%rax \n"
"movq %%rax, %%rsi \n"
"pop %%rdx \n"
"pop %%rcx \n"
"pop %%rbx \n"
: "=S" (c)
: "0" (c), "c" (b), "b" (p1), "d" (p2)
: "%rax", "cc", "memory" );
#endif
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[3] it would be returned
*/
template<uint value_size>
uint UInt<value_size>::SubInt(uint value, uint index)
{
register uint b = value_size;
register uint * p1 = table;
register uint c;
#ifndef __GNUC__
#error "another compiler than GCC is currently not supported in 64bit mode"
#endif
#ifdef __GNUC__
__asm__ __volatile__(
"push %%rbx \n"
"push %%rcx \n"
"push %%rdx \n"
"subq %%rdx, %%rcx \n"
"leaq (%%rbx,%%rdx,8), %%rbx \n"
"movq %%rsi, %%rdx \n"
"clc \n"
"1: \n"
"movq (%%rbx), %%rax \n"
"sbbq %%rdx, %%rax \n"
"movq %%rax, (%%rbx) \n"
"jnc 2f \n"
"movq $0, %%rdx \n"
"inc %%rbx \n"
"inc %%rbx \n"
"inc %%rbx \n"
"inc %%rbx \n"
"inc %%rbx \n"
"inc %%rbx \n"
"inc %%rbx \n"
"inc %%rbx \n"
"loop 1b \n"
"2: \n"
"movq $0, %%rax \n"
"adcq %%rax,%%rax \n"
"pop %%rdx \n"
"pop %%rcx \n"
"pop %%rbx \n"
: "=a" (c)
: "c" (b), "d" (index), "b" (p1), "S" (value)
: "cc", "memory" );
#endif
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 value_size>
uint UInt<value_size>::Rcl2(uint bits, uint c)
{
if( bits == 0 )
return 0;
TTMATH_ASSERT( bits>0 && bits<TTMATH_BITS_PER_UINT )
register sint b = value_size;
register uint * p1 = table;
#ifndef __GNUC__
#error "another compiler than GCC is currently not supported in 64bit mode"
#endif
#ifdef __GNUC__
__asm__ __volatile__(
"push %%rsi \n"
"2: \n"
"xorq %%rax,%%rax \n"
"subq %%rdx,%%rax \n"
"push %%rbx \n"
"push %%rcx \n"
"1: \n"
"rclq $1,(%%rbx) \n"
"inc %%rbx \n"
"inc %%rbx \n"
"inc %%rbx \n"
"inc %%rbx \n"
"inc %%rbx \n"
"inc %%rbx \n"
"inc %%rbx \n"
"inc %%rbx \n"
"loop 1b \n"
"pop %%rcx \n"
"pop %%rbx \n"
"decq %%rsi \n"
"jnz 2b \n"
"movq $0, %%rdx \n"
"adcq %%rdx, %%rdx \n"
"pop %%rsi \n"
: "=d" (c)
: "0" (c), "c" (b), "b" (p1), "S" (bits)
: "%rax", "cc", "memory" );
#endif
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
***this method is created only on a 64bit platform***
*/
template<uint value_size>
uint UInt<value_size>::Rcr2(uint bits, uint c)
{
if( bits == 0 )
return 0;
TTMATH_ASSERT( bits>0 && bits<TTMATH_BITS_PER_UINT )
register sint b = value_size;
register uint * p1 = table;
#ifndef __GNUC__
#error "another compiler than GCC is currently not supported in 64bit mode"
#endif
#ifdef __GNUC__
__asm__ __volatile__(
"push %%rsi \n"
"2: \n"
"push %%rbx \n"
"push %%rcx \n"
"leaq (%%rbx,%%rcx,8),%%rbx \n"
"xorq %%rax, %%rax \n"
"subq %%rdx, %%rax \n"
"1: \n"
"dec %%rbx \n"
"dec %%rbx \n"
"dec %%rbx \n"
"dec %%rbx \n"
"dec %%rbx \n"
"dec %%rbx \n"
"dec %%rbx \n"
"dec %%rbx \n"
"rcrq $1,(%%rbx) \n"
"loop 1b \n"
"pop %%rcx \n"
"pop %%rbx \n"
"decq %%rsi \n"
"jnz 2b \n"
"movq $0, %%rdx \n"
"adcq %%rdx,%%rdx \n"
"pop %%rsi \n"
: "=d" (c)
: "0" (c), "c" (b), "b" (p1), "S" (bits)
: "%rax", "cc", "memory" );
#endif
return c;
}
/*
this method returns the number of the highest set bit in one 32-bit word
if the 'x' is zero this method returns '-1'
***this method is created only on a 64bit platform***
*/
template<uint value_size>
sint UInt<value_size>::FindLeadingBitInWord(uint x)
{
register sint result;
#ifndef __GNUC__
#error "another compiler than GCC is currently not supported in 64bit mode"
#endif
#ifdef __GNUC__
__asm__ __volatile__(
"bsrq %%rbx, %%rax \n"
"jnz 1f \n"
"movq $-1, %%rax \n"
"1: \n"
: "=a" (result)
: "b" (x)
: "cc" );
#endif
return result;
}
/*!
this method sets a special bit in the 'value'
and returns the result
***this method is created only on a 64bit platform***
bit is from <0,31>
e.g.
SetBitInWord(0,0) = 1
SetBitInWord(0,2) = 4
SetBitInWord(10, 8) = 266
*/
template<uint value_size>
uint UInt<value_size>::SetBitInWord(uint value, uint bit)
{
#ifndef __GNUC__
#error "another compiler than GCC is currently not supported in 64bit mode"
#endif
#ifdef __GNUC__
__asm__ __volatile__(
"btsq %%rbx,%%rax \n"
: "=a" (value)
: "0" (value), "b" (bit)
: "cc" );
#endif
return value;
}
/*!
*
* Multiplication
*
*
*/
/*!
multiplication: result2:result1 = a * b
result2 - higher word
result1 - lower word of the result
this methos never returns a carry
***this method is created only on a 64bit platform***
it is an auxiliary method for version two of the multiplication algorithm
*/
template<uint value_size>
void UInt<value_size>::MulTwoWords(uint a, uint b, uint * result2, uint * result1)
{
/*
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
*/
register uint result1_;
register uint result2_;
#ifndef __GNUC__
#error "another compiler than GCC is currently not supported in 64bit mode"
#endif
#ifdef __GNUC__
__asm__ __volatile__(
"mulq %%rdx \n"
: "=a" (result1_), "=d" (result2_)
: "0" (a), "1" (b)
: "cc" );
#endif
*result1 = result1_;
*result2 = 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<uint value_size>
void UInt<value_size>::DivTwoWords(uint a,uint b, uint c, uint * r, uint * rest)
{
register uint r_;
register uint rest_;
/*
these variables have similar meaning like those in
the multiplication algorithm MulTwoWords
*/
#ifndef __GNUC__
#error "another compiler than GCC is currently not supported in 64bit mode"
#endif
#ifdef __GNUC__
__asm__ __volatile__(
"divq %%rcx \n"
: "=a" (r_), "=d" (rest_)
: "d" (a), "a" (b), "c" (c)
: "cc" );
#endif
*r = r_;
*rest = rest_;
}
#endif
} //namespace

857
ttmath/ttmathuint_noasm.h Normal file
View File

@@ -0,0 +1,857 @@
/*
* This file is a part of TTMath Bignum Library
* and is distributed under the (new) BSD licence.
* Author: Tomasz Sowa <t.sowa@slimaczek.pl>
*/
/*
* 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_noasm
#define headerfilettmathuint_noasm
#ifdef TTMATH_NOASM
/*!
\file ttmathuint_noasm.h
\brief template class UInt<uint> with methods without any assembler code
this file is included at the end of ttmathuint.h
*/
namespace ttmath
{
template<uint value_size>
uint UInt<value_size>::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 value_size>
uint UInt<value_size>::Add(const UInt<value_size> & ss2, uint c)
{
uint i;
for(i=0 ; i<value_size ; ++i)
c = AddTwoWords(table[i], ss2.table[i], c, &table[i]);
TTMATH_LOG("UInt_noasm::Add")
return c;
}
/*!
this method adds one word (at a specific position)
and returns a carry (if it was)
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 value_size>
uint UInt<value_size>::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<value_size && c ; ++i)
c = AddTwoWords(table[i], 0, c, &table[i]);
TTMATH_LOG("UInt_noasm::AddInt")
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)
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 value_size>
uint UInt<value_size>::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<value_size && c ; ++i)
c = AddTwoWords(table[i], 0, c, &table[i]);
TTMATH_LOG("UInt64::AddTwoInts")
return c;
}
template<uint value_size>
uint UInt<value_size>::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 value_size>
uint UInt<value_size>::Sub(const UInt<value_size> & ss2, uint c)
{
uint i;
for(i=0 ; i<value_size ; ++i)
c = SubTwoWords(table[i], ss2.table[i], c, &table[i]);
TTMATH_LOG("UInt_noasm::Sub")
return c;
}
/*!
this method subtracts one word (at a specific position)
and returns a carry (if it was)
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 value_size>
uint UInt<value_size>::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<value_size && c ; ++i)
c = SubTwoWords(table[i], 0, c, &table[i]);
TTMATH_LOG("UInt_noasm::SubInt")
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 value_size>
uint UInt<value_size>::Rcl2_one(uint c)
{
uint i, new_c;
if( c != 0 )
c = 1;
for(i=0 ; i<value_size ; ++i)
{
new_c = (table[i] & TTMATH_UINT_HIGHEST_BIT) ? 1 : 0;
table[i] = (table[i] << 1) | c;
c = new_c;
}
TTMATH_LOG("UInt64::Rcl2_one")
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 value_size>
uint UInt<value_size>::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;
}
TTMATH_LOG("UInt64::Rcr2_one")
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 value_size>
uint UInt<value_size>::Rcl2(uint bits, uint c)
{
TTMATH_ASSERT( bits>0 && bits<TTMATH_BITS_PER_UINT )
uint move = TTMATH_BITS_PER_UINT - bits;
uint i, new_c;
if( c != 0 )
c = TTMATH_UINT_MAX_VALUE >> move;
for(i=0 ; i<value_size ; ++i)
{
new_c = table[i] >> move;
table[i] = (table[i] << bits) | c;
c = new_c;
}
TTMATH_LOG("UInt::Rcl2")
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 value_size>
uint UInt<value_size>::Rcr2(uint bits, uint c)
{
TTMATH_ASSERT( bits>0 && bits<TTMATH_BITS_PER_UINT )
uint move = TTMATH_BITS_PER_UINT - bits;
sint i; // signed
uint new_c;
if( c != 0 )
c = TTMATH_UINT_MAX_VALUE << move;
for(i=value_size-1 ; i>=0 ; --i)
{
new_c = table[i] << move;
table[i] = (table[i] >> bits) | c;
c = new_c;
}
TTMATH_LOG("UInt64::Rcr2")
return (c & TTMATH_UINT_HIGHEST_BIT) ? 1 : 0;
}
/*
this method returns the number of the highest set bit in x
if the 'x' is zero this method returns '-1'
*/
template<uint value_size>
sint UInt<value_size>::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 sets a special bit in the 'value'
and returns the last state of the bit (zero or one)
bit is from <0,63>
e.g.
uint x = 100;
uint bit = SetBitInWord(x, 3);
now: x = 108 and bit = 0
*/
template<uint value_size>
uint UInt<value_size>::SetBitInWord(uint & value, uint bit)
{
TTMATH_ASSERT( bit < TTMATH_BITS_PER_UINT )
uint mask = 1;
if( bit > 1 )
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<uint value_size>
void UInt<value_size>::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<uint value_size>
void UInt<value_size>::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 = temp1.u / c;
temp2.u_.high = temp1.u % c;
temp2.u_.low = b_.u_.low;
res_.u_.low = 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<uint value_size>
void UInt<value_size>::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 value_size>
uint UInt<value_size>::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 value_size>
uint UInt<value_size>::DivTwoWordsUnnormalize(uint u, uint d)
{
if( d == 0 )
return u;
u = u >> d;
return u;
}
template<uint value_size>
unsigned int UInt<value_size>::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<uint value_size>
void UInt<value_size>::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

1279
ttmath/ttmathuint_x86.h Normal file

File diff suppressed because it is too large Load Diff

834
ttmath/ttmathuint_x86_64.h Normal file
View File

@@ -0,0 +1,834 @@
/*
* This file is a part of TTMath Bignum Library
* and is distributed under the (new) BSD licence.
* Author: Tomasz Sowa <t.sowa@slimaczek.pl>
*/
/*
* 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_64
#define headerfilettmathuint_x86_64
#ifndef TTMATH_NOASM
#ifdef TTMATH_PLATFORM64
/*!
\file ttmathuint_x86_64.h
\brief template class UInt<uint> with assembler code for 64bit x86_64 processors
this file is included at the end of ttmathuint.h
*/
namespace ttmath
{
/*!
*
* 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 value_size>
uint UInt<value_size>::Add(const UInt<value_size> & ss2, uint c)
{
uint b = value_size;
uint * p1 = table;
const uint * p2 = ss2.table;
uint dummy, dummy2;
// we don't have to use TTMATH_REFERENCE_ASSERT here
// this algorithm doesn't require it
#ifndef __GNUC__
#error "another compiler than GCC is currently not supported in 64bit mode"
#endif
#ifdef __GNUC__
/*
this part should be compiled with gcc
*/
__asm__ __volatile__(
"xorq %%rdx, %%rdx \n"
"neg %%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_LOG("UInt64::Add")
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 value_size>
uint UInt<value_size>::AddInt(uint value, uint index)
{
uint b = value_size;
uint * p1 = table;
uint c;
uint dummy, dummy2;
TTMATH_ASSERT( index < value_size )
#ifndef __GNUC__
#error "another compiler than GCC is currently not supported in 64bit mode"
#endif
#ifdef __GNUC__
__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)
: "a" (value), "c" (b), "0" (index), "b" (p1)
: "cc", "memory" );
#endif
TTMATH_LOG("UInt64::AddInt")
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 value_size>
uint UInt<value_size>::AddTwoInts(uint x2, uint x1, uint index)
{
uint b = value_size;
uint * p1 = table;
uint c;
uint dummy, dummy2;
TTMATH_ASSERT( index < value_size - 1 )
#ifndef __GNUC__
#error "another compiler than GCC is currently not supported in 64bit mode"
#endif
#ifdef __GNUC__
__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)
: "1" (b), "2" (index), "b" (p1), "S" (x1), "0" (x2)
: "cc", "memory" );
#endif
TTMATH_LOG("UInt64::AddTwoInts")
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 value_size>
uint UInt<value_size>::Sub(const UInt<value_size> & ss2, uint c)
{
uint b = value_size;
uint * p1 = table;
const uint * p2 = ss2.table;
uint dummy, dummy2;
// we don't have to use TTMATH_REFERENCE_ASSERT here
// this algorithm doesn't require it
#ifndef __GNUC__
#error "another compiler than GCC is currently not supported in 64bit mode"
#endif
#ifdef __GNUC__
__asm__ __volatile__(
"xorq %%rdx, %%rdx \n"
"neg %%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_LOG("UInt64::Sub")
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 value_size>
uint UInt<value_size>::SubInt(uint value, uint index)
{
uint b = value_size;
uint * p1 = table;
uint c;
uint dummy, dummy2;
TTMATH_ASSERT( index < value_size )
#ifndef __GNUC__
#error "another compiler than GCC is currently not supported in 64bit mode"
#endif
#ifdef __GNUC__
__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)
: "1" (value), "2" (b), "0" (index), "b" (p1)
: "cc", "memory" );
#endif
TTMATH_LOG("UInt64::SubInt")
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 value_size>
uint UInt<value_size>::Rcl2_one(uint c)
{
sint b = value_size;
uint * p1 = table;
uint dummy, dummy2;
#ifndef __GNUC__
#error "another compiler than GCC is currently not supported in 64bit mode"
#endif
#ifdef __GNUC__
__asm__ __volatile__(
"xorq %%rdx, %%rdx \n" // rdx=0
"neg %%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)
: "1" (c), "0" (b), "b" (p1)
: "cc", "memory" );
#endif
TTMATH_LOG("UInt64::Rcl2_one")
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 value_size>
uint UInt<value_size>::Rcr2_one(uint c)
{
sint b = value_size;
uint * p1 = table;
uint dummy;
#ifndef __GNUC__
#error "another compiler than GCC is currently not supported in 64bit mode"
#endif
#ifdef __GNUC__
__asm__ __volatile__(
"neg %%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)
: "1" (c), "0" (b), "b" (p1)
: "cc", "memory" );
#endif
TTMATH_LOG("UInt64::Rcr2_one")
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 value_size>
uint UInt<value_size>::Rcl2(uint bits, uint c)
{
TTMATH_ASSERT( bits>0 && bits<TTMATH_BITS_PER_UINT )
uint b = value_size;
uint * p1 = table;
uint dummy, dummy2, dummy3;
#ifndef __GNUC__
#error "another compiler than GCC is currently not supported in 64bit mode"
#endif
#ifdef __GNUC__
__asm__ __volatile__(
"movq %%rcx, %%rsi \n"
"movq $64, %%rcx \n"
"subq %%rsi, %%rcx \n"
"movq $-1, %%rdx \n"
"shrq %%cl, %%rdx \n"
"movq %%rdx, %%r8 \n"
"movq %%rsi, %%rcx \n"
"xorq %%rdx, %%rdx \n"
"movq %%rdx, %%rsi \n"
"orq %%rax, %%rax \n"
"cmovnz %%r8, %%rsi \n"
"1: \n"
"rolq %%cl, (%%rbx,%%rdx,8) \n"
"movq (%%rbx,%%rdx,8), %%rax \n"
"andq %%r8, %%rax \n"
"xorq %%rax, (%%rbx,%%rdx,8) \n"
"orq %%rsi, (%%rbx,%%rdx,8) \n"
"movq %%rax, %%rsi \n"
"incq %%rdx \n"
"decq %%rdi \n"
"jnz 1b \n"
"and $1, %%rax \n"
: "=a" (c), "=D" (dummy), "=S" (dummy2), "=d" (dummy3)
: "0" (c), "1" (b), "b" (p1), "c" (bits)
: "%r8", "cc", "memory" );
#endif
TTMATH_LOG("UInt64::Rcl2")
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
***this method is created only on a 64bit platform***
*/
template<uint value_size>
uint UInt<value_size>::Rcr2(uint bits, uint c)
{
TTMATH_ASSERT( bits>0 && bits<TTMATH_BITS_PER_UINT )
sint b = value_size;
uint * p1 = table;
uint dummy, dummy2, dummy3;
#ifndef __GNUC__
#error "another compiler than GCC is currently not supported in 64bit mode"
#endif
#ifdef __GNUC__
__asm__ __volatile__(
"movq %%rcx, %%rsi \n"
"movq $64, %%rcx \n"
"subq %%rsi, %%rcx \n"
"movq $-1, %%rdx \n"
"shlq %%cl, %%rdx \n"
"movq %%rdx, %%R8 \n"
"movq %%rsi, %%rcx \n"
"xorq %%rdx, %%rdx \n"
"movq %%rdx, %%rsi \n"
"addq %%rdi, %%rdx \n"
"decq %%rdx \n"
"orq %%rax, %%rax \n"
"cmovnz %%R8, %%rsi \n"
"1: \n"
"rorq %%cl, (%%rbx,%%rdx,8) \n"
"movq (%%rbx,%%rdx,8), %%rax \n"
"andq %%R8, %%rax \n"
"xorq %%rax, (%%rbx,%%rdx,8) \n"
"orq %%rsi, (%%rbx,%%rdx,8) \n"
"movq %%rax, %%rsi \n"
"decq %%rdx \n"
"decq %%rdi \n"
"jnz 1b \n"
"rolq $1, %%rax \n"
"andq $1, %%rax \n"
: "=a" (c), "=D" (dummy), "=S" (dummy2), "=d" (dummy3)
: "0" (c), "1" (b), "b" (p1), "c" (bits)
: "%r8", "cc", "memory" );
#endif
TTMATH_LOG("UInt64::Rcr2")
return c;
}
/*
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<uint value_size>
sint UInt<value_size>::FindLeadingBitInWord(uint x)
{
register sint result;
#ifndef __GNUC__
#error "another compiler than GCC is currently not supported in 64bit mode"
#endif
#ifdef __GNUC__
__asm__ __volatile__(
"bsrq %1, %0 \n"
"jnz 1f \n"
"movq $-1, %0 \n"
"1: \n"
: "=R" (result)
: "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 value_size>
uint UInt<value_size>::SetBitInWord(uint & value, uint bit)
{
TTMATH_ASSERT( bit < TTMATH_BITS_PER_UINT )
uint old_bit;
uint v = value;
#ifndef __GNUC__
#error "another compiler than GCC is currently not supported in 64bit mode"
#endif
#ifdef __GNUC__
__asm__ __volatile__(
"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<uint value_size>
void UInt<value_size>::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
*/
register uint result1_;
register uint result2_;
#ifndef __GNUC__
#error "another compiler than GCC is currently not supported in 64bit mode"
#endif
#ifdef __GNUC__
__asm__ __volatile__(
"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<uint value_size>
void UInt<value_size>::DivTwoWords(uint a,uint b, uint c, uint * r, uint * rest)
{
register uint r_;
register uint rest_;
/*
these variables have similar meaning like those in
the multiplication algorithm MulTwoWords
*/
TTMATH_ASSERT( c != 0 )
#ifndef __GNUC__
#error "another compiler than GCC is currently not supported in 64bit mode"
#endif
#ifdef __GNUC__
__asm__ __volatile__(
"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