Skip to content

use >> 1 for bit manipulation, / 2 for arithmetic halving#240

Merged
cameroncuster merged 6 commits into
devfrom
perf/shift-instead-of-div
Jul 11, 2026
Merged

use >> 1 for bit manipulation, / 2 for arithmetic halving#240
cameroncuster merged 6 commits into
devfrom
perf/shift-instead-of-div

Conversation

@cameroncuster

@cameroncuster cameroncuster commented Jul 10, 2026

Copy link
Copy Markdown
Member

What

Use the operator that matches intent:

  • >> 1 where we are doing bit manipulation — walking powers of two, trie
    bit positions, navigating the implicit segment-tree by index, binary
    exponentiation, Hilbert-curve bit planes, masking with & -bc.
  • / 2 where we are arithmetic halving a value — midpoints, averaging two
    indices, splitting a count/length in two.

Both are identical for the non-negative operands here (/ truncates toward
zero, >> floors toward −∞, and every site is provably >= 0), so this is
purely about spelling intent consistently — one of the pillars of the library.

>> 1 — bit manipulation

  • bit_uncommon/walk.hpp: i >>= 1 — Fenwick binary lifting (i = bit_floor(...))
  • seg_tree.hpp (both variants): i >>= 1, l >>= 1, r >>= 1 — implicit
    binary-heap index navigation
  • strings/binary_trie.hpp: bit >>= 1 (×2) — walking bit positions of a key
  • uncommon/hilbert_mos.hpp: s >>= 1 — Hilbert-curve bit planes
  • trees/uncommon/linear_kth_par.hpp: (bc >> 1) — bit offset inside & -bc
  • math/tetration_mod.hpp + math/count_paths.test.cpp (local modpow):
    e >>= 1 — binary exponentiation (paired with e & 1)

bit_width(EXPR / 2u) — log2 / shift-amount computation

bit_width(x + 0u) - 1 is rewritten as bit_width(x / 2u): same value, but it
reads as "the shift amount", and / 2u keeps the argument unsigned as
std::bit_width requires. Sites: rmq (both), disjoint_rmq, seg_tree nxt,
seg_tree_uncommon/{min_left,max_right} (both), range_parallel_dsu,
ladder_decomposition, linear_kth_par.

/ 2 — arithmetic halving (kept/left as division)

All midpoints and count/length halving stay as / 2: seg_tree_midpoint.hpp
(both), min_plus_convolution_convex_and_arbitrary.hpp,
count_paths/count_paths_triangle.hpp, manacher.hpp, longest_from_index.hpp,
longest_palindrome_query.hpp, uncommon/deque_op.hpp, and the binary-search
midpoints / count halving in the aizu tests (bit_ordered_set, kth_smallest_pst,
mode_query, pq_ds_undo_sliding_window, sa_sort_pairs, lcp_array,
two_edge_components, mono_st_asserts.hpp, handmade_tests/seg_tree_midpoint).

Also in this PR

  • BIT walk cleanup: the callback-based walk(f) in walk_lambda.hpp is
    removed and walk2(sum) is renamed to walk(sum) in both [l,r) and [l,r]
    variants (single, sum-based API). Tests and the cppcheck suppression list are
    updated accordingly.

Why (assembly)

g++ -O3. For signed operands the difference is only the round-toward-zero
correction; for the unsigned/non-negative sites here both lower to a single shift:

int  /2 : add w8, w0, w0, lsr #31   ; add sign bit
          asr w0, w8, #1            ; -> 2 instructions
int >>1 : asr w0, w0, #1            ; -> 1 instruction
unsigned /2 and >>1 : lsr w0,w0,#1  ; identical

Local testing

  • clang-format dry-run (--Werror --style=file:tests/.config/dev.clang-format)
    — passes on all changed files
  • Handmade tests seg_tree_midpoint, seg_tree_find, hilbert_mos, manacher,
    kth_par — pass
  • Exhaustive split equivalence over 9,000,000 range pairs — identical
  • BIT::walk and deq rebuild vs brute force — pass
  • longest_pal_query vs brute force over 20,000 random strings × all substrings
    — identical (start index always >= 0)

Full library-checker/aizu verification runs in CI.

@cameroncuster cameroncuster changed the title data_structures: use >> 1 instead of / 2 for non-negative halving library: use >> 1 instead of / 2 for non-negative halving Jul 11, 2026
@cameroncuster cameroncuster changed the title library: use >> 1 instead of / 2 for non-negative halving use >> 1 instead of / 2 for non-negative halving (library + tests) Jul 11, 2026
@cameroncuster cameroncuster changed the title use >> 1 instead of / 2 for non-negative halving (library + tests) use >> 1 for bit manipulation, / 2 for arithmetic halving Jul 11, 2026
@cameroncuster cameroncuster marked this pull request as ready for review July 11, 2026 03:39
@cameroncuster cameroncuster merged commit c553e26 into dev Jul 11, 2026
8 checks passed
@cameroncuster cameroncuster deleted the perf/shift-instead-of-div branch July 11, 2026 03:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants