I came across a stackoverflow question about multiplying the numbers in a Python list. Suggestions there included:
def product(list):
p =1
for i in list:
p *= i
return p
and
from operator import mul
reduce(mul, list)
Adding my own $.02, you can also do:
import math
math.exp(sum(map(math.log, list)))
which gets the same numerical results (at least to as way more decimal places than you're ever likely to care about, the difference being due to computational floating point errors). It's probably not as readable as the reduce-based solution, though if you're a mathematician who isn't familiar with reduce(), the opposite would be true!
(The underlying principle is that a * b * c * … * z == e ^ (ln(a) + ln(b) + ln( c) + … + ln(z)).)
I wouldn't necessarily advise using the log-based solution under normal circumstances. But if you're ever in a situation where you risk overflow or overflow, such as in
>>> reduce(mul, [10.] * 309)
inf
and your purpose is to compare the products of different sequences rather than to know specifically what the products are, then, you can accomplish your purposes without actually computing the entire product. Rather, you can compare the sums of the logs of the terms, without bothering to compute the product by taking the exponential. Whichever list has a larger sum-of-logs also has the larger product. So, following up on our previous example,
>>> sum(map(math.log, [10.] * 309))
711.49879373515785
is the way to go because it's virtually impossible to have a real-world problem in which you would overflow or underflow with this approach. (The larger the result of that calculation is, the larger the product would be if you could calculate it.)
Accordingly, if you wanted to compare 10. ^ 309 and 11. ^ 309, you could do
>>> sum(map(math.log, [10.] * 309)) > sum(map(math.log, [11.] * 309))
False
[Originally posted as "Calculating the product of a Python list. Updated for clarity and completeness.]
Comments