Skip to main content
Back to BlogConverter Guides

How to Convert Number Bases (and Why BigInt Through Decimal Is the Only Honest Path)

Convert between binary, octal, decimal, hex, and 8 more number bases — and learn why every conversion goes through decimal as the base unit, why BigInt prevents precision loss above 2^53, why hex maps 4 bits per digit and octal maps 3, why two's complement is asymmetric, and why IEEE 754 has a 127 bias.

The Toolbox TeamAugust 14, 20268 min read

The problem: JavaScript's Number loses precision at 2^53 and your hex conversion is wrong

You need to convert 0xDEADBEEF to binary. You reach for parseInt('DEADBEEF', 16).toString(2) — and JavaScript returns 11011110101011011011111011101111, which is correct. Then you try 0x1FFFFFFFFFFFFF (2^53 - 1) and it still works. Then you try 0x10000000000000000 (2^64) and JavaScript returns 0 because Number can't represent integers above 2^53 — the value silently overflows to a floating-point approximation and the conversion is wrong. The honest move is a converter that uses BigInt as the base unit, parses every input through decimal, and renders to any base — never trusting the floating-point path.

Fastest path

Open the Number Base Converter, type the value, pick the from-base and to-base, read the result.

Input:   DEADBEEF (hexadecimal, base 16)
 Decimal:  3735928559
 Binary:   1101 1110 1010 1101 1011 1110 1110 1111
 Octal:    33653337357
 Base-36:  1ceq4
 Two's complement (8-bit): overflow
 Two's complement (32-bit): 11011110101011011011111011101111
 IEEE 754: 0 | 10011101 | 11011110101011011011111

The tool parsed the hex string through DIGIT_CHARS.indexOf() into a BigInt, then rendered that BigInt in all 12 supported bases simultaneously — binary, octal, decimal, hex, base-32, base-36, ternary, quinary, senary, duodecimal, vigesimal, and base-4. It also computed the two's complement representation at four word sizes (8, 16, 32, 64-bit) and the IEEE 754 single-precision float layout. The rest of this guide is why BigInt is the only honest path, why hex maps 4 bits per digit, why two's complement is asymmetric, and why IEEE 754 has a 127 bias.

The substance: one base unit, one digit alphabet, twelve bases

The BigInt-through-decimal conversion path

The tool never converts directly between two non-decimal bases. Every conversion is two steps: parse the input to a BigInt (parseBaseValue), then render the BigInt to the target base (toBaseString). BigInt is the base unit — the same pattern as the byte converter's "everything goes through bytes."

The parse function iterates each character, looks up its value in DIGIT_CHARS ('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'), and accumulates: result = result * bigBase + BigInt(DIGIT_CHARS.indexOf(ch)). This is positional notation in a loop — each digit multiplies the running total by the radix and adds the digit's value. The render function is the inverse: repeatedly take remaining % bigBase to get the least significant digit, prepend it to the result string, and divide remaining by bigBase. Both functions use BigInt, so they work for numbers of any size — 0xDEADBEEF and 0x10000000000000000 both parse correctly.

JavaScript's Number type is a 64-bit IEEE 754 float — it can represent integers exactly up to 2^53 (9,007,199,254,740,991). Above that, integers lose precision: Number(2^53 + 1) === Number(2^53) is true because the float can't distinguish them. parseInt returns a Number, so parseInt('100000000000000000', 16) silently returns a wrong value. BigInt has no such limit — BigInt('1152921504606846976') is exact. The tool uses BigInt for every conversion, which is why it handles 64-bit hex values, large memory addresses, and cryptographic constants without precision loss.

The digit alphabet and why base-36 is the ceiling

DIGIT_CHARS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ' is 36 characters — 10 digits plus 26 letters. This is why the tool supports bases 2 through 36 but no higher. Base-36 uses the full alphanumeric set (0-9, A-Z) and is the densest base that can be represented with single-character digits using case-insensitive ASCII. Bases above 36 would need multi-character digits or case sensitivity, both of which create ambiguity.

The tool supports 12 bases across three categories:

Category Bases Use case
Common 2, 8, 10, 16 Binary, octal, decimal, hex — the four bases every programmer uses
Programming 32, 36 Base-32 for TOTP/2FA codes (RFC 4648), Base-36 for compact URL-safe IDs
Mathematical 3, 4, 5, 6, 12, 20 Ternary, quinary, senary, duodecimal, vigesimal — historical and theoretical bases

The mathematical bases are niche but real. Duodecimal (base 12) is advocated by the Dozenal Society because 12 has more divisors than 10 (1, 2, 3, 4, 6, 12 vs 1, 2, 5, 10), making fractions cleaner. Vigesimal (base 20) was used by the Maya. Ternary (base 3) is studied because ternary logic is more efficient than binary in some theoretical models. The tool includes them not because they're practical but because they're the bases people search for when learning number systems.

Why hex is 4 bits per digit and octal is 3

Each hex digit maps to exactly 4 binary bits because 16 = 2^4. 0xF = 1111, 0x0 = 0000. This is why hex is the standard for representing byte values — two hex digits make one byte, and the mapping is unambiguous. The tool's formatGrouped function groups binary digits into 4-bit or 8-bit chunks for readability: 1101111010101101 becomes 1101 1110 1010 1101 (4-bit) or 11011110 10101101 (8-bit).

Each octal digit maps to exactly 3 binary bits because 8 = 2^3. 0o7 = 111, 0o0 = 000. This is why Unix file permissions use octal — chmod 755 is 7 (rwx) 5 (r-x) 5 (r-x), and each octal digit is 3 permission bits. The 3-bit mapping is also why octal doesn't divide evenly into bytes — one byte is 8 bits, which is 2 octal digits plus 2 leftover bits. This awkwardness is why hex replaced octal as the standard byte representation.

Two's complement and the asymmetric range

The tool computes two's complement at four word sizes: 8, 16, 32, and 64-bit. The signed range is asymmetric:

Word size Min signed Max signed Max unsigned
8-bit -128 127 255
16-bit -32,768 32,767 65,535
32-bit -2,147,483,648 2,147,483,647 4,294,967,295
64-bit -9,223,372,036,854,775,808 9,223,372,036,854,775,807 18,446,744,073,709,551,615

The asymmetry — min is -128 but max is 127 — comes from two's complement encoding. The representation uses the most significant bit as the sign bit, but the negative range includes the value where all bits are 1 (10000000 = -128) while the positive range tops out at 01111111 = 127. There's no +128 in 8-bit signed because that would require a 1 in the sign bit, which is reserved for negatives. The tool flags "overflow" when the input is outside the signed or unsigned range for the selected word size.

The toBinaryString function handles negative numbers by computing maxVal + value — the two's complement encoding. For -1 in 8-bit: 255 + (-1) = 254 = 11111110. For -128: 256 + (-128) = 128 = 10000000. This is the same arithmetic your CPU does; the tool shows you the bits.

IEEE 754 and the 127 bias

The tool renders the IEEE 754 single-precision (32-bit float) layout: 1 sign bit, 8 exponent bits, 23 mantissa bits. The sign bit is 0 for positive, 1 for negative. The exponent is stored with a bias of 127 — the actual exponent is storedExponent - 127. A stored exponent of 128 means an actual exponent of 1; a stored exponent of 127 means an actual exponent of 0. The bias allows the exponent to represent both positive and negative powers without a separate sign bit for the exponent.

The tool uses DataView.setFloat32 to get the raw bytes, then converts each byte to its 8-bit binary string. The output is color-coded: red for the sign bit, blue for the exponent, green for the mantissa. This is the same layout that Float.floatToIntBits in Java and memcpy in C produce — the tool shows you what's actually in memory when you store a float.

The bit-flip visualization and bitwise operations

The tool's Bit Pattern tab renders the value as clickable bit buttons — click any bit to flip it, and the decimal value updates instantly. This is the fastest way to understand bitwise operations: flip the sign bit in an 8-bit value and watch 127 become -1. The word size selector (8, 16, 32, 64) changes the number of bits rendered.

The Bitwise Calculator supports six operations: AND (&), OR (|), XOR (^), NOT (~), left shift (<<), right shift (>>). AND returns 1 only where both bits are 1; OR returns 1 where either bit is 1; XOR returns 1 where the bits differ; NOT flips all bits; left shift multiplies by 2^n; right shift divides by 2^n (with sign extension for signed values). These are the operations that bitmasking, flag systems, and low-level protocol parsing rely on.

Gotchas

  • JavaScript's Number loses precision above 2^53. parseInt('20000000000000000', 16) returns a wrong value because Number can't represent 2^64. The tool uses BigInt, so it handles 64-bit values correctly. If you're using parseInt + toString in your own code, switch to BigInt for values above 2^53.
  • Two's complement is asymmetric. 8-bit signed ranges from -128 to 127, not -127 to 127. The -128 value has no positive counterpart. The tool shows the exact range for each word size.
  • Octal doesn't divide evenly into bytes. One byte is 8 bits = 2 octal digits + 2 leftover bits. This is why hex (2 digits per byte) replaced octal as the standard byte representation.
  • IEEE 754 has a 127 bias, not 128. The stored exponent is actualExponent + 127. A stored exponent of 127 means actual exponent 0 (2^0 = 1). The bias is 2^(exponentBits - 1) - 1 = 2^7 - 1 = 127 for single-precision.
  • Base-36 is case-insensitive. DIGIT_CHARS uses uppercase A-Z. The tool's parseBaseValue uppercases the input before parsing, so deadbeef and DEADBEEF produce the same value. If you need case-sensitive base-62 (0-9, a-z, A-Z), this tool doesn't support it.
  • The two's complement overflow flag is per word size. DEADBEEF (3,735,928,559) fits in 32-bit unsigned but not 32-bit signed (max 2,147,483,647). The tool shows "overflow" for the signed 32-bit interpretation but the correct value for unsigned 32-bit. Check which interpretation your use case needs.
  • Left shift can overflow silently. 1 << 31 in JavaScript (using Number) produces -2147483648 because the sign bit gets set. The tool uses BigInt for shifts, so 1n << 63n produces the correct 64-bit value. Don't rely on JavaScript's << operator for values above 2^31.
  • The presets are real values programmers encounter. 0xFF (255), chmod 755 (octal), DEADBEEF (hex), 0b11111111 (max byte), 2147483647 (max int32). Click any preset to load it and see all 12 base representations.
  • Text encoding is per-character, not per-string. "Hello" in binary is 01001000 01100101 01101100 01101100 01101111 — each character is 8 bits. The tool's text-to-binary encoder uses charCodeAt(0).toString(2).padStart(8, '0') per character. This works for ASCII but not for characters above U+FFFF (emoji, CJK extensions) — those need surrogate pairs and the encoder shows the raw code units, not the code point.

Summary

  • Every conversion goes through BigInt as the base unit. parseBaseValue reads the input into a BigInt using DIGIT_CHARS.indexOf() per character; toBaseString renders the BigInt to any base by repeated % bigBase and / bigBase. BigInt prevents the precision loss that Number suffers above 2^53.
  • DIGIT_CHARS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ' is 36 characters — the digit alphabet for all supported bases. Base-36 is the ceiling because it's the densest case-insensitive single-character base. The tool supports 12 bases across three categories (common, programming, mathematical).
  • Hex maps 4 bits per digit (16 = 2^4); octal maps 3 (8 = 2^3). This is why hex is the standard for bytes (2 hex digits = 1 byte) and octal is the standard for Unix permissions (3 bits per digit = rwx). The tool groups binary into 4-bit or 8-bit chunks for readability.
  • Two's complement is asymmetric. 8-bit signed ranges from -128 to 127 because the sign bit's negative range includes the all-zeros-except-sign value (10000000 = -128) but the positive range tops out at 01111111 = 127. The tool shows signed/unsigned values and overflow flags for 8, 16, 32, and 64-bit word sizes.
  • IEEE 754 single-precision is 1 sign + 8 exponent + 23 mantissa with a 127 bias. The stored exponent is actualExponent + 127. The tool uses DataView.setFloat32 to get the raw bytes and color-codes the sign (red), exponent (blue), and mantissa (green) bits.
  • The bit-flip visualization and bitwise calculator (AND, OR, XOR, NOT, shifts) let you see and manipulate individual bits. Click any bit to flip it; the decimal value updates instantly. This is the fastest way to understand why flipping the sign bit turns 127 into -1.
  • Convert at the Number Base Converter; for spreadsheet conversion use CSV to Excel Converter, for JSON tabular conversion use JSON to CSV Converter, and for color format conversion use Color Converter.