This question already has answers here:
Python floating point number comparison
(3 answers)
Closed 5 years ago.
I write below program but My program cannot check the two number is equal or not.
There is no error,
I would be appreciate for any help.
import math
def IsCollinding(ball1,ball2):
distance=math.sqrt((((ball2[0]-ball1[0])**2)+((ball2[1]-ball1[1])**2)))
print(type(distance))
print(type(ball1[2]+ball2[2]))
if(distance==ball1[2]+ball2[2]):
print("Is Coliding")
else:
print("Not Coliding")
print(distance)
print(ball1[2]+ball2[2])
ball1=[2,2,3]
ball2=[11,11,9.7279220614]
IsCollinding(ball1,ball2)
output:
<type 'float'>
<type 'float'>
Not Coliding
12.7279220614
12.7279220614
You can not really do this. Floats may appear equal, but are actually different due to floating point precision. However, you can cheat. We can call two numbers "equal" if the difference between the two is very small.
The function looks like this:
(x - y) < delta
Where delta is a small number. Implemented in Python:
def almost_equal(x, y, delta=1e-10):
return abs(x - y) < delta
I use abs here to get the absolute value of the difference. We avoid having to deal with negative numbers and the order of the x and y arguments this way.
Comparing two floats is one of the most common gotchas, and is something most of us run into at one point. Googling "comparing two floats python" should have returned plenty of informative results about this topic.
Related
This question already has answers here:
Is floating point arbitrary precision available?
(5 answers)
Is floating point math broken?
(31 answers)
Closed 1 year ago.
I am trying to divide floats by each other but am having a hard time getting accurate results. I understand that computers store floats in a way where the value stored is not exact to the given number. I am simply looking for a way where I can get specific results when working with floats.
input:
x = 2.4
y = 0.2
print(x/y)
Output:
11.999999998
I highly recommend to use decimals
Example
from decimal import Decimal
x = Decimal("2.4")
y = Decimal("0.2")
print(x / y) # 12
Notice we passing number as string, as passing float numbers would have the same problem you pointed out.
But care with comparison, as 12 == x / y evaluates to False
This question already has answers here:
Is floating point math broken?
(31 answers)
Closed 2 years ago.
Maybe this was answered before, but I'm trying to understand what is the best way to work with Pandas subtraction.
import pandas as pd
import random
import numpy as np
random.seed(42)
data = {'r': list([float(random.random()) for i in range(5)])}
for i in range(5):
data['r'].append(float(0.7))
df = pd.DataFrame(data)
If I run the following, I get the expected results:
print(np.sum(df['r'] >= 0.7))
6
However, if I modify slightly the condition, I don't get the expected results:
print(np.sum(df['r']-0.5 >= 0.2))
1
The same happens if I try to fix it by casting into float or np.float64 (and combinations of this), like the following:
print(np.sum(df['r'].astype(np.float64)-np.float64(0.5) >= np.float64(0.2)))
1
For sure I'm not doing the casting properly, but any help on this would be more than welcome!
You're not doing anything improperly. This is a totally straightforward floating point error. It will always happen.
>>> 0.7 >= 0.7
True
>>> (0.7 - 0.5) >= 0.2
False
You have to remember that floating point numbers are represented in binary, so they can only represent sums of powers of 2 with perfect precision. Anything that can't be represented finitely as a sum of powers of two will be subject to error like this.
You can see why by forcing Python to display the full-precision value associated with the literal 0.7:
format(0.7, '.60g')
'0.6999999999999999555910790149937383830547332763671875'
To add to #senderle answer, since this is a floating point issue you can solve it by:
((df['r'] - 0.5) >= 0.19).sum()
Oh a slightly different note, I'm not sure why you use np.sum when you could just use pandas .sum, seems like an unnecessary import
This question already has answers here:
Why is math.sqrt() incorrect for large numbers?
(4 answers)
Is floating point math broken?
(31 answers)
Closed 5 years ago.
If you take a number, take its square root, drop the decimal, and then raise it to the second power, the result should always be less than or equal to the original number.
This seems to hold true in python until you try it on 99999999999999975425 for some reason.
import math
def check(n):
assert math.pow(math.floor(math.sqrt(n)), 2) <= n
check(99999999999999975424) # No exception.
check(99999999999999975425) # Throws AssertionError.
It looks like math.pow(math.floor(math.sqrt(99999999999999975425)), 2) returns 1e+20.
I assume this has something to do with the way we store values in python... something related to floating point arithmetic, but I can't reason about specifically how that affects this case.
The problem is not really about sqrt or pow, the problem is you're using numbers larger than floating point can represent precisely. Standard IEEE 64 bit floating point arithmetic can't represent every integer value beyond 52 bits (plus one sign bit).
Try just converting your inputs to float and back again:
>>> int(float(99999999999999975424))
99999999999999967232
>>> int(float(99999999999999975425))
99999999999999983616
As you can see, the representable value skipped by 16384. The first step in math.sqrt is converting to float (C double), and at that moment, your value increased by enough to ruin the end result.
Short version: float can't represent large integers precisely. Use decimal if you need greater precision. Or if you don't care about the fractional component, as of 3.8, you can use math.isqrt, which works entirely in integer space (so you never experience precision loss, only the round down loss you expect), giving you the guarantee you're looking for, that the result is "the greatest integer a such that a² ≤ n".
Unlike Evan Rose's (now-deleted) answer claims, this is not due to an epsilon value in the sqrt algorithm.
Most math module functions cast their inputs to float, and math.sqrt is one of them.
99999999999999975425 cannot be represented as a float. For this input, the cast produces a float with exact numeric value 99999999999999983616, which repr shows as 9.999999999999998e+19:
>>> float(99999999999999975425)
9.999999999999998e+19
>>> int(_)
99999999999999983616L
The closest float to the square root of this number is 10000000000.0, and that's what math.sqrt returns.
This question already has answers here:
How can I force division to be floating point? Division keeps rounding down to 0?
(11 answers)
Closed 6 years ago.
I am trying to do the calculation
Using the python decimal module with the following code:
from decimal import *
getcontext().prec = 9
sum = Decimal(0)
for i in range(1,11):
sum += Decimal(1/(i**4))
print sum
however, this outputs 1, not a very small fraction like I would expect. I can't find much information here https://docs.python.org/2/library/decimal.html about what is wrong with the code. My guess is sum is not being used as a Decimal in the loop, but I am unsure how to resolve that.
If you use Python 2.x, then in the expression: 1/(i**4), the integer devision is used, as result for i=1, it equals to 1 and for all other i>1, it gets 0.
Just add floating point to 1: 1./(i**4), this should fix the problem.
PS In Python 3.x, your code should work as expected, because operator / is defined on floating point numbers, while operator // is defined for integers.
First of all, don't use sum as a variable name, as it is a built-in.
And its sort of necessary to provide at least one float for arithmetic if you expect a float-type answer, here:
s = Decimal(0)
for i in range(1,11):
s += Decimal(1./(i**4)) # dividing 1. or 1.0 instead of just 1
print s
this gives:
1.08203658
This question already has answers here:
approximate comparison in python
(3 answers)
Closed 8 years ago.
I just recently ran into a problem where I needed to append numbers to a list only if they weren't in the list already, and then I had to run those numbers through a comparison later on. The problem arises in floating point arithmetic errors. To illustrate what is basically happening in my code:
_list = [5.333333333333333, 6.666666666666667, ...]
number = some_calculation()
if number not in _list:
_list.append(number) #note that I can't use a set to remove
#duplicates because order needs to be maintained
new_list = []
for num in _list:
if some_comparison(num): #note that I can't combine 'some_comparison' with the
new_list.append(num) #above check to see if the item is already in the list
The problem is that some_calculation() would sometimes generate an inexact number, such as 5.333333333333332, which is, as far as my calculations need to go, the same as the first element in _list in this example. The solution I had in mind was to simply round all the numbers generated to 9 or so decimal places. This worked for a short amount of time, until I realized that some_comparison compares num against, again, an inexact calculation. Even if I didn't round the numbers in _list, some_comparison would still return an inexact value and thus would evaluate to False.
I am absolutely puzzled. I've never had to worry about floating point errors so this problem is quite infuriating. Does anyone have any ideas for solutions?
NOTE: I would post the actual code, but it's very convoluted and requires 7 or 8 different functions and classes I made specifically for this purpose, and reposting them here would be a hassle.
Make the comparison something like
if(abs(a-b) <= 1e-6 * (a + b)):
This is standard practice when using floating point. The real value you use (instead of 1e-6) depends on the magnitude of the numbers you use and your definition of "the same".
EDIT I added *(a+b) to give some robustness for values of different magnitudes, and changed the comparison to <= rather than < to cover the case where a==b==0.0.
You can subclass list and add in a tolerance to __contains__:
class ListOFloats(list):
def __contains__(self, f):
# If you want a different tolerance, set it like so:
# l=ListOFloats([seq])
# l.tol=tolerance_you_want
tol=getattr(self, 'tol', 1e-12)
return any(abs(e-f) <= 0.5 * tol * (e + f) for e in self)
_list = ListOFloats([5.333333333333333, 6.666666666666667])
print(5.333333333333333 in _list)
# True
print(6.66666666666666 in _list)
# True
print(6.66666666666 in _list)
# False
Use round on both the values in the list and the comparison values. They won't be exact but they'll be consistent, so a search will return the expected results.