Skip to content

Commit

Permalink
Clarify the choice of magic numbers and compute the most magic one
Browse files Browse the repository at this point in the history
  • Loading branch information
vitaut committed Jan 23, 2022
1 parent 09fde7f commit f7a809b
Showing 1 changed file with 17 additions and 3 deletions.
20 changes: 17 additions & 3 deletions include/fmt/format-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -927,13 +927,27 @@ inline int floor_log10_pow2_minus_log10_4_over_3(int e) noexcept {
// Precondition: n <= pow(10, N + 1).
template <int N>
bool check_divisibility_and_divide_by_pow10(uint32_t& n) noexcept {
// The numbers below are chosen such that:
// 1. floor(n/d) = floor(nm / 2^(k+l)) where d=10 or d=100,
// 2. floor(nm/2^k) mod 2^l = 0 if and only if n is divisible by d,
// where m is magic_number, k is margin_bits, l is divisibility_check_bits
// and d is divisor.
//
// Item 1 is a common technique of replacing division by a constant with
// multiplication, see e.g. "Division by Invariant Integers Using
// Multiplication" by Granlund and Montgomery (1994). magic_number (m) is set
// to ceil(2^(k+l)/d) for large enough k+l.
// The idea for item 2 originates from Schubfach.
static constexpr struct {
uint32_t magic_number;
int divisor;
int margin_bits;
int divisibility_check_bits;
} infos[] = {{0x199a, 8, 8}, {0xa3d71, 10, 16}};
} infos[] = {{10, 8, 8}, {100, 10, 16}};
constexpr auto info = infos[N - 1];
n *= info.magic_number;
constexpr uint32_t magic_number =
(1 << (info.margin_bits + info.divisibility_check_bits)) / info.divisor +
1;
n *= magic_number;
n >>= info.margin_bits;
const uint32_t comparison_mask = (1u << info.divisibility_check_bits) - 1;
bool result = (n & comparison_mask) == 0;
Expand Down

0 comments on commit f7a809b

Please sign in to comment.