9

I am currently working with very small numbers in my python program, e.g.

x = 200 + 2e-26

One solution is to work with logarithmic values which would increase the range of my float value. The problem is that I have to do a fft with these values, too, and therefore using the logarithmic approach is not usable (and using the Decimal-module neither). Is there another way to solve that problem?

Edit: My problem with the decimal module is: How can I handle imaginary values? I tried a = Decimal(1e-26)+Decimal(1e-26*1j) and a = Decimal(1e-26)+Decimal(1e-26)*1j, and both ways failed (error on request).

arc_lupus
  • 3,942
  • 5
  • 45
  • 81
  • 3
    What's wrong with the `decimal` module? – Aaron Digulla Apr 07 '15 at 09:32
  • I can not use it for complex numbers, I tried with `a=Decimal(1e-26)+Decimal(1e-26*1j)` and `a=Decimal(1e-26)+Decimal(1e-26)*1j`. Is there another way? – arc_lupus Apr 07 '15 at 09:36
  • Isn't the problem more like that you have very small numbers added on top of larger numbers and the small number simply drops of at the end of precision? Can you normalize the large number away? – dhke Apr 07 '15 at 09:51
  • The `decimal` module doesn't support complex numbers, from what I can tell. You might be able to mash the `complex` and `Decimal` types together in some class, but I'm not sure if that's the best approach... – Martijn Arts Apr 07 '15 at 09:53
  • Are the numbers all biased? So is the "large" component all the time the same? – Oliver W. Apr 07 '15 at 09:56
  • The numbers are biased, but only for the values @ n*10**2, so there is no real benefit. – arc_lupus Apr 07 '15 at 10:39

2 Answers2

3

Consider trying out the mpmath package.

>>> from mpmath import mpf, mpc, mp
>>> mp.dps = 40
>>> mpf(200) + mpf(2e-26) + mpc(1j)
mpc(real='200.0000000000000000000000000200000000000007', imag='1.0')

Mostly accurate and can handle complex numbers, more details in the documentation.

metatoaster
  • 17,419
  • 5
  • 55
  • 66
2

While numpy supports more decimal types (and also complex versions), they don't help:

>>> import numpy
>>> numpy.longfloat
<type 'numpy.float128'>
>>> a = numpy.array([200, 2e-26], dtype=numpy.longfloat)
>>> a
array([ 200.0,  2e-26], dtype=float128)
>>> a.sum()
200.0
>>> a = numpy.array([200, 2e-26], dtype=numpy.longdouble)
>>> a.sum()
200.0

The reason is explained here: Internally, numpy uses 80 bits which means 63 bits mantissa which just supports 63/3 = 21 digits.

What you need is a real 128bit float type like the one from boost.

Try the Boost.Python module which might give you access to this type. If that doesn't work, then you'll have to write your own wrapper class in C++ as explained here.

Community
  • 1
  • 1
Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820