I already have a code which uses the bisection method to determine the value of something, the problem is that I need a value so precise, more than 15 decimals, and at some
For float
instances, Python uses machine-level double precision floating point numbers (double
in C terms). What exactly this is depends on the platform and compiler that built Python.
These days it is most probably a 64-bit double-precision binary floating-point number. The 53-bit significand gives between 15 to 17 significant decimal digits.
If you use numpy
, you can use the long double
floating point number. This has a 64-bit sigificand, yielding approximately 18 decimal digits.
Decimal
values have adjustable precision. By default it is 28 significant digits, but you can change that. So changing to Decimal is probably a good choice if you can get by with the standard mathematical operators and the limited amount of mathematical functions that Decimal
supports. But this would indeed mean changing all your code. It is part of the standard library, that might be a plus.
Alternatively, you could look at the mpmath library. This also allows you to set an arbitrary precision (it defaults to 15 significant digits). It supports much more advanced mathematics than Decimal
. It implements all the functions from math
and cmath
and more. But here you would also have to convert your whole program to change float
to the mpf
type. By default, mpmath works with integers internally. When available, mpmath uses the Python bindings to the gmp library which makes it much faster, especially at high precision (>100 digits).
If you want more precision, you will have to convert your program to use a arbitrary precision math module. Depending on how many math
functions you use, mpmath
looks like a better fit; it supports all functions from math
and cmath
and then some.
A total automatic conversion from float
to mpf
(or Decimal
) types is not possible. But you can get most of the way there.
Both Decimal
and mpf
support the standard math operators. So you should not have to change those. You do need to look at places where you create or input floating point numbers and at places where you use functions from math
.
First, change all instances of float(
to Decimal(
or mpf(
. That takes care of explicitly created numbers.
Second, search for all floating point literals and replace them the same way. You can use your editor's search-and-replace function for this, or you can write a small Python script for it. So this can largely be automated.
Then look at all the functions that read data from a source (e.g. a file or database), and update them. This will probably have to be done manually, unless there these explicitly use float()
, in which case they are handled by the abovementioned method.
If you are currently using the math
module, you will have to search and replace those functions by their equivalents in the chosen module. In this case the search part can be easily automated.
If you have used import math
, you can easily search for "math.
" to find the functions that need replacing. In this case when using mpmath
, you could simply replace "math.
" with "mpmath.
", since mpmath
implements all functions from math
.
If you have used from math import x, y, z
, you need to search for x, y and z separately. You could even write a script to translate math
functions to their equivalents in Decimal
or mpf
. It depends on the size and complexity of your code base if this is worth doing.
You are asking if you can change the Python builtin type of floating point literals from float
to (for example) decimal.Decimal
. You can't do that.
Other things to consider
If decimal.Decimal
is central to your code, you could import it with a shorter name:
from decimal import Decimal as Dec
x1 = Dec('0.234')
y1 = Dec('4.32')
x2 = Dec('4.321')
y2 = Dec('5.87')
Type annotations can help you to not miss conversions:
def distance(x1: Dec, y1: Dec, x2: Dec, y2: Dec) -> Dec:
return Dec.sqrt((x2 - x1)**2 + (y2 - y1)**2)
If precision is important, initialize decimal.Decimal
with a string instead of float. Floats can't exactly represent simple numbers, like for example 0.2:
>>> Dec(0.2)
Decimal('0.200000000000000011102230246251565404236316680908203125')
>>> Dec('0.2')
Decimal('0.2')
There is probably a limited number of places where you have to convert to Decimal
. Most operations on Decimal
either gives a new Decimal, or throws an exception.
>>> d = distance(x1, y1, x2, y2)
>>> d
Decimal('4.371048958774083555277441787')
>>> (d + x1*x2 + y1*y2**2) / 100
Decimal('1.542359709587740835552774418')
I know this is not perfect, but it might help.