user84055
user84055

Reputation: 33

Bigfloat - Error in the precision

I'm trying to use Bigfloat library in python 2.7.

from bigfloat import *

f1 = Context(precision=2000)

with precision(2000):  f1 = 1e-19*1e-19*9e9/((1-1e-18)*(1-1e-18))-1e-19*1e-19*9e9

with precision(100):  f2 = 1.6e-27*1.6e-27*6.6e-11/(1e-18*1e-18)

print BigFloat(f1) print f2

Python gives me f1=0, but it is not true. I tested it with g++ and the result is 1.75e-46.

Is it an error in my program? Is it not possible to calculate this precision with Bigfloat ? Is it an error in the lib?

Upvotes: 1

Views: 718

Answers (1)

Mark Dickinson
Mark Dickinson

Reputation: 30856

As an example, here's how you might compute f1 to a precision of 256 bits using the bigfloat library.

>>> from bigfloat import BigFloat, precision
>>> with precision(256):
...     x = BigFloat('1e-19')
...     y = BigFloat('9e9')
...     z = BigFloat('1e-18')
...     f1 = x * x * y / ((1 - z) * (1 - z)) - x * x * y
... 
>>> f1
BigFloat.exact('1.800000000000000002700000000000000003600000000000000004500006811997284879750608e-46', precision=256)

Note the use of BigFloat('1e-19'), which is creating the closest binary float to 10**-19 at the current precision (256 bits). This is different from BigFloat(1e-19) (without the single quotes), since there 1e-19 is a Python float, so has already been rounded to 53-bit precision.

Take a look at the documentation for more details.

However, with a bit of creativity and algebra, you don't need a high-precision library at all here. You can rewrite the expression for f1 as:

f1 = x * x * y * (1 / ((1 - z) * (1 - z)) - 1)

and by putting everything over a common denominator, the quantity in parentheses can be rewritten as (2 - z) * z / ((1 - z) * (1 - z)). So you could equally well compute f1 as:

f1 = x * x * y * (2-z) * z / ((1 - z) * (1 - z))

and in this form, you don't lose accuracy when z is very small. So now regular Python floats are good enough:

>>> x = 1e-19
>>> y = 9e9
>>> z = 1e-18
>>> f1 = x * x * y * (2 - z) * z / ((1 - z) * (1 - z))
>>> f1
1.8e-46

If you do decide you want to use a high-precision floating-point library, I'd also recommend looking at the gmpy2 library. It's based on the same underlying MPFR library as bigfloat, but it's better maintained.

Upvotes: 1

Related Questions