Skip to content

Commit 30201d0

Browse files
authored
Improve rounding approach for log2 and log256 (#106)
1 parent e61daa9 commit 30201d0

1 file changed

Lines changed: 14 additions & 16 deletions

File tree

math/core/sources/internal/macros.move

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,8 @@ public(package) macro fun mul_mod<$Int>($a: $Int, $b: $Int, $modulus: $Int): $In
252252
/// - `$bit_width`: The bit width of the type (8, 16, 32, 64, 128, or 256).
253253
///
254254
/// #### Returns
255-
/// The zero-based position of the most significant bit as a `u8`. Returns `0` if `$value` is 0.
255+
/// The zero-based position of the most significant bit as a `u8`.
256+
/// Returns `0` if `$value` is 0.
256257
public(package) macro fun msb<$Int>($value: $Int, $bit_width: u16): u8 {
257258
common::msb($value as u256, $bit_width)
258259
}
@@ -291,10 +292,8 @@ public(package) macro fun log2<$Int>(
291292
floor_log
292293
} else if (rounding_mode == rounding::up()) {
293294
floor_log + 1
294-
} else if (log2_should_round_up(value, floor_log)) {
295-
floor_log + 1
296295
} else {
297-
floor_log
296+
round_log2_to_nearest(value, floor_log)
298297
}
299298
}
300299

@@ -312,7 +311,7 @@ public(package) macro fun log2<$Int>(
312311
/// - `$rounding_mode`: Rounding strategy drawn from `rounding::RoundingMode`.
313312
///
314313
/// #### Returns
315-
/// The base-256 logarithm as a `u16`, rounded according to the specified mode.
314+
/// The base-256 logarithm as a `u8`, rounded according to the specified mode.
316315
/// Returns `0` if `$value` is 0.
317316
public(package) macro fun log256<$Int>(
318317
$value: $Int,
@@ -323,8 +322,8 @@ public(package) macro fun log256<$Int>(
323322
if (value == 0) {
324323
return 0
325324
};
326-
let floor_log2 = common::msb(value, bit_width) as u16;
327-
let floor_log256 = (floor_log2 / 8) as u8;
325+
let floor_log2 = common::msb(value, bit_width);
326+
let floor_log256 = floor_log2 / 8;
328327

329328
if (rounding_mode == rounding::down()) {
330329
floor_log256
@@ -333,10 +332,8 @@ public(package) macro fun log256<$Int>(
333332
floor_log256
334333
} else if (rounding_mode == rounding::up()) {
335334
floor_log256 + 1
336-
} else if (log256_should_round_up(value, floor_log256 as u16)) {
337-
floor_log256 + 1
338335
} else {
339-
floor_log256
336+
round_log256_to_nearest(value, floor_log256)
340337
}
341338
}
342339

@@ -701,11 +698,11 @@ public(package) fun round_division_result(
701698
///
702699
/// #### Returns
703700
/// `true` if the value should round up, `false` otherwise.
704-
public(package) fun log2_should_round_up(value: u256, floor_log: u16): bool {
701+
public(package) fun round_log2_to_nearest(value: u256, floor_log: u16): u16 {
705702
let threshold_exp = 2 * floor_log + 1;
706703
let max_small = std::u128::max_value!() as u256;
707704
let fast_path = threshold_exp < 256 && value <= max_small;
708-
if (fast_path) {
705+
let should_round_up = if (fast_path) {
709706
// Fast path: both value² and exponent fit in u256
710707
let value_squared = value * value;
711708
let threshold = 1 << (threshold_exp as u8);
@@ -720,7 +717,8 @@ public(package) fun log2_should_round_up(value: u256, floor_log: u16): bool {
720717
u512::from_u256(1 << (threshold_exp as u8))
721718
};
722719
value_squared.ge(&threshold)
723-
}
720+
};
721+
if (should_round_up) { floor_log + 1 } else { floor_log }
724722
}
725723

726724
/// Nearest-integer rounding for log256 without floats.
@@ -743,12 +741,12 @@ public(package) fun log2_should_round_up(value: u256, floor_log: u16): bool {
743741
///
744742
/// #### Returns
745743
/// `true` if the value should round up, `false` otherwise.
746-
public(package) fun log256_should_round_up(value: u256, floor_log: u16): bool {
744+
public(package) fun round_log256_to_nearest(value: u256, floor_log: u8): u8 {
747745
// For u256 values, floor_log ∈ [0, 31], so `threshold_exp = 8 * floor_log + 4 ≤ 252`
748746
// and the power-of-two threshold fits safely in u256.
749747
let threshold_exp = 8 * floor_log + 4;
750-
let threshold = 1 << (threshold_exp as u8);
751-
value >= threshold
748+
let threshold = 1 << threshold_exp;
749+
if (value >= threshold) { floor_log + 1 } else { floor_log }
752750
}
753751

754752
/// Apply nearest-integer rounding to log10 without floats.

0 commit comments

Comments
 (0)