I would like to find the sum of a list of floats and check if it is a whole number or not:
l = [0.85, 0.85, 0.15, 0.15]
The sum of l
is 2.0, obviously. But Python does not agree, due to floating point limitations :
> sum(l)
1.9999999999999998
Therefore my method of choice, sum(l).is_integer()
, will return False
.
What would be a better method to evaluate if lists sum to a whole number?
You can use the decimal
package.
>>> from decimal import Decimal
>>> l = [Decimal(x) for x in ['0.85', '0.85', '0.15', '0.15']]
>>> s = sum(l)
>>> s
Decimal('2.00')
>>> s == int(s)
True
You can use a combination of math.isclose
and the inbuilt round
function.
>>> from math import isclose
>>> l = [0.85, 0.85, 0.15, 0.15]
>>> s = sum(l)
>>> isclose(s, round(s))
True
When you need exact arithmetic, the best solution is to work with integers only. In this case you could round each of your inputs to 2 or 3 decimal places for the check.
l = [0.85, 0.85, 0.15, 0.15]
number_of_places = 3
multiplier = 10 ** number_of_places
>>> sum(int(round(x*multiplier)) for x in l)
2000
>>> sum(int(round(x*multiplier)) for x in l) % multiplier == 0
True
Apart Decimal, you can also use the fractions module, which will enable handling arbitrary denominators like:
from fractions import Fraction
print(Fraction(1,3) + Fraction(4,7) + Fraction(2,21))
Also works with Fraction('0.85') + Fraction('0.15')
or Fraction('2/6')
.
Note that the result of adding Fractions is a Fraction, eventually with denominator == 1, so instead of testing is_integer()
, you have to replace with a denominator check, or with equality of int conversion:
collection = [Fraction(each) for each in ['0.85', '0.85', '0.15', '0.15']]
sum = sum(collection)
print(sum.denominator == 1)
print(int(sum) == sum)
In some languages including Smalltalk, Fractions are automatically reduced to Integer when denominator is 1, making the code a bit less brittle...
^((1/3) + (4/7) + (2/21)) isInteger
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.