Floating point precision in Python - python

I have written this function in python:
import math
def radical(a, b, k):
return (1-((a**2-b**2)/a**2)*(math.sin(math.pi*(2*k-1)/180))**2)**.5
def f(a, b):
sigma = 0
for k in range(1,180/4):
sigma = sigma + radical(a, b, k)
return 8*a*math.sin(math.pi/180)*sigma
print f(25.,35.)
When I calculate this function in Wolphramapha and Maple I will get 189.797 but with python I will get 184.91089913
What is the problem in my program?

You are off by one. The range method excludes the end point. Try adding one:
for k in range(1,180/4 + 1):
Result: 189.797208409

Well, first of all, python assumes integer division, so there is some serious round off in this code. I believe there is an import in division for this. Also, Here is some information on python's floating point arithmetic issues/problems:
http://docs.python.org/2/tutorial/floatingpoint.html

Related

What is the best practice to avoid precision error while taking floor on math.log?

Recently we encountered an issue with math.log() . Since 243 is a perfect power of 3 , assumption that taking floor should be fine was wrong as it seems to have precision error on lower side.
So as a hack we started adding a small value before taking logarithm. Is there a way to configue math.log upfront or something similar that that we dont have to add EPS every time.
To clarify some of the comments Note we are not looking to round to nearest integer. Our goal is to keep the value exact or at times take floor. But if the precision error is on lower side floor screws up big time, that's what we are trying to avoid.
code:
import math
math.log(243, 3)
int(math.log(243, 3))
output:
4.999999999999999
4
code:
import math
EPS = 1e-09
math.log(243 + EPS, 3)
int(math.log(243 + EPS, 3))
output:
5.0000000000037454
5
Instead of trying to solve it might be easier to look at and just solve this iteratively, taking advantage of Python's integer type. This way you can avoid the float domain, and its associated precision loss, entirely.
Here's a rough attempt:
def ilog(a: int, p: int) -> tuple[int, bool]:
"""
find the largest b such that p ** b <= a
return tuple of (b, exact)
"""
if p == 1:
return a, True
b = 0
x = 1
while x < a:
x *= p
b += 1
if x == a:
return b, True
else:
return b - 1, False
There are plenty of opportunities for optimization if this is too slow (consider Newton's method, binary search...)
How about this? Is this what you are looking for?
import math
def ilog(a: int, p:int) -> int:
"""
find the largest b such that p ** b <= a
"""
float_log = math.log(a, p)
if (candidate := math.ceil(float_log))**p <= a:
return candidate
return int(float_log)
print(ilog(243, 3))
print(ilog(3**31, 3))
print(ilog(8,2))
Output:
5
31
3
You can use decimals and play with precision and rounding instead of floats in this case
Like this:
from decimal import Decimal, Context, ROUND_HALF_UP, ROUND_HALF_DOWN
ctx1 = Context(prec=20, rounding=ROUND_HALF_UP)
ctx2 = Context(prec=20, rounding=ROUND_HALF_DOWN)
ctx1.divide(Decimal(243).ln( ctx1) , Decimal(3).ln( ctx2))
Output:
Decimal('5')
First, the rounding works like the epsilon - the numerator is rounded up and denominator down. You always get a slightly higher answer
Second, you can adjust precision you need
However, fundamentally the problem is unsolvable.

last digit is off by 1 regardless of math methods used

Having a minor issue with the return value of this function for large parameters (works fine for smaller ones). Here is the code:
def pyramid_blocks(n, m, h):
return int(h*n*m + (h*h-h)*(3*n+3*m+2*h-1)/6)
Here is the test case where it fails:
ARGUMENTS: 2123377, 2026271, 2437
EXPECTED: 10497605327499753
RETURNED: 10497605327499754
I know the formula is correct (subtracting 1 will make it incorrect), but the last digit keeps rounding up. Smells like a integer arithmetic bit issue. Tried using math.ceil and still no luck.
Integers are exact in Python. You can use integer division with a double slash: //:
def pyramid_blocks(n, m, h):
return int(h*n*m + (h*h-h)*(3*n+3*m+2*h-1)//6)
This now returns 10497605327499753
Your problem is your division by 6, which is using the floating point / operator. You want to use the integer division operator //.
>>> n = 2123377
>>> m = 2026271
>>> h = 2437
>>> n*m*h + (h*h-h)*(3*n+3*m+2*h-1)//6
10497605327499753
You probably meant to use integer division:
def pyramid_blocks(n, m, h):
return int(h*n*m + (h*h-h)*(3*n+3*m+2*h-1)//6)
The first answer solves the problem, but in case you're wondering why this is happening:
from decimal import *
def pyramid_blocks(n, m, h):
n = Decimal(n)
m = Decimal(m)
h = Decimal(h)
return int(h*n*m + (h*h-h)*(3*n+3*m+2*h-1)/6)
pyramid_blocks(2123377,2026271,2437)
Output
10497605327499753
Floor division(//) will solve your problem. This just simply removes the numbers after the decimal.
Eg:
>>>20/3
>>>6.666666
>>>20//3
>>>6
Updated code:
def pyramid_blocks(n, m, h):
return int(h*n*m + (h*h-h)*(3*n+3*m+2*h-1)//6)
pyramid_blocks(2123377,2026271,2437)
Output(for given arguements):
10497605327499753
There are already multiple answers how to fix your problem, but no one has yet to answered why this happens. It is not integer arithmetic, it is floating point arithmetic!
10497605327499753 in binary is a number with 54 binary digits. If we ignore the leading 1 (which is not actually represented in memory) that leaves 53 digits - one more than the mantissa (or significand) of an IEEE 754 double allows!

Python innacuracies with large numbers?

I have to write a function that uses another function, but the other function has to return integers which get fairly innacurate with large numbers.
My code:
import math
def reduce(n, d):
m = min(n, d)
for i in range(m, 1, -1):
if n%i==0 and d%i==0:
n = n//i
d = d//i
return (n, d)
def almost_square(n, d):
f = n/d
c = math.ceil(f)
n*=c
return reduce(n, d)
def destiny(n, d):
b = n/d
fraction = n, d
while not b.is_integer():
breuk = almost_square(fraction[0], fraction[1])
b = fraction[0]/fraction[1]
return int(b)
What the functions are supposed to do:
reduce: just simplifying the fraction, so 2/4 becomes 1/2 for example
almost_square: multiplying the fraction with the rounded up integer of the fraction
destiny: applying almost square on a fraction until it returns an integer.
The thing is, my uni works with a program that tries 50 test cases for each function and you only completed the exercise when every function works for all 50 test cases, and they expect the function 'reduce' to return a tuple of integers, but making integers of the numbers there makes my function 'destiny' innacurate, or at least I think so.
So out of the 50 test cases, all 50 work on the function reduce, all 50 work on the function almost_square, but 5 fail for the function destiny which are:
destiny(10, 6), my output: 1484710602474311424, expected output: 1484710602474311520
destiny(17, 13), my output: 59832260230817688435680083968, expected output: 59832260230817687634146563200
destiny(10, 3), my output: 1484710602474311424, expected output: 1484710602474311520
destiny(15, 9), my output: 1484710602474311424, expected output: 1484710602474311520
destiny(11, 5), my output: 494764640798827343035498496, expected output: 494764640798827359861461484
Anything that could fix this?
There is some floating point arithmetic in that code, which can slightly throw off the results, and apparently it did. Forget about float, don't use any "floats, but larger" libraries either, integer arithmetic is the way to go.
For example,
f = n/d
c = math.ceil(f)
n*=c
This code looks like it computes n * ⌈n / d⌉, but it only approximately computes that because it uses floating point arithmetic, requiring values to be rounded to the nearest float (for example, int(float(1484710602474311520)) is 1484710602474311424). It should be implemented using integer arithmetic, for example like this:
n *= (n + d - 1) // d
The destiny function should not use floating point division either, and it does not need to. The "is b an integer" test can be stated equivalently as "does d divide n", which can be implemented with integer arithmetic.
Also for that reduce function you can use math.gcd, or implement gcd yourself, the implementation that you have now is very slow.
With those changes, I get the right results for the test cases that you mentioned. I could show the code, but since it is an assignment, you should probably write the code yourself. Asking this question at all is already risky.
Integers don't get inaccurate with large numbers. Floating point numbers do. And you are using floating point numbers.
Rewrite your algorithm to only use integers.

Speed up a for loop [duplicate]

Does anyone know how to write a program in Python that will calculate the addition of the harmonic series. i.e. 1 + 1/2 +1/3 +1/4...
#Kiv's answer is correct but it is slow for large n if you don't need an infinite precision. It is better to use an asymptotic formula in this case:
#!/usr/bin/env python
from math import log
def H(n):
"""Returns an approximate value of n-th harmonic number.
http://en.wikipedia.org/wiki/Harmonic_number
"""
# Euler-Mascheroni constant
gamma = 0.57721566490153286060651209008240243104215933593992
return gamma + log(n) + 0.5/n - 1./(12*n**2) + 1./(120*n**4)
#Kiv's answer for Python 2.6:
from fractions import Fraction
harmonic_number = lambda n: sum(Fraction(1, d) for d in xrange(1, n+1))
Example:
>>> N = 100
>>> h_exact = harmonic_number(N)
>>> h = H(N)
>>> rel_err = (abs(h - h_exact) / h_exact)
>>> print n, "%r" % h, "%.2g" % rel_err
100 5.1873775176396242 6.8e-16
At N = 100 relative error is less then 1e-15.
#recursive's solution is correct for a floating point approximation. If you prefer, you can get the exact answer in Python 3.0 using the fractions module:
>>> from fractions import Fraction
>>> def calc_harmonic(n):
... return sum(Fraction(1, d) for d in range(1, n + 1))
...
>>> calc_harmonic(20) # sum of the first 20 terms
Fraction(55835135, 15519504)
Note that the number of digits grows quickly so this will require a lot of memory for large n. You could also use a generator to look at the series of partial sums if you wanted to get really fancy.
Just a footnote on the other answers that used floating point; starting with the largest divisor and iterating downward (toward the reciprocals with largest value) will put off accumulated round-off error as much as possible.
A fast, accurate, smooth, complex-valued version of the H function can be calculated using the digamma function as explained here. The Euler-Mascheroni (gamma) constant and the digamma function are available in the numpy and scipy libraries, respectively.
from numpy import euler_gamma
from scipy.special import digamma
def digamma_H(s):
""" If s is complex the result becomes complex. """
return digamma(s + 1) + euler_gamma
from fractions import Fraction
def Kiv_H(n):
return sum(Fraction(1, d) for d in xrange(1, n + 1))
def J_F_Sebastian_H(n):
return euler_gamma + log(n) + 0.5/n - 1./(12*n**2) + 1./(120*n**4)
Here's a comparison of the three methods for speed and precision (with Kiv_H for reference):
Kiv_H(x) J_F_Sebastian_H(x) digamma_H(x)
x seconds bits seconds bits seconds bits
1 5.06e-05 exact 2.47e-06 8.8 1.16e-05 exact
10 4.45e-04 exact 3.25e-06 29.5 1.17e-05 52.6
100 7.64e-03 exact 3.65e-06 50.4 1.17e-05 exact
1000 7.62e-01 exact 5.92e-06 52.9 1.19e-05 exact
The harmonic series diverges, i.e. its sum is infinity..
edit: Unless you want partial sums, but you weren't really clear about that.
This ought to do the trick.
def calc_harmonic(n):
return sum(1.0/d for d in range(2,n+1))
How about this:
partialsum = 0
for i in xrange(1,1000000):
partialsum += 1.0 / i
print partialsum
where 1000000 is the upper bound.
Homework?
It's a divergent series, so it's impossible to sum it for all terms.
I don't know Python, but I know how to write it in Java.
public class Harmonic
{
private static final int DEFAULT_NUM_TERMS = 10;
public static void main(String[] args)
{
int numTerms = ((args.length > 0) ? Integer.parseInt(args[0]) : DEFAULT_NUM_TERMS);
System.out.println("sum of " + numTerms + " terms=" + sum(numTerms));
}
public static double sum(int numTerms)
{
double sum = 0.0;
if (numTerms > 0)
{
for (int k = 1; k <= numTerms; ++k)
{
sum += 1.0/k;
}
}
return sum;
}
}
Using the simple for loop
def harmonicNumber(n):
x=0
for i in range (0,n):
x=x+ 1/(i+1)
return x
I add another solution, this time using recursion, to find the n-th Harmonic number.
General implementation details
Function Prototype: harmonic_recursive(n)
Function Parameters: n - the n-th Harmonic number
Base case: If n equals 1 return 1.
Recur step: If not the base case, call harmonic_recursive for the n-1 term and add that result with 1/n. This way we add each time the i-th term of the Harmonic series with the sum of all the previous terms until that point.
Pseudocode
(this solution can be implemented easily in other languages too.)
harmonic_recursive(n):
if n == 1:
return 1
else:
return 1/n + harmonic_recursive(n-1)
Python code
def harmonic_recursive(n):
if n == 1:
return 1
else:
return 1.0/n + harmonic_recursive(n-1)
By using the numpy module, you can also alternatively use:
import numpy as np
def HN(n):
return sum(1/arange(1,n+1))

distance formula in python bug

I'm calculating the length of a line segment in python, but I don't understand why one piece of code gives me zero and the other gives the right answer.
This piece of code gives me zero:
def distance(a, b):
y = b[1]-a[1]
x = b[0]-a[0]
ans=y^2+x^2
return ans^(1/2)
This one gives me the right answer:
import math as math
def distance(a, b):
y = b[1]-a[1]
x = b[0]-a[0]
ans=y*y+x*x
return math.sqrt(ans)
Thank you.
In your first snippet you have written this:
ans^(1/2)
In Python the power operator is not ^, that's the XOR-operator. The power operator in Python is **. On top of that, in Python 2.x by default the result of the division of two integers is an integer, so 1/2 will evaluate as 0. The correct way would be this:
ans ** 0.5
And another thing, the function you have implemented here can be done a lot easier with math.hypot:
import math
def distance(a, b):
return math.hypot(b[0] - a[0], b[1] - a[1])
Try doing x**2 rather than x^2 ( which is XOR)
Or use the math.pow function
And also, 1/2 is 0 and not 0.5

Categories