math.frexp

Steven D'Aprano steve at pearwood.info
Fri Jul 15 12:32:26 EDT 2016


On Fri, 15 Jul 2016 09:48 pm, Chris Angelico wrote:

>> py> product_scaled([2.5, 3.5])  # expected 8.75
>> 2.734375
>>
> 
> You're chaining your product twice. (Also your scale, although that
> appears to be correct.) Changing it to "prod = m1 * m2" gives 8.75.

D'oh!

Thanks! I needed some fresh eyes on that, because I have been staring at it
for two days.


> But what do you gain by this? You're still stuffing the result back
> into a float at the end, so all you do is change from getting
> float("inf") to getting OverflowError. How can you make it not
> overflow?

If the result is too big to be represented as a float at the end of the
product, then of course it will overflow. But this can give some protection
against overflow of intermediate values. Consider multiplying:

2.0, 1e200, 1e200, 1e-200, 1e-200, 3.0


Mathematically, the answer should be 6. In principle, by rescaling when
needed to prevent overflow (or underflow), product() should be able to get
something very close to 6, if not exactly 6.

But I'm not actually writing a general product() function. I'm doing this
for geometric mean, so I return the scaling exponent and the mantissa[1]
separately, and then take the nth-root of them individually, before
combining them into the final result. Here's an example from my test suite.
I can take the geometric mean of: 

[2.0**900, 2.0**920, 2.0**960, 2.0**980, 2.0**990]

and get to within a relative error of 1e-14 of the correct answer, 2**950:

py> geometric_mean([2.0**900, 2.0**920, 2.0**960, 2.0**980, 2.0**990])
9.516908214257811e+285
py> 2.0**950
9.516908214257812e+285


Here's one that's exact:

py> geometric_mean([2e300, 4e300, 8e300, 16e300, 32e300])
8e+300






[1] I don't care what it's actually called :-)


-- 
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