The x
on each call is the result of the last call (it's only one of the direct inputs on the very first invocation), so doing 1 / x
each time takes the reciprocal of the previous result. To fix, you need to change the lambda
to only multiply in the reciprocal of the new number, not the accumulated value. You also need to provide an initial neutral value (1
) so that the first value in f
has its reciprocal taken properly (otherwise, it would be the plain value of f[0]
multiplied by the reciprocals of f[1:]
):
# x is accumulated product of reciprocals to date, *DON'T* take reciprocal again
reduce(lambda x, y: x * (1 / y), f, 1)
# ^ multiplicative identity is correct neutral value here
That said, you can simplify a little more; x * (1 / y)
is (roughly, given floating point precision issues) equivalent to x / y
, so you could simplify further to:
reduce(lambda x, y: x / y, f, 1)
or using the operator
module to push all the work to the C layer (only important if f
might be really big):
import operator
reduce(operator.truediv, f, 1)
Either way, this gets the expected result:
>>> (1/2) * (1/3) * (1/4)
0.041666666666666664
>>> reduce(lambda x,y: x * (1 / y), f, 1)
0.041666666666666664
>>> reduce(lambda x,y: x / y, f, 1)
0.041666666666666664
>>> reduce(operator.truediv, f, 1)
0.041666666666666664
As noted in the comments below, computing individual reciprocals and multiplying them all together is slower and more prone to error (especially when all inputs are int
) than just computing the product of all the values in f
, then computing the reciprocal of that product once, at the very end. On Python 3.8+, with math.prod
, this is as simple as:
>>> 1 / math.prod(f)
0.041666666666666664
On older versions of Python, you have to make your own product-computing function, but it's easy to do using reduce
+operator.mul
:
>>> 1 / reduce(operator.mul, f)
0.041666666666666664