Use more decimals in Python

前端 未结 2 369
南笙
南笙 2021-01-19 04:17

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

相关标签:
2条回答
  • 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).

    Conclusion

    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.

    How to convert

    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.

    0 讨论(0)
  • 2021-01-19 04:42

    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.

    0 讨论(0)
提交回复
热议问题