3 ms·
Here's how you can use sympy (`pip install sympy`) or the decimal module to get better numerical answers out of python: # as shown in the text, fp math yie
by llimllib 3y ago
Here's how you can use sympy (`pip install sympy`) or the decimal module to get better numerical answers out of python:
# as shown in the text, fp math yields an inexact result.
# should be 3.310115e-5
$ python -c "from math import *; print(8721*sqrt(3)-10_681*sqrt(2))"
3.31011488015065e-05
# https://docs.sympy.org/latest/modules/evalf.html
$ python -c "from sympy import *; print(N(8721*sqrt(3)-10_681*sqrt(2)))"
3.31011506606020e-5
# the second argument to N is the desired precision
$ python -c "from sympy import *; print(N(8721*sqrt(3)-10_681*sqrt(2), 50))"
0.000033101150660602022280988927734905539317579147087675
# or using the somewhat more awkward decimal module:
$python -c "from decimal import *; print(Decimal(8721)*Decimal(3).sqrt() - Decimal(10_681)*Decimal(2).sqrt())"
0.00003310115066060202229
I'm not at all an expert at this, just wanted to play around with some tools that have helped me with similar problems in the past.
I also don't know how accurate the digits following `3310115` are! All I know is that these are ways to make the machine spit out the correct number up to seven digits; I'd love it if somebody would explain to me more of what I've done here tbh
- svilen_dobrev 3y agofurther, python has fractions (with proper divisors' arithmetic over them), so >>> Fraction("2/3") * Fraction("66/13") Fraction( 44, 13)
- Majromax 3y agoWhat you've done here is tell SymPy to use extra precision for the intermediate (and final) output. This doesn't truly fix the problem of cancellation and loss of precision, but for many practical purposes it can postpone the problem long enough to give you a useful result. Internally, SymPy uses mpmath (https://mpmath.org/ https://mpmath.org/) for representation of numbers to arbitrary precision. You could install and use the latter library directly, gaining extra precision without going through symbolic manipulation. All that being said, it's still good practice to avoid loss of precision at the outset. Arbitrary-precision calculations are slow compared to hardware-native floating point operations. Using the example from mpmath's homepage in iPython: In [1]: import mpmath as mp; import scipy as sp; import numpy as np In [2]: mp.mp.dps=50 # set extended precision In [3]: %%timeit ...: mp.quad(lambda x: mp.exp(-x**2), [-mp.inf, mp.inf]) ** 2 40.5 ms ± 4.74 ms per loop (mean ± std. dev. of 7 runs, 10 loops each) In [4]: mp.quad(lambda x: mp.exp(-x**2), [-mp.inf, mp.inf]) ** 2 Out[4]: mpf('3.1415926535897932384626433832795028841971693993751015') In [5]: %%timeit ...: sp.integrate.quad(lambda x: np.exp(-x**2), -np.inf, np.inf)[0]**2 570 µs ± 78.9 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each) In [6]: sp.integrate.quad(lambda x: np.exp(-x**2), -np.inf, np.inf)[0]**2 Out[6]: 3.1415926535897927
- aidenn0 3y agoSymPy will numerically approximate the value of the equation inside "N" to the number of specified decimal digits, so the first 50 non-zero digits will be completely correct[1] when you pass "50" as the second argument to N. 1: I'm not sure how SymPy handles rounding, but it is typical to round the last digit so e.g. printing just 5 digits of 0.123456 would correctly be 0.12346