This section contains the bare minimum required to get started. Refer to the libmpdec manual for anything more advanced.
For a custom build, refer to INSTALL.txt. For a Windows build, see
vcbuild\README.txt
.
# Unix:
./configure
make
# Run the tests (optional). This downloads the official test cases
# (text files):
make check
# As root, install the libraries:
sudo make install
# Depending on your system (e.g., Ubuntu), you may need to run ldconfig.
# Replace "/usr/local/lib" with the actual install location that appears
# in the "make install" output:
sudo ldconfig /usr/local/lib
# Unix:
cd libmpdec
make examples
# Try a couple of values:
./pow 2 1234567
4.9963964863286026867472463500015498863E+371641 Inexact Rounded
This section contains the bare minimum required to get started. Refer to the libmpdec++ manual for anything more advanced.
libmpdec++ is installed by default, unless –disable-cxx is passed to ./configure.
For a Windows build, see vcbuild\README.txt
.
Build the examples:
# Unix:
cd libmpdec++
make examples
# Try a couple of values:
./pi 7
3.141593
./pi 40
3.141592653589793238462643383279502884197
./factorial 5
120
./factorial 40
815915283247897734345611269596115894272000000000
time ./factorial 1000000 > /dev/null
real 0m2.204s
Compare the pi function to the Python version further down. There is not much difference:
Decimal
pi(int prec)
{
context.prec(prec + 2);
Decimal lasts = 0;
Decimal t = 3;
Decimal s = 3;
Decimal n = 1;
Decimal na = 0;
Decimal d = 0;
Decimal da = 24;
while (s != lasts) {
lasts = s;
n += na;
na += 8;
d += da;
da += 32;
t = (t * n) / d;
s += t;
}
context.prec(prec);
return +s;
}
As for every C extension, the build requires a working C compiler. For most Linux distributions, the Python header files have to be installed explicitly, since they are shipped as a separate package:
# Debian, Ubuntu:
sudo apt-get install gcc make
sudo apt-get install python-dev
# Fedora, RedHat:
sudo yum install gcc make
sudo yum install python-devel
# openSUSE:
sudo zypper install gcc make
sudo zypper install python-devel
# BSD:
# You know what to do.
# Mac OS X:
# Install Xcode and Python headers.
If pip is present on the system, installation should be as easy as:
pip install cdecimal
Otherwise:
tar xvzf cdecimal-2.3.tar.gz
cd cdecimal-2.3
python setup.py install
If problems arise, read the file PYINSTALL.txt which comes with the distribution.
The easiest way is to use the binary installers. Otherwise, the build requires Visual Studio.
Showing off cdecimal’s bignum speed. Note that the factorial function is entirely written in Python and does not call a C factorial function.
from cdecimal import *
def _factorial(n, m):
if (n > m):
return _factorial(m, n)
elif m == 0:
return 1
elif n == m:
return n
else:
return _factorial(n, (n+m)//2) * _factorial((n+m)//2 + 1, m)
def factorial(n):
return _factorial(n, 0)
c = getcontext()
c.prec = MAX_PREC
# 1000000! in pure Python
x = factorial(Decimal(1000000))
sx = str(x)
# Compare to Python integers:
y = factorial(1000000)
sy = str(y)
Showing off cdecimal’s speed for small precisions. Again, the algorithm is in pure Python and does not involve calling a custom C pi-function. This is also the benchmark where cdecimal is often faster than Java’s BigDecimal.
import cdecimal
import decimal
def pi(module, prec):
"""From the decimal.py documentation"""
module.getcontext().prec = prec + 2
D = module.Decimal
lasts, t, s, n, na, d, da = D(0), D(3), D(3), D(1), D(0), D(0), D(24)
while s != lasts:
lasts = s
n, na = n+na, na+8
d, da = d+da, da+32
t = (t * n) / d
s += t
module.getcontext().prec -= 2
return +s
for i in range(10000):
x = pi(cdecimal, 28)
for i in range(10000):
y = pi(decimal, 28)
The telco benchmark was devised by Mike Cowlishaw as a way of measuring decimal performance in a real world telecom application.
Get telco.py, telco.testb, expon180-1e6b.zip and unzip expon180-1e6b.zip.
# decimal.py
python telco.py # sanity check
python telco.py full # benchmark
# Edit telco.py and change decimal to cdecimal.
# Speedups should be about 30x.
python telco.py # sanity check
python telco.py full # benchmark
This is a nice tip from the sqlalchemy developers. Since cdecimal.Decimal currently does not support mixed operations with decimal.Decimal, the easiest way to enforce global use of cdecimal is to occupy both places for cdecimal and decimal in sys.modules. This must take place at program start, before importing anything else.
This technique is used in the following section in the file psycopg.py.
# At program start:
import sys
import cdecimal
sys.modules["decimal"] = cdecimal
# Further imports:
import psycopg2 # psycopg2 imports cdecimal, masquerading as decimal
from decimal import * # same here, this is now cdecimal
...
The PostgreSQL database adapter psycopg supports PostgreSQL’s numeric type. For a speed comparison, download setup_dectest.sql and psycopg.py. Naturally, both PostgreSQL and psycopg2 are required for this benchmark.
The benchmark inserts 100000 rows containing numeric data into the test database. Subsequently, it fetches all rows. Since INSERT has a lot of database overhead, the main speed gains are in FETCHALL. Similar speed gains (10x) have also been reported by Informix database users.
# Setup a test database:
psql < setup_dectest.sql
# Run the benchmark for decimal.py:
python psycopg.py
# Edit psycopg.py and uncomment the top two import lines to
# use cdecimal globally.
# The speedup should be about 1.7x for INSERT and 12x for FETCHALL.
python psycopg.py