LogicGates.org Open the simulatorSimulator

Integer limits

The smallest and largest value of every fixed-width integer type, from int8 to uint128, with what each one is called in C, Java, C#, Rust, Go, SQL and JavaScript. Type a number to see which types can hold it.

A whole number in decimal, 0x hex or 0b binary, negative if you like. Commas are fine, and so are 2^31 − 1 and 2³¹ − 1.

Smallest types for 3,000,000,000
Smallest signed type: int64 Smallest unsigned type: uint32
It needs 33 bits as a signed two’s complement number and 32 bits as an unsigned one.
  • int8 too small
  • uint8 too small
  • int16 too small
  • uint16 too small
  • int32 too small
  • uint32 holds it
  • int64 holds it
  • uint64 holds it
  • int128 holds it
  • uint128 holds it

Minimum and maximum of every integer type

Each name links to a page with the limits in hex and binary, the type’s name in each language, and an overflow playground set to that type.

Type Bits Maximum Minimum
int8 8 1272⁷ − 1 −128−2⁷
uint8 8 2552⁸ − 1 0
int16 16 32,7672¹⁵ − 1 −32,768−2¹⁵
uint16 16 65,5352¹⁶ − 1 0
int32 32 2,147,483,6472³¹ − 1 −2,147,483,648−2³¹
uint32 32 4,294,967,2952³² − 1 0
int64 64 9,223,372,036,854,775,8072⁶³ − 1 −9,223,372,036,854,775,808−2⁶³
uint64 64 18,446,744,073,709,551,6152⁶⁴ − 1 0
int128 128 170,141,183,460,469,231,731,687,303,715,884,105,7272¹²⁷ − 1 −170,141,183,460,469,231,731,687,303,715,884,105,728−2¹²⁷
uint128 128 340,282,366,920,938,463,463,374,607,431,768,211,4552¹²⁸ − 1 0

The formulas

n bits make 2ⁿ different patterns. An unsigned type reads them all as magnitudes, a signed type gives the half with the top bit set to negative numbers, using two’s complement:

Signed, n bits

−2ⁿ⁻¹ to 2ⁿ⁻¹ − 1

For 32 bits: −2³¹ to 2³¹ − 1, which is −2,147,483,648 to 2,147,483,647.

Unsigned, n bits

0 to 2ⁿ − 1

For 32 bits: 0 to 2³² − 1, which is 0 to 4,294,967,295.

The signed range is lopsided: there is one more negative number than positive, because zero takes one of the patterns whose top bit is 0. So the smallest int8 is −128 but the largest is only 127, and negating −128 overflows back to itself. In hex the limits are easy to spot: a signed maximum is 7F followed by Fs (0x7FFFFFFFFFFFFFFF for int64), the signed minimum is 8 followed by zeros, and an unsigned maximum is all Fs.

Same bits, two readings: the signed and unsigned type of each width
Width Signed range Unsigned range
8 bits −2⁷ to 2⁷ − 1 0 to 2⁸ − 1
16 bits −2¹⁵ to 2¹⁵ − 1 0 to 2¹⁶ − 1
32 bits −2³¹ to 2³¹ − 1 0 to 2³² − 1
64 bits −2⁶³ to 2⁶³ − 1 0 to 2⁶⁴ − 1
128 bits −2¹²⁷ to 2¹²⁷ − 1 0 to 2¹²⁸ − 1

Overflow playground

Pick a type and a value, then add one, subtract one, double, negate or cast it to another type. The bits show what the processor does: it keeps the low bits and drops whatever does not fit.

Decimal, 0x hex or 0b binary, with a minus sign if negative. 2^31 − 1 works too.

int8: 127 +1 −128 Overflow: wrapped past the maximum to the bottom of the range
Before 0x7F
Exact answer 128 written in 9 bits: the leftmost bit does not fit and is dropped
After 0x80

The solid underlined bit is the sign bit: 1 means negative in a signed type. Struck-through bits are dropped.

  1. Exact answer: 128.
  2. That is above the maximum of int8, 127.
  3. The hardware keeps only the low 8 bits, which is the same as taking the answer modulo 2⁸ = 256: 128.
  4. The top bit is 1, so read as signed it is 128 − 256 = −128.

What each language does on overflow

The bits wrap the same way on every processor; what differs is whether the language lets that happen silently, stops the program, or never runs out of bits at all. The C, Java, Rust, Go, JavaScript and Python behaviour here was checked by running code.

What each language does when integer arithmetic overflows
Language By default To check or wrap on purpose
C and C++ Unsigned types wrap around modulo 2ⁿ. Signed overflow is undefined behaviour: the compiler may assume it never happens and optimise on that basis. Types narrower than int are promoted to int first, so even uint16_t × uint16_t can overflow a signed int. __builtin_add_overflow (GCC, Clang); ckd_add in C23’s <stdckdint.h>; -fsanitize=undefined to catch it
Java Wraps around silently, in two’s complement. Math.addExact, multiplyExact and friends throw ArithmeticException
C# Wraps around, unless the code is in a checked context, which throws OverflowException. A constant expression that overflows is a compile error. checked(...) blocks, or the CheckForOverflowUnderflow compiler option
Rust Panics in debug builds. Release builds wrap, unless overflow-checks is turned on for that profile. checked_add, wrapping_add, saturating_add, overflowing_add
Go Wraps around silently. Only constant expressions that overflow are compile errors. math/bits.Add64 reports the carry; Mul64 returns the high half of the product
Swift Traps: the program stops with a runtime error. &+, &-, &* wrap on purpose; addingReportingOverflow reports it
Kotlin Wraps around silently, like Java. Math.addExact on the JVM
JavaScript Numbers never wrap, but lose precision past 2⁵³. Bitwise operators and typed arrays wrap to their width. BigInt never overflows. Number.isSafeInteger; BigInt.asIntN and asUintN to wrap deliberately
Python int never overflows: it grows as needed. ctypes and NumPy fixed-width types do wrap
SQL An error: the statement fails with an out of range or arithmetic overflow message. MySQL outside strict mode clips an out-of-range value stored into a column to the limit, with a warning

One C and C++ detail: arithmetic on 8 and 16-bit types is done in int, so x + 1 on an int8_t at 127 is 128 as an int. It only wraps when stored back into the int8_t; that conversion is implementation defined in C (GCC and Clang wrap) and defined as wrapping since C++20.

Real overflows and limits

  • Pac-Man level 256 (uint8): The arcade Pac-Man keeps its level number in a single byte. On level 256 the routine that draws the bonus fruit at the bottom of the screen goes wrong when that count overflows: it draws far more than it should, garbles the right half of the maze and leaves a level that cannot be finished.
  • Ariane 5 flight 501 (int16): On 4 June 1996 the first Ariane 5 broke up about 40 seconds after lift-off. Its inertial reference software converted a 64-bit floating-point value, the horizontal bias, into a 16-bit signed integer. The value was larger than 32,767, the conversion raised an exception, both inertial reference units shut down, and the rocket veered off course and was destroyed.
  • The Year 2038 problem (int32): Unix time counts seconds since 1970-01-01 00:00:00 UTC. In a signed 32-bit integer the last second it can hold is 2038-01-19 03:14:07 UTC; one second later it wraps to −2,147,483,648, which reads as 1901-12-13 20:45:52 UTC. Systems that still store time in 32 bits need to move to 64.
  • Boeing 787 generator control units (int32): In 2015 the US Federal Aviation Administration ordered 787 operators to cycle power regularly, because a software counter in the generator control units overflowed after 248 days of continuous power and could shut down all AC power. 2³¹ hundredths of a second is 248.55 days, which is why it is widely taken to be a signed 32-bit count of centiseconds.
  • Gangnam Style on YouTube (int32): In December 2014 YouTube said Psy’s Gangnam Style had been watched so many times, closing in on 2,147,483,647 views, the largest signed 32-bit integer, that it had upgraded the view counter to a 64-bit integer.
  • Windows 95 and 98 after 49.7 days (uint32): Microsoft documented that Windows 95 and 98 could stop responding after exactly 49.7 days of continuous running, a fault in their timing code. 2³² milliseconds is 49.71 days, the point where a 32-bit count of milliseconds runs out.
  • Unsigned Unix time (uint32): Stored as unsigned 32 bits, Unix time runs out later than the signed 2038 limit: the last second is 2106-02-07 06:28:15 UTC. The price is that dates before 1970 cannot be written at all.
  • 64-bit Unix time (int64): With a signed 64-bit count of seconds, Unix time lasts about 292 billion years either side of 1970, which is why moving to 64 bits settles the 2038 problem for good.

Common mistakes

  • Negating −2,147,483,648 or taking its absolute value (int32): The exact answer, 2,147,483,648, is one past the maximum of 2,147,483,647, so once it is stored as int32 it wraps back to −2,147,483,648: −x and abs(x) of the minimum stay negative wherever the result wraps, and in C and C++ the overflow is undefined behaviour.
  • Counting down to zero with an unsigned counter (uint32): A loop such as for (i = n; i >= 0; i--) never ends when i is uint32: i >= 0 is always true, and 0 − 1 wraps to 4,294,967,295. Test i > 0 and use i − 1 inside, or use a signed counter.
  • Comparing signed with unsigned in C (uint32): -1 < x is false when x is a uint32_t, even when x is 0: the −1 is converted to uint32 first and becomes 4,294,967,295 (on platforms where int is 32 bits).
  • Finding a midpoint as (low + high) / 2 (int32): When low and high are both 1,073,741,824 or more, just over half the maximum, their sum overflows int32. low + (high − low) / 2 gives the same midpoint without the overflow.
  • Sending 64-bit IDs through JSON to JavaScript (int64): JSON.parse turns every number into a double, which is exact only up to 2⁵³ − 1. An ID of 9,007,199,254,740,993 arrives as 9,007,199,254,740,992. Send large IDs as strings.
  • Reading Java bytes as 0 to 255 (int8): Java’s byte is signed, so a byte holding 0xFF reads as −1. Use b & 0xFF or Byte.toUnsignedInt(b) to get 255.
  • Multiplying two uint16_t values in C (uint16): Both are promoted to signed int first, so 65,535 × 65,535 = 4,294,836,225 overflows a 32-bit int (maximum 2,147,483,647), which is undefined behaviour. Cast one operand to uint32_t before multiplying.

Each type in detail

Questions

What is the maximum value of an int?

In Java, C# and Kotlin an int is 32 bits, so its maximum is 2,147,483,647 (2³¹ − 1) and its minimum −2,147,483,648. C and C++ only promise that int is at least 16 bits, though it is 32 on every common desktop and phone platform. Python’s int has no maximum.

What is the formula for the range of an n-bit integer?

A signed two’s complement integer of n bits holds −2ⁿ⁻¹ to 2ⁿ⁻¹ − 1. An unsigned one holds 0 to 2ⁿ − 1. Both have 2ⁿ distinct values; the signed type just spends half of them on negative numbers.

Why is the maximum 2ⁿ − 1 and not 2ⁿ?

Because zero needs a pattern too. n bits make 2ⁿ patterns, and counting from 0 the last one is 2ⁿ − 1. Eight bits all set to 1 are 255, not 256, and 256 needs a ninth bit.

What happens when an integer overflows?

The processor keeps the low n bits of the result and drops the carry, so the value wraps around: 2,147,483,647 + 1 in a 32-bit int becomes −2,147,483,648. Java, Go, Kotlin and C# do exactly that by default. C and C++ treat signed overflow as undefined behaviour, Rust panics in debug builds, Swift stops the program, and Python’s ints never overflow at all. Below 32 bits, C, Java, C# and Kotlin do the arithmetic in int, so 127 + 1 on an 8-bit value is 128 until it is stored back into the 8-bit variable; Go, Rust and Swift work at the narrow width itself.

What is the largest integer JavaScript can hold exactly?

Number.MAX_SAFE_INTEGER, 9,007,199,254,740,991 or 2⁵³ − 1. JavaScript numbers are 64-bit floats with a 53-bit significand, so past that not every whole number exists: 2⁵³ + 1 rounds to 2⁵³. BigInt has no such limit, and BigInt64Array stores true 64-bit integers.

Which integer type should I use?

The smallest type whose range covers every value the data can take, with room to spare for anything that grows, such as counters, IDs and timestamps. A signed 32-bit count of seconds since 1970 runs out in 2038, so time and ever-growing IDs belong in 64 bits. Type a number into the lookup above to see which types hold it.