Bit Twiddling Hacks
The `bit-twiddle` package provides a highly optimized collection of fundamental bit manipulation functions, ported primarily from Stanford's extensive "Bit Twiddling Hacks" guide. It offers utilities for common bitwise operations such as computing the sign of an integer, absolute value, checking if a number is a power of two, logarithmic approximations (`log2`, `log10`), population count (`popCount`), and finding the next or previous power of two. Additionally, it includes specialized functions for interleaving and deinterleaving bits (`interleave2`, `interleave3`), crucial for efficient spatial indexing schemes like quadtrees and octrees (Z-order curves). The current stable version is 1.0.2, published in 2014. Due to the static nature of bitwise algorithms and the package's age, it is considered abandoned, with no active development or planned release cadence. Its primary differentiator remains its direct, performant JavaScript implementations of these classic algorithms, making it valuable for performance-critical numerical computing or graphics applications where low-level bit manipulation is essential.
Common errors
-
TypeError: Cannot read properties of undefined (reading 'sign')
cause Attempting to use named imports (e.g., `import { sign } from 'bit-twiddle';`) in a CommonJS-only environment (e.g., Node.js without a bundler or `"type": "module"` in `package.json`).fixFor CommonJS, use `const { sign } = require('bit-twiddle');` or `const bitTwiddle = require('bit-twiddle'); const sign = bitTwiddle.sign;` -
ReferenceError: require is not defined
cause Attempting to use CommonJS `require()` syntax in an ESM module context (e.g., a `.mjs` file or a project with `"type": "module"` in `package.json`).fixUse ESM import syntax: `import { sign } from 'bit-twiddle';` Ensure your environment correctly handles ESM modules (e.g., Node.js v12+ or a bundler).
Warnings
- gotcha All bitwise operations in JavaScript implicitly convert numbers to signed 32-bit integers before operating, and then convert the result back to a 64-bit floating-point number. This means values outside the range of -2,147,483,648 to 2,147,483,647 might yield unexpected results if not accounted for, particularly for functions like `isPow2` or `popCount` when applied to very large numbers.
- gotcha The `log2(v)` and `log10(v)` functions return an 'integer approximation' of the logarithm. This is not a precise floating-point logarithm but a quick bitwise estimate, suitable for certain performance-critical algorithms where exactness is not paramount.
- deprecated This package has not been updated since 2014 and is considered abandoned. While bit twiddling hacks are generally stable, there are no guarantees of future maintenance, bug fixes, or performance improvements. Modern JavaScript engines might have optimized built-in operations that approach or exceed the performance of some of these hacks, or newer, maintained libraries might offer similar functionality with better support.
Install
-
npm install bit-twiddle -
yarn add bit-twiddle -
pnpm add bit-twiddle
Imports
- sign
const sign = require('bit-twiddle').sign;import { sign } from 'bit-twiddle'; - isPow2
const bitTwiddle = require('bit-twiddle'); const isPow2 = bitTwiddle.isPow2;import { isPow2 } from 'bit-twiddle'; - interleave2
import interleave2 from 'bit-twiddle';
import { interleave2, deinterleave2 } from 'bit-twiddle';
Quickstart
import { sign, isPow2, nextPow2, popCount, interleave2, deinterleave2 } from 'bit-twiddle';
// Basic bitwise operations
console.log('Sign of -5:', sign(-5)); // Expected: -1
console.log('Is 16 a power of 2?', isPow2(16)); // Expected: true
console.log('Is 15 a power of 2?', isPow2(15)); // Expected: false
console.log('Next power of 2 for 27:', nextPow2(27)); // Expected: 32
console.log('Number of set bits in 42 (00101010b):', popCount(42)); // Expected: 3
// Z-order curve (quadtree/octree) indexing
const x = 12;
const y = 25;
const interleaved = interleave2(x, y);
console.log(`Interleaving (x=${x}, y=${y}): ${interleaved} (binary: ${interleaved.toString(2)})`);
const deinterleavedX = deinterleave2(interleaved, 0);
const deinterleavedY = deinterleave2(interleaved, 1);
console.log(`Deinterleaving: x=${deinterleavedX}, y=${deinterleavedY}`);
// Demonstrating 32-bit integer limits (JavaScript bitwise operations clamp to 32-bit)
const largeNum = 2 ** 31 - 1; // Max signed 32-bit int
console.log(`PopCount for max signed 32-bit int (${largeNum}):`, popCount(largeNum));
const exceedingNum = 2 ** 32; // Exceeds signed 32-bit int range in bitwise ops
console.log(`Is 2^32 a power of 2 (conceptually)? ${isPow2(exceedingNum)}. Actual bitwise value for isPow2 is based on 32-bit interpretation.`, isPow2(exceedingNum));