Multi-Precision Arithmetic by C++ with no use of
assembler
SN library Copyright (C) 1999-2018 K.Tsuru
Elementary directions
Here I shall explain the fundamental usage of this library.
About specification statements, overloaded operators and upper limit of
digits
You can easily translate a conventional C++ program into a "SN" one by replacing
"long" with "SLong" and "double" with "SDouble". Allowing time and memory the
default maximum
length is about four million(=106) digits for 32 bit system or about several billion(=109) digits for 64 bit system.
A number of four million figures occupies a memory 2MB.
In my library many recursive functions are used. It costs much memory and stack.
Considering the speed of CPU and memory in present personal computer I think that
it is not feasible over the above value. How do you think?
More in the real functions uses the series in which division by "unsigned long" is used. The divisor must be less than ULONG_MAX/radix for the speed. Then for a large
significant figures the series will not converge within this value.
See also "sn32-64/doc/cputime.txt".
Firstly I show some examples.
Sample program 1
--------------------------------------------------------------
#include "sn.h" // SN library's header file int main() { SLong f; // declaration of multi-precision integer SDouble pi; // declaration of multi-precision real number f = Fact(10000000); //calculate a factorial 10,000,000! (18 sec)and substitute to lhs cout << a << endl; //output using iostream operator 65,657,053 digits. It takes much time. pi = Pi(); //calculate pi in default significant figures(*) cout << pi << endl; //output }---------------------------------------------------------------
// SDouble a(0); /* error */ SDouble a(0.0), b(10), c(b), e("1.0e-500"), f; // initialize SLong g; cin >> g; // input any long integer by keyboard ............... f="0.12345678901234567890123456789e10000"; g="1.5e200"; cout << f*g << endl;Sample program 2
-------------------------------------------------------------- SFraction f, g, r; // declaration of multi-precision fraction f = "1009/99799811"; g = "997/99819757"; //set values by strings //f.Set(1009L, 99799811L); can be used r = f+g; cout << f << '+' << g << '=' << r << endl; r = f-g; cout << f << '-' << g << '=' << r << endl; r = f*g; cout << f << '*' << g << '=' << r << endl; r = f/g; cout << f << '/' << g << '=' << r << endl; --------------------------------------------------------------"SFraction" class has decimal radix(10000). "SRational" class whose radix is binary (32768) can also be used. As shown the above usual operators '+', '-', '*' and '/' can be used.
SFraction f(1, 3); // f=1/3 SDouble a; a=f; //Ok, a = 0.33333.... f=a; //error, not convert to 1/3
---------------------------------------------------------------------notice "SDouble" object cannot call the function "SetEffFig()", i.e. "pi.SetEffFig(500)" causes an error. It is desirable to take the number of significant figures near and smaller a little the power of two(2n), because the efficiency of FFT multiplication and memory size are good.
RealSize C; // Only one object is permitted. C.SetEffFig(250); //change the number of significant figures into 250*4=1000 digits SDouble pi; pi=Pi(); cout << pi << endl; // C.SetEffFig(500); /* error */ C.SetEffFig(0); //put back to previous value C.SetEffFig(500); //Ok. "500" is near to and within 2 to the 9th power 512. ---------------------------------------------------------------------
About speed of calculation including
square
A statement
y = a *(x *x );
is faster than
y = a *x *x;
because in the (x*x ) an optimization can be done for SLong
or SDouble numbers e.g. in a multiplication
xy = (aR + b )(cR + d ) = acR 2+(ad
+bc )R +bd (R is power of radix)
when x== y (i.e. &x == &y ), ad == bc,
then one multiplication can be reduced.