math.frexp

Steven D'Aprano steve at pearwood.info
Fri Jul 15 07:39:31 EDT 2016


I'm experimenting with various implementations of product(values). Here's a
naive version that easily suffers from overflow:

from functools import reduce
from operator import mul

def product_naive(values):
    return reduce(mul, values)


py> product_naive([2, 4, 5])
40
py> product_naive([1e200, 1e200, 1e200])
inf


So I started experimenting with math.frexp, but I'm having trouble
understanding what I'm doing wrong here.


Help on built-in function frexp in module math:

frexp(...)
    frexp(x)

    Return the mantissa and exponent of x, as pair (m, e).
    m is a float and e is an int, such that x = m * 2.**e.
    If x is 0, m and e are both 0.  Else 0.5 <= abs(m) < 1.0.



If x and y are both floats, then given:

m1, e1 = math.frexp(x)
m2, e2 = math.frexp(y)

Then x*y = m1*m2 * 2.0**(e1 + e2). We can test that:


py> from math import frexp
py> x = 2.5
py> y = 3.5
py> x*y
8.75
py> m1, e1 = math.frexp(x)
py> m2, e2 = math.frexp(y)
py> m1*m2 * 2.0**(e1 + e2)
8.75


Looks good to me. So let's try a less naive version of product():


def product_scaled(values):
    scale = 0
    prod = 1.0
    for a in values:
        m1, e1 = math.frexp(a)
        m2, e2 = math.frexp(prod)
        scale += (e1 + e2)
        prod *= (m1*m2)
    return (prod * 2.0**scale)


py> product_scaled([2.5, 3.5])  # expected 8.75
2.734375



What am I doing wrong?




-- 
Steven
“Cheer up,” they said, “things could be worse.” So I cheered up, and sure
enough, things got worse.




More information about the Python-list mailing list