Skip to content
Merged
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
- `sqrt` for `UD30x9` and `SD29x9` with round-down semantics. (#286)
- `log2`, `ln`, `log10` for `UD30x9` (rounds down) and `SD29x9` (rounds toward zero). (#320)

### `openzeppelin_math`

#### Changed

- `u128::is_power_of_ten` and `u256::is_power_of_ten` now compute the result via `log10_floor` and `pow` instead of a hardcoded lookup table. (#323)

## 1.1.0 (21-04-2026)

### `openzeppelin_fp_math`
Expand Down
58 changes: 20 additions & 38 deletions math/core/sources/internal/macros.move
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,26 @@ public(package) macro fun log10<$Int>($value: $Int, $rounding_mode: RoundingMode
}
}

/// Test whether `$n` is an exact non-negative integer power of ten (`10^k` for some
/// `k >= 0`).
///
/// #### Generics
/// - `$Int`: Any unsigned integer type (`u8`, `u16`, `u32`, `u64`, `u128`, or `u256`).
///
/// #### Parameters
/// - `$n`: The unsigned integer to test.
///
/// #### Returns
/// - `true` if `$n` equals `10^k` for some `k >= 0`, otherwise `false`.
public(package) macro fun is_power_of_ten<$Int>($n: $Int): bool {
let n = $n as u256;
if (n == 0) {
return false
};
let exp = log10_floor(n);
n == 10u256.pow(exp)
}

/// Compute floor(log10(value)) using binary search over powers of 10.
///
/// This helper uses precomputed constants (`TEN_POW_2`, `TEN_POW_4`, etc.) to efficiently
Expand Down Expand Up @@ -1015,41 +1035,3 @@ public(package) fun mul_mod_impl(a: u256, b: u256, modulus: u256): u256 {
((a * b) % modulus)
}
}

/// Perform binary search on a sorted vector to find if `$needle` exists in the vector.
///
/// The helper works across all unsigned widths and performs a standard iterative binary
/// search on a sorted vector. It compares the search value against the middle element
/// at each iteration until either the value is found or the search space is exhausted.
///
/// #### Generics
/// - `$Int`: Any unsigned integer type (`u8`, `u16`, `u32`, `u64`, `u128`, or `u256`).
///
/// #### Parameters
/// - `$haystack`: A sorted vector of unsigned integers to search through.
/// - `$needle`: The value to search for in the vector.
///
/// #### Returns
/// `true` if `$needle` exists in `$haystack`, `false` otherwise.
public(package) macro fun binary_search<$Int>($haystack: vector<$Int>, $needle: $Int): bool {
let haystack = $haystack;
let needle = $needle;

let mut left = 0;
let mut right = haystack.length();

while (left < right) {
let mid = left + (right - left) / 2;
let mid_val = *haystack.borrow(mid);

if (mid_val == needle) {
return true
} else if (mid_val < needle) {
left = mid + 1;
} else {
right = mid;
}
};

false
}
46 changes: 1 addition & 45 deletions math/core/sources/u128.move
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,6 @@ public fun mul_mod(a: u128, b: u128, modulus: u128): u128 {

/// Returns `true` if `n` is a power of ten.
///
/// Uses a lookup table with binary search for efficiency.
/// For `u128`, valid powers of ten range from 10^0 to 10^38.
///
/// #### Parameters
Expand All @@ -226,48 +225,5 @@ public fun mul_mod(a: u128, b: u128, modulus: u128): u128 {
/// #### Returns
/// - `true` if `n` is a power of ten within the `u128` range, otherwise `false`.
public fun is_power_of_ten(n: u128): bool {
// Powers of 10 from 10^0 to 10^38 for u128
let powers = vector[
1u128,
10u128,
100u128,
1000u128,
10000u128,
100000u128,
1000000u128,
10000000u128,
100000000u128,
1000000000u128,
10000000000u128,
100000000000u128,
1000000000000u128,
10000000000000u128,
100000000000000u128,
1000000000000000u128,
10000000000000000u128,
100000000000000000u128,
1000000000000000000u128,
10000000000000000000u128,
100000000000000000000u128,
1000000000000000000000u128,
10000000000000000000000u128,
100000000000000000000000u128,
1000000000000000000000000u128,
10000000000000000000000000u128,
100000000000000000000000000u128,
1000000000000000000000000000u128,
10000000000000000000000000000u128,
100000000000000000000000000000u128,
1000000000000000000000000000000u128,
10000000000000000000000000000000u128,
100000000000000000000000000000000u128,
1000000000000000000000000000000000u128,
10000000000000000000000000000000000u128,
100000000000000000000000000000000000u128,
1000000000000000000000000000000000000u128,
10000000000000000000000000000000000000u128,
100000000000000000000000000000000000000u128,
];

macros::binary_search!(powers, n)
macros::is_power_of_ten!(n)
Comment thread
bidzyyys marked this conversation as resolved.
}
85 changes: 1 addition & 84 deletions math/core/sources/u256.move
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,6 @@ public fun mul_mod(a: u256, b: u256, modulus: u256): u256 {

/// Returns `true` if `n` is a power of ten.
///
/// Uses a lookup table with binary search for efficiency.
/// For `u256`, valid powers of ten range from 10^0 to 10^77.
///
/// #### Parameters
Expand All @@ -235,87 +234,5 @@ public fun mul_mod(a: u256, b: u256, modulus: u256): u256 {
/// #### Returns
/// - `true` if `n` is a power of ten within the `u256` range, otherwise `false`.
public fun is_power_of_ten(n: u256): bool {
// Powers of 10 from 10^0 to 10^77 for u256
let powers = vector[
1u256,
10u256,
100u256,
1000u256,
10000u256,
100000u256,
1000000u256,
10000000u256,
100000000u256,
1000000000u256,
10000000000u256,
100000000000u256,
1000000000000u256,
10000000000000u256,
100000000000000u256,
1000000000000000u256,
10000000000000000u256,
100000000000000000u256,
1000000000000000000u256,
10000000000000000000u256,
100000000000000000000u256,
1000000000000000000000u256,
10000000000000000000000u256,
100000000000000000000000u256,
1000000000000000000000000u256,
10000000000000000000000000u256,
100000000000000000000000000u256,
1000000000000000000000000000u256,
10000000000000000000000000000u256,
100000000000000000000000000000u256,
1000000000000000000000000000000u256,
10000000000000000000000000000000u256,
100000000000000000000000000000000u256,
1000000000000000000000000000000000u256,
10000000000000000000000000000000000u256,
100000000000000000000000000000000000u256,
1000000000000000000000000000000000000u256,
10000000000000000000000000000000000000u256,
100000000000000000000000000000000000000u256,
1000000000000000000000000000000000000000u256,
10000000000000000000000000000000000000000u256,
100000000000000000000000000000000000000000u256,
1000000000000000000000000000000000000000000u256,
10000000000000000000000000000000000000000000u256,
100000000000000000000000000000000000000000000u256,
1000000000000000000000000000000000000000000000u256,
10000000000000000000000000000000000000000000000u256,
100000000000000000000000000000000000000000000000u256,
1000000000000000000000000000000000000000000000000u256,
10000000000000000000000000000000000000000000000000u256,
100000000000000000000000000000000000000000000000000u256,
1000000000000000000000000000000000000000000000000000u256,
10000000000000000000000000000000000000000000000000000u256,
100000000000000000000000000000000000000000000000000000u256,
1000000000000000000000000000000000000000000000000000000u256,
10000000000000000000000000000000000000000000000000000000u256,
100000000000000000000000000000000000000000000000000000000u256,
1000000000000000000000000000000000000000000000000000000000u256,
10000000000000000000000000000000000000000000000000000000000u256,
100000000000000000000000000000000000000000000000000000000000u256,
1000000000000000000000000000000000000000000000000000000000000u256,
10000000000000000000000000000000000000000000000000000000000000u256,
100000000000000000000000000000000000000000000000000000000000000u256,
1000000000000000000000000000000000000000000000000000000000000000u256,
10000000000000000000000000000000000000000000000000000000000000000u256,
100000000000000000000000000000000000000000000000000000000000000000u256,
1000000000000000000000000000000000000000000000000000000000000000000u256,
10000000000000000000000000000000000000000000000000000000000000000000u256,
100000000000000000000000000000000000000000000000000000000000000000000u256,
1000000000000000000000000000000000000000000000000000000000000000000000u256,
10000000000000000000000000000000000000000000000000000000000000000000000u256,
100000000000000000000000000000000000000000000000000000000000000000000000u256,
1000000000000000000000000000000000000000000000000000000000000000000000000u256,
10000000000000000000000000000000000000000000000000000000000000000000000000u256,
100000000000000000000000000000000000000000000000000000000000000000000000000u256,
1000000000000000000000000000000000000000000000000000000000000000000000000000u256,
10000000000000000000000000000000000000000000000000000000000000000000000000000u256,
100000000000000000000000000000000000000000000000000000000000000000000000000000u256,
];

macros::binary_search!(powers, n)
macros::is_power_of_ten!(n)
Comment thread
bidzyyys marked this conversation as resolved.
}
Loading
Loading