{"id":134,"date":"2026-11-12T16:40:00","date_gmt":"2026-11-12T16:40:00","guid":{"rendered":"https:\/\/tothepowerof2.com\/blog\/?p=134"},"modified":"2026-11-11T03:37:53","modified_gmt":"2026-11-11T03:37:53","slug":"hash-table-capacities-near-powers-of-two","status":"publish","type":"post","link":"https:\/\/tothepowerof2.com\/blog\/hash-table-capacities-near-powers-of-two\/","title":{"rendered":"Sizing Hash Table Capacities Near Powers of Two"},"content":{"rendered":"<p><strong>TL;DR \/ Summary:<\/strong> Many hash tables size their buckets to a power of two so index mapping can use bitwise masks instead of slow modulo operations. Before you hard-code 1024 or 4096, confirm 2\u207f with <a href=\"https:\/\/tothepowerof2.com\/\">tothepowerof2.com<\/a>, plan a load-factor resize, and know when prime capacities are the wiser tradition.<\/p>\n<h2>Why buckets love 2\u207f<\/h2>\n<p>A hash function yields a wide integer; the table must fold that integer into an index. If capacity is 2\u207f, <code>hash &amp; (capacity - 1)<\/code> replaces <code>hash % capacity<\/code>. On modern CPUs the mask is cheap and branch-friendly. Languages and libraries that promise amortized constant-time lookups often document power-of-two growth for that reason.<\/p>\n<p>Growth policies commonly double: 16 \u2192 32 \u2192 64 \u2192 \u2026 Doubling preserves the power-of-two invariant and spreads entries after a rehash. Understanding the exponent helps you predict memory spikes when a table crosses a load-factor threshold mid-request. That prediction matters on latency-sensitive paths more than on batch jobs that can pause.<\/p>\n<h2>Load factor is the real dial<\/h2>\n<p>Capacity alone does not define performance. Load factor\u2014entries divided by buckets\u2014decides how often collisions chain or probe. A 2\u00b9\u00b2-bucket table at 0.9 load can feel worse than a 2\u00b9\u2070 table at 0.5. When estimating memory, multiply expected entries by your max load factor, then round <em>up<\/em> to the next power of two so you do not resize during a latency-sensitive window.<\/p>\n<p>Worked sketch: 1,800 session tokens, max load 0.75 \u2192 need at least 2,400 buckets \u2192 next power of two is 2\u00b9\u00b2 = 4096. Compute that ceiling with a calculator instead of guessing \u201cabout four thousand.\u201d Write the assumption in a code comment so the next engineer knows why 4096 appeared rather than 3000.<\/p>\n<h2>When primes still appear<\/h2>\n<p>Some older guidance prefers prime bucket counts to reduce patterned collisions when hash mixing is weak. If your hasher is low quality or identity-based on sequential keys, a prime modulus can help. High-quality mixers plus power-of-two masks are the common modern pairing\u2014especially in systems languages that control both hasher and table.<\/p>\n<p>Read your standard library notes. Blindly forcing 2\u207f in a structure that already rounds to primes wastes time and may fight its resize heuristics. Interop layers that wrap two different map types should not assume identical sizing philosophies.<\/p>\n<h2>Cache lines, allocator pressure, and servers<\/h2>\n<p>Doubling a large table briefly needs old and new storage. On a memory-tight VPS or mobile runtime, that spike matters more than the elegance of bitwise indexing. Pre-size tables when you know the cardinality (dictionaries of feature flags, caches of SKUs) so traffic does not trigger a mid-day rehash.<\/p>\n<p>Also watch pointer-heavy entries: the bucket array may be 2\u207f, but each collision node allocates separately. Profiling allocations often reveals more pain than the mask versus modulo debate. Sometimes a denser open-addressing table with a slightly larger power-of-two array beats a chaining design that looks smaller on paper.<\/p>\n<h2>Debugging checklist for \u201cmysterious\u201d slow maps<\/h2>\n<ul>\n<li>Log capacity and size at resize boundaries.<\/li>\n<li>Verify the hasher is not returning near-sequential values for your key type.<\/li>\n<li>Confirm you did not clamp capacity to a non-power accidentally via a buggy rounder.<\/li>\n<li>Compare hit latency before and after a forced rehash offline.<\/li>\n<\/ul>\n<p>If a custom round-up function fails on edge exponents, validate with known values: 2\u00b9\u2070=1024, 2\u00b9\u2076=65536, 2\u00b2\u2070=1048576. Keep that cheat sheet in the PR description when changing defaults. Unit-test the rounder with inputs just below and above each boundary; off-by-one bugs love those edges.<\/p>\n<h2>Team conventions that prevent thrash<\/h2>\n<p>Agree whether configs express capacity as an exponent, as a raw bucket count, or as an expected entry count with a load factor. Mixing the three in one codebase produces silent production surprises. Prefer \u201cexpected entries + load factor\u201d in product configs and let library code round to 2\u207f internally. That keeps product managers away from bitwise trivia while still giving engineers predictable memory.<\/p>\n<h2>Benchmarks that answer the right question<\/h2>\n<p>Microbenchmarks that insert random keys into an empty map until a timer stops rarely resemble production. Prefer fixtures that match your key distribution: UUIDs, monotonic IDs, email strings, or composite keys. Measure lookup p95 after the table reaches steady size, including one forced resize, so you see allocation spikes.<\/p>\n<p>Compare two capacities that differ by one exponent\u2014say 2\u00b9\u00b9 versus 2\u00b9\u00b2\u2014while holding load factor constant. If latency barely moves but RSS jumps, the larger table may be vanity. If collision chains dominate profiles, the larger table may be cheap insurance. Publish both numbers in the PR so reviewers are not asked to trust folklore about \u201cpowers of two are always faster.\u201d<\/p>\n<p>For services with cold starts, pre-sizing to the expected steady cardinality can matter more than asymptotic elegance. A first-request rehash on a latency SLO path is a self-inflicted outage pattern.<\/p>\n<h2>Capacity near a power of two beats superstition<\/h2>\n<p>Power-of-two capacities are a performance convention, not a superstition. Size from expected entries and load factor, round up to a clean 2\u207f when your library expects it, and use <a href=\"https:\/\/tothepowerof2.com\/\">the powers-of-two tool<\/a> to avoid off-by-one exponents that strand you at 2047 buckets instead of 2048. Predictable growth beats heroic micro-optimizations after an outage.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>TL;DR \/ Summary: Many hash tables size their buckets to a power of two so index mapping can use bitwise masks instead of slow modulo operations. Before you hard-code 1024 or 4096, confirm 2\u207f with tothepowerof2.com, plan a load-factor resize, and know when prime capacities are the wiser tradition. Why buckets love 2\u207f A hash &#8230; <a title=\"Sizing Hash Table Capacities Near Powers of Two\" class=\"read-more\" href=\"https:\/\/tothepowerof2.com\/blog\/hash-table-capacities-near-powers-of-two\/\" aria-label=\"Read more about Sizing Hash Table Capacities Near Powers of Two\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":61,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[],"class_list":["post-134","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-math-practice-examples"],"_links":{"self":[{"href":"https:\/\/tothepowerof2.com\/blog\/wp-json\/wp\/v2\/posts\/134","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/tothepowerof2.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/tothepowerof2.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/tothepowerof2.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/tothepowerof2.com\/blog\/wp-json\/wp\/v2\/comments?post=134"}],"version-history":[{"count":2,"href":"https:\/\/tothepowerof2.com\/blog\/wp-json\/wp\/v2\/posts\/134\/revisions"}],"predecessor-version":[{"id":137,"href":"https:\/\/tothepowerof2.com\/blog\/wp-json\/wp\/v2\/posts\/134\/revisions\/137"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/tothepowerof2.com\/blog\/wp-json\/wp\/v2\/media\/61"}],"wp:attachment":[{"href":"https:\/\/tothepowerof2.com\/blog\/wp-json\/wp\/v2\/media?parent=134"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/tothepowerof2.com\/blog\/wp-json\/wp\/v2\/categories?post=134"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/tothepowerof2.com\/blog\/wp-json\/wp\/v2\/tags?post=134"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}