By Docify

Positional BigInt vs Number.parseInt

• 6 min read

Number.parseInt stops at the first invalid digit and returns an IEEE-754 Number (exact integers only through 2^53 − 1). Number.parseInt("1012", 2) is 5. Number.parseInt("9007199254740993", 10) is 9007199254740992. The live converter reads bases 2–36 with Horner's method on BigInt (value = value * radix + digit) and rejects a bad digit instead of truncating. Output is BigInt.prototype.toString(radix). Example: Convert returns 255. FF converts to that same 255. At most 256 digits. Not two's complement. Encoding UTF-8 text as RFC 4648 §8 hex (foobar → 666F6F626172) is /base16/, not this integer converter.

“Convert hex to decimal” is often implemented as Number.parseInt(s, 16). That function and positional notation are not the same algorithm. This page names the two failure modes — silent truncation and the 53-bit integer limit — and why the number base converter uses Horner's method on BigInt for every radix from 2 to 36. Encoding the letters of a string as RFC 4648 §8 hex is a different algorithm — that output is foobar → 666F6F626172 on /base16/.

Number.parseInt stops at the first bad digit

1012 in base 2 is not five

ECMA-262 parseInt (and Number.parseInt, the same function) reads a prefix of radix-R digits and ignores the rest. Number.parseInt("1012", 2) is 5 because it accepts 101 and stops at 2. Likewise Number.parseInt("12x3", 10) is 12, and Number.parseInt("10.5", 10) is 10. When the radix is 16, a leading 0x or 0X is a recognized prefix: Number.parseInt("0x10", 16) is 16. 0b and 0o are not special; Number.parseInt("0b10", 2) is 0.

parseInt("1012", 2) = 5 · converter throws on digit 2

The converter rejects the same strings

Horner's loop looks up each character in 0123456789abcdefghijklmnopqrstuvwxyz after toLowerCase(). A digit value must be less than the from-base, or the page throws Digit "2" is not valid in base 2. Hex 0x10 fails on x, not because prefixes are stripped. The example fills hex ff to decimal; clicking Convert writes 255. FF converts to that same 255. Copy writes the displayed string. Nothing is uploaded.

IEEE-754 cannot hold every integer

Exact integers end at 2^53 − 1

A JavaScript Number is IEEE-754 binary64. The significand is 53 bits, so Number.MAX_SAFE_INTEGER is 9007199254740991 (2^53 − 1). Past that, consecutive integers are not all representable: Number.parseInt("9007199254740993", 10) is 9007199254740992. The Number literal 9007199254740993 is already that even value, so === cannot detect the loss.

parseInt("9007199254740993", 10) = 9007199254740992

Hex 20000000000001 is 2^53 + 1

Fourteen hex digits reach 56 bits. 16^13 is 2^52 (4503599627370496), so 20000000000001 is 2 × 16^13 + 1 = 9007199254740993. Horner on BigInt keeps the odd integer 9007199254740993n. Number.parseInt("20000000000001", 16) is 9007199254740992. That is why this page does not parse with an IEEE-754 Number and does not emit Number.prototype.toString(radix).

BigInt() is not a radix parser

0xff works; ff throws

BigInt("0xff") is 255n. So do the binary and octal prefixes 0b and 0o. BigInt("ff") throws SyntaxError. There is no BigInt.parseInt(string, radix). A constructor call therefore cannot read the sample input ff in base 16, or a custom base-36 string, without a prefix the page also refuses.

BigInt("ff") → SyntaxError · Horner("ff", 16) → 255n

Horner: value = value * radix + digit

After trim and an optional leading minus (mathematical sign, not two's complement), each character is a digit value in 0–35. Hex ff is 0 × 16 + 15 = 15, then 15 × 16 + 15 = 255. Example: Convert returns 255. Decimal 255 to hex writes ff. Output is BigInt.prototype.toString(radix) (ECMA-262, lowercase 0-9a-z). Uppercase reformats those letters and does not convert again. At most 256 digits. Rejected: 0x / 0b / 0o prefixes, underscores, interior spaces, fractions, scientific notation, fixed-width two's complement, IEEE-754 dumps, and custom alphabets (not Base58 / Base62 / Base64). Encoding UTF-8 text as RFC 4648 §8 hex is /base16/.

Integer hex is not RFC 4648 Base16

ff → 255 is a number; foobar → 666F6F626172 is bytes

Hex on this page is a radix, not an encoding. Example: Convert returns 255 because ff is 15 × 16 + 15. The Base16 encoder writes RFC 4648 §8 (0–9 A–F, no padding) of UTF-8 bytes. Encoding ASCII foobar writes 666F6F626172. A SHA-256 output on /hash-generator/ is also hex, but it is an unkeyed digest, not a radix and not Base16 of typed text. #3366cc on /color-converter/ is an 8-bit sRGB triple. The live number-base converter does not encode text.

Convert bases 2–36 with exact BigInt arithmetic

Example: Convert returns hex ff → 255. Horner parse, not Number.parseInt. Invalid digits throw. Nothing is uploaded.

Use Number Base Converter →

FAQ

What is the difference between BigInt and parseInt?
parseInt returns a Number (limited to 2^53-1). BigInt handles arbitrarily large integers.
When should I use BigInt?
Use BigInt for integers larger than Number.MAX_SAFE_INTEGER (9007199254740991).
Can I mix BigInt and Number?
No. You must explicitly convert between them. 1n + 1 throws a TypeError.
Does this tool upload my data?
No. All processing runs in your browser using JavaScript. Nothing is sent to a server.

Related