Python mpmath not arbitrary precision? - python

I'm trying to continue on my previous question in which I'm trying to calculate Fibonacci numbers using Benet's algorithm. To work with arbitrary precision I found mpmath. However the implementation seems to fail above certain value. For instance the 99th value gives:
218922995834555891712
This should be (ref):
218922995834555169026
Here is my code:
from mpmath import *
def Phi():
return (1 + sqrt(5)) / 2
def phi():
return (1 - sqrt(5)) / 2
def F(n):
return (power(Phi(), n) - power(phi(), n)) / sqrt(5)
start = 99
end = 100
for x in range(start, end):
print(x, int(F(x)))

mpmath does do arbitrary precision math, and it does do it accurately to any precision (as described above) if you are using the arbitrary precision math module and not the default behavior.
mpmath has more than one module which determines the accuracy and speed of the results (to be chosen depending on what you need), and by default it uses Python floats, which is what I believe you saw above.
If you call mpmath's fib( ) having set mp.dps high enough, you will get the correct answer as stated above.
>>> from mpmath import mp
>>> mp.dps = 25
>>> mp.nprint( mp.fib( 99 ), 25 )
218922995834555169026.0
>>> mp.nprint( mpmath.fib( 99 ), 25 )
218922995834555169026.0
Whereas, if you don't use the mp module, you will only get results as accurate as a Python double.
>>> import mpmath
>>> mpmath.dps = 25
>>> mpmath.nprint( mpmath.fib( 99 ), 25
218922995834555170816.0

mpmath provides arbitrary precision (as set in mpmath.mp.dps), but still inaccuate calculation. For example, mpmath.sqrt(5) is not accurate, so any calculation based on that will also be inaccurate.
To get an accurate result for sqrt(5), you have to use a library which supports abstract calculation, e.g. http://sympy.org/ .
To get an accurate result for Fibonacci numbers, probably the simplest way is using an algorithm which does only integer arithmetics. For example:
def fib(n):
if n < 0:
raise ValueError
def fib_rec(n):
if n == 0:
return 0, 1
else:
a, b = fib_rec(n >> 1)
c = a * ((b << 1) - a)
d = b * b + a * a
if n & 1:
return d, c + d
else:
return c, d
return fib_rec(n)[0]

Actually mpmath's default precision is 15 which I think is not enough if you want to get the result of up to 21-digit precision.
One thing you can do is set the precision to be a higher value and use mpmath's defined arithmetic functions for addition, subtraction, etc.
from mpmath import mp
mp.dps = 50
sqrt5 = mp.sqrt(5)
def Phi():
return 0.5*mp.fadd(1, sqrt5)
def phi():
return 0.5*mp.fsub(1, sqrt5)
def F(n):
return mp.fdiv(mp.power(Phi(), n) - mp.power(phi(), n), sqrt5)
print int(F(99))
This will give you
218922995834555169026L

Related

Euler-Mascheroni Constant

In programming, I used only Integers. But this time for some calculations. I need to calculate Euler-Mascheroni Constant γ . up to n-th decimal.{Though n ∈ [30, 150] is enough for me.
[x] = gif(x) = math.floor(x)
But, I doubt the precision
Numerical Algorithm
I need higher degree of accuracy using Python.
From the French Wikipedia discussion page, an approximation to 6 decimal places:
import math as m
EulerMascheroniApp = round( (1.-m.gamma(1+1.e-8))*1.e14 )*1.e-6
print(EulerMascheroniApp)
# 0.577216
This constant is also available in the sympy module, under the name EulerGamma:
>>> import sympy
>>> sympy.EulerGamma
EulerGamma
>>> sympy.EulerGamma.evalf()
0.577215664901533
>>> - sympy.polygamma(0,1)
EulerGamma
>>> sympy.stieltjes(0)
EulerGamma
>>> sympy.stieltjes(0, 1)
EulerGamma
Documentation:
math.gamma;
sympy.EulerGamma;
sympy.functions.special;
sympy: numerical evaluation.
On this last documentation link, you can find more information about how to evaluate the constant with more precision, if the default of .evalf() is not enough.
If you still want to compute the constant yourself as an exercise, I suggest comparing your results to sympy's constant, to check for accuracy and correctness.
You can calculate it using python Decimal built-in module to control how many decimals (https://docs.python.org/2/library/decimal.html) you are going to use.
a = 1/7
len(str(a))-2
Out[1] 17
using Decimal:
from decimal import *
getcontext().prec = 90 #90 decimals precision
a = Decimal(1) / Decimal(7)
len(str(a))-2
Out[2] 90
basically:
n = 100000
Euler_Mascheroni = -Decimal(log(Decimal(n))) + sum([Decimal(1)/Decimal(i) for i in range(1,n)])
Euler_Mascheroni
Out[3] Decimal('0.577210664893199330073570099082905499710324918344701101627529415938181982282214')
finally, you can "arbitrarily" increase precision:
from decimal import *
from math import log
def Euler_Mascheroni(n,nth_decimals = 80):
getcontext().prec = nth_decimals
SUM = Decimal(0)
for i in range(1,n):
SUM+=Decimal(1)/Decimal(i)
return -Decimal(log(Decimal(n))) + SUM
Euler_Mascheroni(100000000,nth_decimals = 120)
which gives:
Decimal('0.5772156599015311156682000509495086978690376512201034388184221886576113026091829254475798266636558124658249350393045066')
Answering comment from #Stef
EM = Decimal(0.57721566490153286060651209008240243104215933593992)#reference taken from wikipedia
n = 100000000
Decimal(log(Decimal(n)))
getcontext().prec = 100
SUM = Decimal(0)
for i in range(1,n):
SUM+=Decimal(1)/Decimal(i)
EM - (SUM-Decimal(log(Decimal(n))))
will give
Decimal('5.00000174 ... 85E-9')

How does Integer Division work in python?

So, I have recently heard of Integer Division and that it is very fast. I have always been using Bit Shifting when I do floor(x / 2^n).
So, I have tested if which is faster Integer Division or Bit Shifting so, I made this code where it tests and compare it 100 times and find the mean:
import timeit
import statistics as stat
def compare_times(a, b):
res_a = timeit.timeit(a)
res_b = timeit.timeit(b)
c = res_a - res_b # if negative, a is faster
return c
output = []
for _ in range(100):
output.append(compare_times("5 >> 1", "5 // 2"))
print (stat.mean(output))
And the result is positive, meaning b is faster. Isn't bit shifting working directly at the bit of the number? Why is it slower than Integer Division?
I tested another thing to see if it is because I chose 5, so:
import timeit
import statistics as stat
import random
def compare_times(a, b):
res_a = timeit.timeit(a)
res_b = timeit.timeit(b)
c = res_a - res_b # if negative, a is faster
return c
output = []
for _ in range(100):
number = random.randrange(5000, 50001)
output.append(compare_times(f"{number} >> 1", f"{number} // 2"))
print (stat.mean(output))
which also outputted positve.
The only time I see a (bit shift) is faster than Integer Division is when in floor(x / 2^n), n >= 2.
So, ultimately, how does Integer Division work? And why is it faster than Bit Shift in terms of smaller numbers?
Any time difference you're seeing is spurious; in fact, 5 // 2 and 5 >> 1 both compile to the same CPython bytecode:
>>> from dis import dis
>>> dis('5 // 2')
1 0 LOAD_CONST 2 (2)
2 RETURN_VALUE
>>> dis('5 >> 1')
1 0 LOAD_CONST 2 (2)
2 RETURN_VALUE
That is, the computation is done at compile-time, not at runtime, so you are actually just measuring how long it takes to load a pre-computed constant in both cases. To get an accurate benchmark, you need to actually perform the computation at runtime, such as by passing a variable; I also suggest using larger numbers (or raising the number of repetitions beyond the default of 1,000,000) to get a more reliable comparison.
>>> n = 1234 ** 56 # a 174-digit number
>>> from timeit import timeit
>>> timeit(lambda: n // 2)
0.32904140199389076
>>> timeit(lambda: n >> 1)
0.12879745499958517
So we can see that at least for very large numbers, bit-shifting is faster, as you would expect. For smaller numbers there may be no significant difference.
As for how CPython actually computes integer division, the source code on GitHub is freely available to read, and according to a comment there, the algorithm used is found in a well-known textbook:
/* We follow Knuth [The Art of Computer Programming, Vol. 2 (3rd
edn.), section 4.3.1, Algorithm D], except that we don't explicitly
handle the special case when the initial estimate q for a quotient
digit is >= PyLong_BASE: the max value for q is PyLong_BASE+1, and
that won't overflow a digit. */

Calculate e in Python [duplicate]

This question already has answers here:
Python basic math [closed]
(3 answers)
Closed 8 years ago.
What would the easiest way to represent the following equation be?
Just to clarify, my question is asking for some code that calculates the answer to the equation.
There are two problems with this:
The summation warrants an infinite loop which is impossible to get an answer from
I hoping for a long, detailed answer (maybe to 40 digits or so).
If you need more precision, you could try to use Fraction:
from fractions import Fraction # use rational numbers, they are more precise than floats
e = Fraction(0)
f = Fraction(1)
n = Fraction(1)
while True:
d = Fraction(1) / f # this ...
if d < Fraction(1, 10**40): # don't continue if the advancement is too small
break
e += d # ... and this are the formula you wrote for "e"
f *= n # calculate factorial incrementally, faster than calling "factorial()" all the time
n += Fraction(1) # we will use this for calculating the next factorial
print(float(e))
or Decimal:
from decimal import Decimal, getcontext
getcontext().prec = 40 # set the precision to 40 places
e = Decimal(0)
f = Decimal(1)
n = Decimal(1)
while True:
olde = e
e += Decimal(1) / f
if e == olde: # if there was no change in the 40 places, stop.
break
f *= n
n += Decimal(1)
print(float(e))
So here is e in 1000 places:
2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427427466391932003059921817413596629043572900334295260595630738132328627943490763233829880753195251019011573834187930702154089149934884167509244761460668082264800168477411853742345442437107539077744992069551702761838606261331384583000752044933826560297606737113200709328709127443747047230696977209310141692836819025515108657463772111252389784425056953696770785449969967946864454905987931636889230098793127736178215424999229576351482208269895193668033182528869398496465105820939239829488793320362509443117301238197068416140397019837679320683282376464804295311802328782509819455815301756717361332069811250996181881593041690351598888519345807273866738589422879228499892086805825749279610484198444363463244968487560233624827041978623209002160990235304369941849146314093431738143640546253152096183690888707016768396424378140592714563549061303107208510383750510115747704171898610687396965521267154688957035044
To see more clearly what it does, here is its simplified version:
e = f = 1.0
for i in range(2, 16):
e += 1.0 / f
f *= i
print(e)
The obvious solution would be
import math
def e(n=10):
return sum(1 / float(math.factorial(i)) for i in range(n))
but it loses precision around n=20 (the error as compared to math.e is around 10^-16)
40-digits precision might be a challenge, and might require arbitrary precision arithmetic
I do not really see the point to have such precise "e" value since you won't be able to perform any calculations with such precision (if you do anything to it, you will lose that precision, unless you do everything in some arbitrary precision arithmetic).
To produce a similar result to my answer from a question on approximating pi:
from functools import wraps
def memoize(f):
"""Store and retrive previous results of the decorated function f."""
cache = {}
#wraps(f)
def func(*args):
if args not in cache:
cache[args] = f(*args)
return cache[args]
return func
#memoize
def fact(n):
"""Recursively calculates n!."""
if n <= 1:
return 1
return n * fact(n - 1)
def inverse_fact_n(start_n=0):
"""Generator producing the infinite series 1/n!."""
numerator = 1.0
denominator = start_n
while True:
yield numerator / fact(denominator)
denominator += 1
def approximate_e(steps=None, tolerance=None):
"""Calculate an approximation of e from summation of 1/n!."""
if steps is None and tolerance is None:
raise ValueError("Must supply one of steps or tolerance.")
series = inverse_fact_n()
if steps is not None: # stepwise method
return sum(next(series) for _ in range(steps))
output = 0 # tolerance method
term = next(series)
while abs(term) > tolerance:
output += term
term = next(series)
return output
if __name__ == "__main__":
from math import e
print("math.e:\t\t{0:.20f}.".format(e))
stepwise = approximate_e(steps=100)
print("Stepwise:\t{0:.20f}.".format(stepwise))
tolerated = approximate_e(tolerance=0.0000000001)
print("Tolerated:\t{0:.20f}.".format(tolerated))
The function approximate_e allows you to specify either:
A number of steps ("I want it to take this long"); or
A desired tolerance ("I want it to be this accurate").
There is some relatively advanced Python around this (e.g. the memoizing decorator function and the generator function to produce the series), but you can just focus on the main function, where next(series) gives you the next term of the summation.
This gives me the output:
math.e: 2.71828182845904509080.
Stepwise: 2.71828182845904553488.
Tolerated: 2.71828182844675936281.
The most effective way is to use the properties of the exponential function.
exp(x)=(exp(x/N))^N
Thus you compute x=exp(2^(-n)) with 2n bits more precision than required in the final result, and compute e by squaring the result n times.
For small numbers x, the error of truncating the series for exp(x) at the term with power m-1 is smaller than two times the next term with power m.
To summarize, to compute e with a precision/accuracy of d bit, you select some medium large n and select m such that
2^(1-mn)/m! is smaller than 2^(-d-2n)
This determination of m can also be done dynamically (using Decimal as in the answer of user22698)
from decimal import Decimal, getcontext
def eulernumber(d):
dd=d
n=4
while dd > 1:
dd /= 8
n += 1
getcontext().prec = d+n
x = Decimal(1)/Decimal(1 << n)
eps = Decimal(1)/Decimal(1 << (1 + (10*d)/3 ))
term = x
expsum = Decimal(1) + x
m = 2
while term > eps:
term *= x / Decimal(m)
m += 1
expsum += term
for k in range(n):
expsum *= expsum
getcontext().prec = d
expsum += Decimal(0)
return expsum
if __name__ == "__main__":
for k in range(1,6):
print(k,eulernumber(4*k))
for k in range(10,13):
print(k,eulernumber(4*k))
with output
( 1, Decimal('2.718'))
( 2, Decimal('2.7182818'))
( 3, Decimal('2.71828182846'))
( 4, Decimal('2.718281828459045'))
( 5, Decimal('2.7182818284590452354'))
(10, Decimal('2.718281828459045235360287471352662497757'))
(11, Decimal('2.7182818284590452353602874713526624977572471'))
(12, Decimal('2.71828182845904523536028747135266249775724709370'))
See the (unix/posix) bc math library for a more professional implementation of this idea, also for the logarithm and trig functions. The code of the exponential function is even given as example in the man page.

Checking if float is equivalent to an integer value in python

In Python 3, I am checking whether a given value is triangular, that is, it can be represented as n * (n + 1) / 2 for some positive integer n.
Can I just write:
import math
def is_triangular1(x):
num = (1 / 2) * (math.sqrt(8 * x + 1) - 1)
return int(num) == num
Or do I need to do check within a tolerance instead?
epsilon = 0.000000000001
def is_triangular2(x):
num = (1 / 2) * (math.sqrt(8 * x + 1) - 1)
return abs(int(num) - num) < epsilon
I checked that both of the functions return same results for x up to 1,000,000. But I am not sure if generally speaking int(x) == x will always correctly determine whether a number is integer, because of the cases when for example 5 is represented as 4.99999999999997 etc.
As far as I know, the second way is the correct one if I do it in C, but I am not sure about Python 3.
There is is_integer function in python float type:
>>> float(1.0).is_integer()
True
>>> float(1.001).is_integer()
False
>>>
Both your implementations have problems. It actually can happen that you end up with something like 4.999999999999997, so using int() is not an option.
I'd go for a completely different approach: First assume that your number is triangular, and compute what n would be in that case. In that first step, you can round generously, since it's only necessary to get the result right if the number actually is triangular. Next, compute n * (n + 1) / 2 for this n, and compare the result to x. Now, you are comparing two integers, so there are no inaccuracies left.
The computation of n can be simplified by expanding
(1/2) * (math.sqrt(8*x+1)-1) = math.sqrt(2 * x + 0.25) - 0.5
and utilizing that
round(y - 0.5) = int(y)
for positive y.
def is_triangular(x):
n = int(math.sqrt(2 * x))
return x == n * (n + 1) / 2
You'll want to do the latter. In Programming in Python 3 the following example is given as the most accurate way to compare
def equal_float(a, b):
#return abs(a - b) <= sys.float_info.epsilon
return abs(a - b) <= chosen_value #see edit below for more info
Also, since epsilon is the "smallest difference the machine can distinguish between two floating-point numbers", you'll want to use <= in your function.
Edit: After reading the comments below I have looked back at the book and it specifically says "Here is a simple function for comparing floats for equality to the limit of the machines accuracy". I believe this was just an example for comparing floats to extreme precision but the fact that error is introduced with many float calculations this should rarely if ever be used. I characterized it as the "most accurate" way to compare in my answer, which in some sense is true, but rarely what is intended when comparing floats or integers to floats. Choosing a value (ex: 0.00000000001) based on the "problem domain" of the function instead of using sys.float_info.epsilon is the correct approach.
Thanks to S.Lott and Sven Marnach for their corrections, and I apologize if I led anyone down the wrong path.
Python does have a Decimal class (in the decimal module), which you could use to avoid the imprecision of floats.
floats can exactly represent all integers in their range - floating-point equality is only tricky if you care about the bit after the point. So, as long as all of the calculations in your formula return whole numbers for the cases you're interested in, int(num) == num is perfectly safe.
So, we need to prove that for any triangular number, every piece of maths you do can be done with integer arithmetic (and anything coming out as a non-integer must imply that x is not triangular):
To start with, we can assume that x must be an integer - this is required in the definition of 'triangular number'.
This being the case, 8*x + 1 will also be an integer, since the integers are closed under + and * .
math.sqrt() returns float; but if x is triangular, then the square root will be a whole number - ie, again exactly represented.
So, for all x that should return true in your functions, int(num) == num will be true, and so your istriangular1 will always work. The only sticking point, as mentioned in the comments to the question, is that Python 2 by default does integer division in the same way as C - int/int => int, truncating if the result can't be represented exactly as an int. So, 1/2 == 0. This is fixed in Python 3, or by having the line
from __future__ import division
near the top of your code.
I think the module decimal is what you need
You can round your number to e.g. 14 decimal places or less:
>>> round(4.999999999999997, 14)
5.0
PS: double precision is about 15 decimal places
It is hard to argue with standards.
In C99 and POSIX, the standard for rounding a float to an int is defined by nearbyint() The important concept is the direction of rounding and the locale specific rounding convention.
Assuming the convention is common rounding, this is the same as the C99 convention in Python:
#!/usr/bin/python
import math
infinity = math.ldexp(1.0, 1023) * 2
def nearbyint(x):
"""returns the nearest int as the C99 standard would"""
# handle NaN
if x!=x:
return x
if x >= infinity:
return infinity
if x <= -infinity:
return -infinity
if x==0.0:
return x
return math.floor(x + 0.5)
If you want more control over rounding, consider using the Decimal module and choose the rounding convention you wish to employ. You may want to use Banker's Rounding for example.
Once you have decided on the convention, round to an int and compare to the other int.
Consider using NumPy, they take care of everything under the hood.
import numpy as np
result_bool = np.isclose(float1, float2)
Python has unlimited integer precision, but only 53 bits of float precision. When you square a number, you double the number of bits it requires. This means that the ULP of the original number is (approximately) twice the ULP of the square root.
You start running into issues with numbers around 50 bits or so, because the difference between the fractional representation of an irrational root and the nearest integer can be smaller than the ULP. Even in this case, checking if you are within tolerance will do more harm than good (by increasing the number of false positives).
For example:
>>> x = (1 << 26) - 1
>>> (math.sqrt(x**2)).is_integer()
True
>>> (math.sqrt(x**2 + 1)).is_integer()
False
>>> (math.sqrt(x**2 - 1)).is_integer()
False
>>> y = (1 << 27) - 1
>>> (math.sqrt(y**2)).is_integer()
True
>>> (math.sqrt(y**2 + 1)).is_integer()
True
>>> (math.sqrt(y**2 - 1)).is_integer()
True
>>> (math.sqrt(y**2 + 2)).is_integer()
False
>>> (math.sqrt(y**2 - 2)).is_integer()
True
>>> (math.sqrt(y**2 - 3)).is_integer()
False
You can therefore rework the formulation of your problem slightly. If an integer x is a triangular number, there exists an integer n such that x = n * (n + 1) // 2. The resulting quadratic is n**2 + n - 2 * x = 0. All you need to know is if the discriminant 1 + 8 * x is a perfect square. You can compute the integer square root of an integer using math.isqrt starting with python 3.8. Prior to that, you could use one of the algorithms from Wikipedia, implemented on SO here.
You can therefore stay entirely in python's infinite-precision integer domain with the following one-liner:
def is_triangular(x):
return math.isqrt(k := 8 * x + 1)**2 == k
Now you can do something like this:
>>> x = 58686775177009424410876674976531835606028390913650409380075
>>> math.isqrt(k := 8 * x + 1)**2 == k
True
>>> math.isqrt(k := 8 * (x + 1) + 1)**2 == k
False
>>> math.sqrt(k := 8 * x + 1)**2 == k
False
The first result is correct: x in this example is a triangular number computed with n = 342598234604352345342958762349.
Python still uses the same floating point representation and operations C does, so the second one is the correct way.
Under the hood, Python's float type is a C double.
The most robust way would be to get the nearest integer to num, then test if that integers satisfies the property you're after:
import math
def is_triangular1(x):
num = (1/2) * (math.sqrt(8*x+1)-1 )
inum = int(round(num))
return inum*(inum+1) == 2*x # This line uses only integer arithmetic

Mathematica to Python

How can this Mathematica code be ported to Python? I do not know the Mathematica syntax and am having a hard time understanding how this is described in a more traditional language.
Source (pg 5): http://subjoin.net/misc/m496pres1.nb.pdf
This cannot be ported to Python directly as the definition a[j] uses the Symbolic Arithmetic feature of Mathematica.
a[j] is basically the coefficient of xj in the series expansion of that rational function inside Apart.
Assume you have a[j], then f[n] is easy. A Block in Mathematica basically introduces a scope for variables. The first list initializes the variable, and the rest is the execution of the code. So
from __future__ import division
def f(n):
v = n // 5
q = v // 20
r = v % 20
return sum(binomial(q+5-j, 5) * a[r+20*j] for j in range(5))
(binomial is the Binomial coefficient.)
Using the proposed solutions from the previous answers I found that sympy sadly doesn't compute the apart() of the rational immediatly. It somehow gets confused. Moreover, the python list of coefficients returned by *Poly.all_coeffs()* has a different semantics than a Mathmatica list. Hence the try-except-clause in the definition of a().
The following code does work and the output, for some tested values, concurs with the answers given by the Mathematica formula in Mathematica 7:
from __future__ import division
from sympy import expand, Poly, binomial, apart
from sympy.abc import x
A = Poly(apart(expand(((1-x**20)**5)) / expand((((1-x)**2)*(1-x**2)*(1-x**5)*(1-x**10))))).all_coeffs()
def a(n):
try:
return A[n]
except IndexError:
return 0
def f(n):
v = n // 5
q = v // 20
r = v % 20
return sum(a[r+20*j]* binomial(q+5-j, 5) for j in range(5))
print map(f, [100, 50, 1000, 150])
The symbolics can be done with sympy. Combined with KennyTM's answer, something like this might be what you want:
from __future__ import division
from sympy import Symbol, apart, binomial
x = Symbol('x')
poly = (1-x**20)**5 / ((1-x)**2 * (1-x**2) * (1-x**5) * (1-x**10))
poly2 = apart(poly,x)
def a(j):
return poly2.coeff(x**j)
def f(n):
v = n // 5
q = v // 20
r = v % 20
return sum(binomial(q+5-j, 5)*a(r+20*j) for j in range(5))
Although I have to admit that f(n) does not work (I'm not very good at Python).

Categories

Resources