- Start Date: 2024-01-08
- RFC PR: amaranth-lang/rfcs#17
- Amaranth Issue: amaranth-lang/amaranth#1025
Remove log2_int
Summary
Replace log2_int with two functions: ceil_log2 and exact_log2.
Motivation
log2_int is a helper function that was copied from Migen in the early days of Amaranth.
It behaves like so:
nmust be an integer, and a power-of-2 unlessneed_pow2isFalse;- if
n == 0, it returns0; - if
n != 0, it returns(n - 1).bit_length().
Differences with math.log2
In practice, log2_int differs from math.log2 in the following ways:
- its implementation is restricted to integers only;
- if
need_pow2is false, the result is rounded up to the nearest integer; - it doesn't raise an exception for
n == 0; - if
need_pow2is false, it doesn't raise an exception forn < 0.
Observations
- 1) is a desirable property; coercing integers into floating-point numbers is fraught with peril, as the latter have limited precision.
- 2) has common use-cases in digital design, such as address decoders.
- 3) and 4) are misleading at best. Despite being advertised as a logarithm,
log2_intdoesn't exclude 0 or negative integers from its domain.
Guide-level explanation
Amaranth provides two log2 functions for integer arithmetic:
ceil_log2(n), wherenis assumed to be any non-negative integerexact_log2(n), wherenis assumed to be an integer power-of-2
For example:
ceil_log2(8) # 3
ceil_log2(5) # 3
ceil_log2(4) # 2
exact_log2(8) # 3
exact_log2(5) # raises a ValueError
exact_log2(4) # 2
Reference-level explanation
Use of the log2_int function is deprecated.
A ceil_log2(n) function is added, that:
- returns the integer log2 of the smallest power-of-2 greater than or equal to
n; - raises a
TypeErrorifnis not an integer; - raises a
ValueErrorifnis lesser than 0.
An exact_log2(n) function is added, that:
- returns the integer log2 of
n; - raises a
TypeErrorifnis not an integer; - raises a
ValueErrorifnis not a power-of-two.
Drawbacks
This is a breaking change.
Rationale and alternatives
The following alternatives have been considered:
- Do nothing. Callers of
log2_intmay still need to restrict its domain to positive integers. - Restrict
log2_intto positive integers. Downstream code relying on the previous behavior may silently break. - Remove
log2_int, and usemath.log2as replacement:log2_int(n)would be replaced withmath.log2(n)log2_int(n, need_pow2=False)would be replaced withmath.ceil(math.log2(n))
Option 3) will give incorrect results, as n is coerced from int to float:
>>> log2_int((1 << 64) + 1, need_pow2=False)
65
>>> math.ceil(math.log2((1 << 64) + 1))
64
Prior art
None.
Unresolved questions
None.
Future possibilities
None.
Acknowledgements
@wanda-phi provided valuable feedback while this RFC was being drafted.