amaranth/amaranth/utils.py
Wanda 7f76914b74 Implement RFC 17: Remove log2_int.
Reexports of `amaranth.utils` functions are removed from
`amaranth._utils` to avoid a circular import issue (for `deprecated`).
Since this is a private module, this should not be a problem.
2024-01-11 04:45:17 +00:00

51 lines
1.3 KiB
Python

import operator
from ._utils import deprecated
__all__ = ["ceil_log2", "exact_log2", "log2_int", "bits_for"]
def ceil_log2(n):
"""Returns the integer log2 of the smallest power-of-2 greater than or equal to `n`.
Raises a `ValueError` for negative inputs."""
n = operator.index(n)
if n < 0:
raise ValueError("{n} is negative")
if n == 0:
return 0
return (n - 1).bit_length()
def exact_log2(n):
"""Returns the integer log2 of `n`, which must be an exact power of two.
Raises a `ValueError` if `n` is not a power of two."""
n = operator.index(n)
if n <= 0 or (n & (n - 1)):
raise ValueError("{n} is not a power of 2")
return (n - 1).bit_length()
@deprecated("instead of `log2_int(n, True)`, use `exact_log2(n)`; instead of `log2_int(n, False)` use `ceil_log2(n)`")
def log2_int(n, need_pow2=True):
n = operator.index(n)
if n == 0:
return 0
r = (n - 1).bit_length()
if need_pow2 and (1 << r) != n:
raise ValueError(f"{n} is not a power of 2")
return r
def bits_for(n, require_sign_bit=False):
n = operator.index(n)
if n > 0:
r = ceil_log2(n + 1)
else:
require_sign_bit = True
r = ceil_log2(-n)
if require_sign_bit:
r += 1
return r