Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the best practice to avoid precision error while taking floor on math.log?

Recently we encountered an issue with math.log() . Since 243 is a perfect power of 3 , assumption that taking floor should be fine was wrong as it seems to have precision error on lower side. So as a hack we started adding a small value before taking logarithm. Is there a way to configue math.log upfront or something similar that that we dont have to add EPS every time.

To clarify some of the comments Note we are not looking to round to nearest integer. Our goal is to keep the value exact or at times take floor. But if the precision error is on lower side floor screws up big time, that's what we are trying to avoid.

code:

import math
math.log(243, 3)
int(math.log(243, 3))

output:

4.999999999999999
4

code:

import math
EPS = 1e-09
math.log(243 + EPS, 3)
int(math.log(243 + EPS, 3))

output:

5.0000000000037454
5
like image 512
ishandutta2007 Avatar asked Oct 18 '25 03:10

ishandutta2007


1 Answers

Instead of trying to solve log it might be easier to look at pow and just solve this iteratively, taking advantage of Python's integer type. This way you can avoid the float domain, and its associated precision loss, entirely.

Here's a rough attempt:

def ilog(a: int, p: int) -> tuple[int, bool]:
    """
    find the largest b such that p ** b <= a
    return tuple of (b, exact)
    """
    if p == 1:
        return a, True
    b = 0
    x = 1
    while x < a:
        x *= p
        b += 1
    if x == a:
        return b, True
    else:
        return b - 1, False

There are plenty of opportunities for optimization if this is too slow (consider Newton's method, binary search...)

like image 106
wim Avatar answered Oct 20 '25 16:10

wim



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!