정수 오버플로와 BigInt: 언어별 안전한 한계

INT_MAX + 1 을 C·Java·C#·Swift·Dart·PHP·파이썬에서 실행해 비교합니다. JSON.parse 가 19자리 ID 를 바꾸는 이유, 문자열·BigInt 해법, SQLite 한계까지 확인합니다.

시리즈: 숫자·금액 계산 강좌 2/6 (초급). 금액, 카운터, ID 를 정수로 저장하면서 "정수는 실수와 달리 항상 정확하다" 고 생각하는 신입 개발자를 위한 글입니다. 다 읽으면 언어마다 정수가 얼마나 큰지, 한계를 넘으면 무슨 일이 일어나는지, 19자리 ID 를 JSON 과 자바스크립트에서 자릿수를 잃지 않고 다루는 법을 알게 됩니다.

1회에서는 실수가 근삿값이라는 것을 봤습니다. 정수는 정확하지만 범위 안에서만 그렇고, 끝에서 벌어지는 일은 언어마다 전혀 다릅니다. C 는 정의되지 않은 동작, 자바는 조용히 한 바퀴, Swift 는 프로그램을 멈추고, PHP 는 float 로 바뀌고, 자바스크립트는 조용히 반올림합니다. 원화는 소수 단위가 없어서 금액을 정수로 다루는 게 당연한데, 32비트 int 에 들어가는 건 약 21억 4748만까지입니다. 직원 1,500명에게 월 200만 원씩 주는 회사의 급여 합계 30억 원도 들어가지 않습니다. 주문 시스템, 결제 API, 몇 년씩 도는 카운터, DB ID 를 JSON 으로 받는 프런트엔드를 만든다면 이 중 하나는 꼭 만납니다. 아래는 모두 Apple Silicon Mac(M1 Pro), macOS 26 에서 Apple clang 21, OpenJDK 26, .NET 10(SDK 10.0.403), Swift 6.4.2, Dart 3.11.5, PHP 8.5.6, Python 3.9.6 과 3.12.14, JavaScriptCore jsc, sqlite 3.51.0 으로 실행했습니다. 경로는 ~/demo/ 로 바꿨습니다.

5분 만에 첫 오버플로

월급 2,000,000원 × 1,500명 = 3,000,000,000원(30억 원)입니다. first_ov.c 로 저장합니다.

#include <stdio.h>
int main(void) {
    int price = 2000000;
    int qty = 1500;
    int total = price * qty;
    printf("total = %d\n", total);
    long long ok = (long long)price * qty;
    printf("ok    = %lld\n", ok);
    return 0;
}
$ clang -std=c17 -Wall -Wextra -o first_ov first_ov.c && ./first_ov
total = -1294967296
ok    = 3000000000

컴파일 경고도 크래시도 없이 합계가 음수가 될 뿐입니다. 이 Mac 에서 C 의 int 는 32비트라 -2,147,483,648 부터 2,147,483,647(21억 4748만 3647)까지만 담습니다. 30억은 들어가지 않고, 남은 비트를 읽으면 -1,294,967,296 이 됩니다. 계산 결과가 타입의 범위를 넘는 것을 정수 오버플로라고 합니다.

해법은 곱셈을 넓은 타입에서 하는 것입니다. (long long)price * qty 는 곱하기 전에 한쪽을 64비트로 바꿉니다. long long total = price * qty; 는 늦습니다. 곱셈은 이미 32비트에서 끝났습니다.

-fsanitize=undefined(UBSan, 정의되지 않은 동작 검사기)를 붙이면 clang 이 정확한 줄을 알려 줍니다.

$ clang -std=c17 -Wall -Wextra -fsanitize=undefined -o first_ov_ub first_ov.c && ./first_ov_ub
first_ov.c:5:23: runtime error: signed integer overflow: 2000000 * 1500 cannot be represented in type 'int'
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior first_ov.c:5:23
total = -1294967296
ok    = 3000000000

정수는 얼마나 큰가: 언어별 크기

언어 기본 정수 범위 더 큰 것
C (clang, macOS arm64) int 32비트 ±약 21억 long / long long 64비트(여기서 sizeof 8, 8)
Java int 32비트 ±약 21억 long 64비트, BigInteger
C# int 32비트 ±약 21억 long 64비트, decimal, BigInteger
Swift Int (64비트 플랫폼에서 64비트) ±약 922경 Int64, 기본 큰 정수 없음
Dart (네이티브) int 64비트 ±약 922경 BigInt
Dart (자바스크립트로 변환) int 가 JS 숫자 2^53 까지 정확 BigInt
PHP int 64비트(PHP_INT_SIZE 8) ±약 922경 bcmath, gmp
Python int 제한 없음 필요 없음
JavaScript Number(double) 2^53 - 1 까지 정확 BigInt
SQLite INTEGER 최대 8바이트 ±약 922경 TEXT 로 저장

외워 둘 숫자는 둘입니다. 2,147,483,647(2^31 - 1, 21억 4748만 3647, 32비트 한계)과 9,007,199,254,740,991(2^53 - 1, 약 9007조, double 이 빈틈없이 담는 가장 큰 정수). 64비트 한계는 9,223,372,036,854,775,807(약 922경)입니다.

한계를 넘으면: 7개 언어 비교

모든 언어에서 MAX + 1 과 2,000,000 × 1,500 을 계산했습니다. 출력은 실행 결과 그대로입니다.

C: 부호 있는 정수 오버플로는 정의되지 않은 동작(UB)입니다. 표준이 결과를 정하지 않고, 최적화기는 "일어나지 않는다" 고 가정해도 됩니다. 이 Mac 에서는 INT_MAX + 1 이 -2147483648 이었지만 우연이지 규칙이 아닙니다(-O2 에서 결과가 달라지는 루프는 C 정의되지 않은 동작과 최적화 참고). 부호 없는 오버플로는 정의돼 있어서 UINT_MAX + 1 은 0 이었습니다. UB 없이 확인하려면 clang/gcc 내장 함수 __builtin_add_overflow(a, 1, &r) 를 쓰고, INT_MAX 에서 참을 돌려줬습니다. -fno-sanitize-recover=all 을 붙이면 UBSan 이 첫 보고에서 프로그램을 멈추고, 종료 상태는 134 였습니다.

Java: 언제나 조용히 한 바퀴 돕니다.

a + 1 = -2147483648
price * qty = -1294967296
long wrong = -1294967296          // long wrong = price * qty;
long right = 3000000000           // long right = (long) price * qty;
Math.abs(Integer.MIN_VALUE) = -2147483648
java.lang.ArithmeticException: integer overflow     // Math.addExact(a, 1)
java.lang.ArithmeticException: integer overflow     // Math.multiplyExact(price, qty)

가장 작은 int 의 Math.abs 는 여전히 음수입니다. +2,147,483,648 은 int 에 없기 때문입니다. *Exact 메서드(Java 8 이후)가 안전한 버전입니다.

C#: 기본은 한 바퀴 돌고, checked 로 오버플로를 예외로 바꿀 수 있습니다. 상수는 컴파일할 때 검사됩니다.

price * qty = -1294967296
OverflowException: Arithmetic operation resulted in an overflow.     // checked(price * qty)
Program.cs(1,9): error CS0220: The operation overflows at compile time in checked mode

마지막 줄은 int x = int.MaxValue + 1; 의 컴파일 오류입니다. SDK 메시지는 OS 언어 설정에 따라 번역돼 나올 수 있으니 검색할 때는 코드 CS0220 으로 찾는 게 확실합니다. 영어로 보려면 DOTNET_CLI_UI_LANGUAGE=en dotnet build 로 실행합니다(위 줄도 그렇게 얻었습니다). .csproj 에 <CheckForOverflowUnderflow>true</CheckForOverflowUnderflow> 를 넣으면 프로젝트 전체가 검사 모드가 됩니다. dotnet new console 로 갓 만든 프로젝트에는 없습니다.

Swift: 오버플로가 나면 트랩, 즉 일부러 프로그램을 멈춥니다. 상수면 컴파일조차 안 됩니다.

ovc.swift:1:26: error: arithmetic operation '2147483647 + 1' (on type 'Int32') results in an overflow

실행 중에 정해지는 값이면 about to multiply 를 출력한 뒤 종료 상태 133(128 + 시그널 5, SIGTRAP)으로 끝났습니다. -Onone 이든 -O 든 같았습니다. 한 바퀴 돌기를 원하면 명시합니다. a &+ 1 은 -2147483648, a.addingReportingOverflow(1) 은 (-2147483648, true) 였습니다.

Dart: 어디서 돌리느냐에 따라 다릅니다. Dart VM 에서 int 는 64비트로 한 바퀴 돌아서 9223372036854775807 + 1 이 -9223372036854775808 이었습니다. dart compile js 로 자바스크립트로 바꾸면 int 가 JS 숫자가 되므로 표현할 수 없는 리터럴은 컴파일러가 거부합니다.

Error: The integer literal 9007199254740993 can't be represented exactly in JavaScript.

int.parse 로 읽은 값이면, 변환된 코드를 (브라우저가 아니라 jsc 로) 실행했을 때 64비트 최댓값은 9223372036854776000, 2^53 + 1 은 9007199254740992 가 됐고 identical(1, 1.0) 은 true 가 됐습니다. 같은 소스인데 숫자가 달라집니다. Flutter 웹은 따로 테스트하세요.

PHP: 넘친 int 는 float 가 됩니다.

var_dump(PHP_INT_MAX + 1);            float(9.223372036854776E+18)
var_dump(PHP_INT_MAX + 1 == PHP_INT_MAX);   bool(true)
(int)(PHP_INT_MAX + 1)  -> Warning: The float 9.223372036854776E+18 is not representable as an int, cast occurred
                           int(-9223372036854775808)
intdiv(PHP_INT_MIN, -1) -> Fatal error: Uncaught ArithmeticError: Division of PHP_INT_MIN by -1 is not an integer

오류는 없지만 float 정밀도는 53비트라 PHP_INT_MAX + 1 == PHP_INT_MAX 가 참입니다. int 로 되돌리는 캐스트는 8.5.6 에서 경고를 냈습니다. 옛 버전에서도 나오는지는 시험하지 않았습니다. bcadd("9223372036854775807", "1") 와 gmp_add 는 둘 다 정확히 9223372036854775808 을 출력했습니다.

Python: 정수가 넘치지 않습니다. (2**63 - 1) + 1 은 9223372036854775808, 2**64 * 2**64 는 39자리를 모두 출력했습니다. 한계는 고정 크기 세계로 넘길 때 나옵니다. struct.pack('<i', 2**31) 은 struct.error: 'i' format requires -2147483648 <= number <= 2147483647, (2**64).to_bytes(8, 'little') 은 OverflowError: int too big to convert 였습니다.

MAX + 1 판단 흐름도. 고정 크기 정수가 아니면 커지거나 타입이 바뀐다: 파이썬 int 는 늘어나고, PHP int 는 float 가 되며, 자바스크립트 Number 는 2 의 53 제곱을 넘으면 반올림된다. 고정 크기이고 검사하는 연산이면 프로그램이 멈춘다: Swift 기본 연산자는 종료 상태 133 으로 트랩하고, Java Math.addExact 와 C# checked 는 예외를 던진다. 검사가 없고 C 의 부호 있는 int 면 정의되지 않은 동작이고 UBSan 이 보고한다. 그 밖에는 조용히 한 바퀴 돈다: Java, C#, VM 위의 Dart, Swift &+, C unsigned.
실행한 환경마다 MAX + 1 이 어떻게 됐는지. 동작은 네 가지이고, 멈춰 주는 것은 하나뿐이다.

자바스크립트: MAX_SAFE_INTEGER 와 자릿수가 바뀌는 ID

자바스크립트 Number 는 double(1회)입니다. 53비트 가수로 2^53 까지의 정수는 모두 정확하지만, 그 위로는 double 사이 간격이 2, 4, 8… 로 벌어집니다.

$ jsc safe.js
9007199254740991 true              // Number.MAX_SAFE_INTEGER, === 2**53 - 1
9007199254740992 9007199254740992 true   // 2**53 과 2**53 + 1 이 같다
true false                         // Number.isSafeInteger(2**53 - 1), (2**53)
9007199254740992 9007199254740992 9007199254740994 9007199254740996 9007199254740996   // 2**53 + 0..4

이게 가장 아픈 곳은 ID 입니다. 64비트 자동 증가 키나 분산 시스템의 Snowflake 방식 ID 는 2^53 을 넘습니다. 서버는 올바른 JSON 을 보냈는데 브라우저의 JSON.parse 가 조용히 값을 바꿉니다.

const body = '{"id": 1234567890123456789, "order_id": 9007199254740993, "sid": "1234567890123456789"}';
const o = JSON.parse(body);
print(o.id, o.order_id, o.sid);
print(JSON.stringify(o));
1234567890123456800 9007199254740992 1234567890123456789
{"id":1234567890123456800,"order_id":9007199254740992,"sid":"1234567890123456789"}

ID 는 11, 주문 ID 는 1 어긋났고 오류는 하나도 없습니다. 클라이언트가 그 ID 를 되돌려 보내면 다른 행을 고치거나 아무것도 못 고칩니다. 문자열인 sid 는 무사했습니다. 파이썬 json.loads 와 PHP 8.5 json_decode 는 정수가 크기 때문에 9007199254740993 을 제대로 읽습니다. PHP 는 64비트를 넘는 12345678901234567890 을 float(1.2345678901234567E+19) 로 만들고, JSON_BIGINT_AS_STRING 을 주면 string(20) "12345678901234567890" 이 됐습니다. 서버 쪽 비슷한 함정은 PHP prepared statement 가 JSON 숫자 타입을 바꾸는 이야기에 있습니다.

해법(우선순위 순):

  1. ID 는 문자열로 보낸다. API 가 "id": "1234567890123456789" 를 돌려줍니다. ID 는 이름표이지 더할 수량이 아닙니다. 어떤 클라이언트에서도 됩니다.
  2. 계산이 필요하면 BigInt. BigInt("1234567890123456789") + 1n 은 1234567890123456790 이었습니다. BigInt 에는 고유한 규칙이 있고, jsc 에서 확인했습니다.
1n + 1                 TypeError: Invalid mix of BigInt and other type in addition.
JSON.stringify({x:10n})  TypeError: JSON.stringify cannot serialize BigInt.
Math.sqrt(16n)         TypeError: Conversion from 'BigInt' to 'number' is not allowed.
  1. 파싱하면서 원문을 읽는다. 새 엔진에서는 JSON.parse reviver 에 각 숫자의 원문이 전달되고, JSON.rawJSON 으로 BigInt 를 숫자 그대로 써낼 수 있습니다. 이 Mac 의 jsc 에서 둘 다 동작했습니다.
const r = JSON.parse(body, (k, v, ctx) => k === 'id' ? BigInt(ctx.source) : v);
print(String(r.id), typeof r.id);                                // 1234567890123456789 bigint
print(JSON.stringify({ id: JSON.rawJSON(r.id.toString()) }));    // {"id":1234567890123456789}

이 두 기능은 언어에 최근 들어온 것입니다. 지원해야 하는 모든 브라우저와 Node.js 버전에 있는지 확인하고 쓰세요(실행한 건 jsc 뿐입니다). 1번 방법에는 이런 주의가 필요 없습니다.

조용한 32비트 벽이 하나 더 있습니다. 비트 연산자는 32비트 정수로 바꿉니다. (2147483647 + 1) | 0 은 -2147483648, Math.imul(2000000, 1500) 은 -1294967296 이었습니다. Number 와 BigInt 는 자바스크립트 성능과 숫자에서 더 다룹니다.

데이터베이스: SQLite INTEGER 의 한계

SQLite INTEGER 는 부호 있는 64비트입니다. 한계에서 세 가지로 다르게 움직입니다.

sqlite> SELECT 9223372036854775807 + 1, typeof(9223372036854775807 + 1);
9.22337203685478e+18|real
sqlite> SELECT sum(x) FROM (SELECT 9223372036854775807 AS x UNION ALL SELECT 1);
Runtime error near line 4: integer overflow
sqlite> SELECT total(x) FROM (SELECT 9223372036854775807 AS x UNION ALL SELECT 1);
9.22337203685478e+18

+ 는 조용히 float 로 바뀌고, sum() 은 오류, total() 은 항상 float 를 돌려줍니다. INTEGER 열에 12345678901234567890 을 넣으면 real 로 저장됐고, 따옴표로 감싼 같은 숫자도 열이 정수 친화성(affinity)이라 real 이 됐습니다. 64비트를 넘는 값은 TEXT 열에 넣습니다.

기본 키가 한계에 닿으면:

sqlite> CREATE TABLE t(id INTEGER PRIMARY KEY, n INTEGER);
sqlite> INSERT INTO t(id, n) VALUES (9223372036854775807, 1);
sqlite> INSERT INTO t(n) VALUES (2);
sqlite> SELECT * FROM t;
712334064962770860|2
9223372036854775807|1

가장 큰 rowid 가 쓰였으면 SQLite 는 비어 있는 값을 무작위로 고릅니다. 재사용도 역행도 하지 않겠다고 약속하는 AUTOINCREMENT 에서는 같은 삽입이 Error: stepping, database or disk is full (13) 로 실패했습니다. 하나씩 세어서 922경에 닿을 일은 없지만, 누가 거대한 ID 를 손으로 넣으면 닿습니다. SQL 기초는 SELECT·WHERE·ORDER BY를 보세요.

흔한 실수와 타입 고르기

실수 실제로 일어나는 일 고치는 법
int a, b 로 long long t = a * b;(자바 long t = a * b 도) 먼저 32비트로 곱해서 넘침: -1294967296 한쪽을 넓힌다: (long long)a * b
밀리초를 int 로 센다 2^31 밀리초는 약 24.8일 64비트로
음수가 아니게 하려는 Math.abs(x) Math.abs(Integer.MIN_VALUE) 는 -2147483648 최솟값을 확인하거나 long 으로
JS 클라이언트에 숫자 ID 를 JSON 으로 1234567890123456789 가 1234567890123456800 으로 도착 ID 는 문자열로 보낸다
BigInt 와 Number 섞기 TypeError: Invalid mix of BigInt and other type 명시적으로 바꾸고 값마다 타입 하나만
2^63 을 넘어도 PHP int 연산을 믿기 조용히 float 가 되고 == PHP_INT_MAX 가 참 bcmath 나 gmp
Dart 코드 하나를 VM 과 웹에서 공유 웹에서 9223372036854775807 이 9223372036854776000 2^53 미만으로 유지하거나 BigInt

타입 고르기:

저장하는 것 쓸 타입 피할 타입
개수, 수량, 약 9×10^15 미만의 최소 통화 단위(원·센트) 64비트 정수(long, Int, PHP/Dart VM int, INTEGER) 합계가 커질 수 있으면 32비트 int
DB 나 다른 서비스의 ID JSON 과 JS 에서는 문자열, 서버에서는 64비트 정수 JS Number
2^63 을 넘어 계산해야 하는 정수 BigInteger, 파이썬 int, BigInt, gmp float
조용히 넘치면 안 되는 값 자바 *Exact, C# checked, Swift 기본 연산자, __builtin_*_overflow C/Java/C# 의 맨 +

돈(센트, decimal 형, 10원 단위 절사)은 4회와 3회에서 다룹니다. 타입 기초는 자바 타입과 PHP 타입에 있습니다.

측정: JSON.parse 를 무사히 통과하는 ID 비율과 BigInt 비용

JSON.parse 를 멀쩡히 통과하는 ID 는 얼마나 되나? 다섯 범위마다 파이썬(random.seed(7))으로 무작위 정수 100,000개를 만들어 JSON 숫자와 문자열 두 가지로 쓰고, jsc 에서 읽어 숫자를 문자열과 BigInt 로 비교했습니다.

막대그래프. 2 의 53 제곱 − 1 까지는 100% 가 그대로다. 2^53~2^54 는 49.99%, 2^54~2^56 은 16.72%, Snowflake 크기인 2^59~2^61 은 0.53%, 19 자리인 10^18~2^63 은 0.19% 였다.
범위마다 무작위 정수 100,000 개 중 jsc 의 JSON.parse 를 거쳐도 그대로인 비율. seed 7. 각 값은 문자열 버전과 BigInt 로 비교했다.
범위 무사한 개수 최대 오차
2^53 - 1 이하 100,000 (100%) 0
2^53 ~ 2^54 49,994 (49.99%) 1
2^54 ~ 2^56 16,718 (16.72%) 4
2^59 ~ 2^61 (Snowflake 크기) 526 (0.53%) 128
10^18 ~ 2^63 (19자리) 189 (0.19%) 512

2^53 을 넘으면 무사한 건 간격의 배수에 우연히 걸린 ID 뿐입니다. 19자리 ID 는 99.8% 가 최대 512 어긋나서 나옵니다.

BigInt 비용은? jsc 에서 0~9,999,999 합계, Apple Silicon Mac(M1 Pro), 7회 중앙값으로 Number 3.2 ms, BigInt 301.3 ms 였고 결과는 둘 다 49999995000000 이었습니다. JIT 가 Number 루프를 아주 잘 최적화하므로 약 94배라는 차이는 상한 정도로 보고 상수로 여기지 마세요. 파이썬 임의 길이 int 로 1,000,000개를 누적한 시간(7회 중앙값):

시작 값 Python 3.9.6 Python 3.12.14
0 27.7 ms 26.6 ms
2**64 28.1 ms 26.9 ms
2**256 30.6 ms 29.0 ms
2**4096 141.8 ms 138.0 ms

큰 정수가 공짜는 아니지만 수백 비트까지는 파이썬이 거의 티를 내지 않습니다. BigInt 는 필요한 곳에만 쓰면 됩니다.

솔직한 한계와 버전 메모

  • C 정수 크기는 macOS arm64 의 clang 기준입니다. 64비트 Windows 에서는 long 이 32비트입니다(여기서 실행하지 않음).
  • C 부호 있는 오버플로 결과는 이 컴파일러가 -O0 에서 낸 값입니다. 표준은 아무것도 보장하지 않습니다.
  • Swift 트랩은 캡처한 출력에 메시지 없이 종료 상태 133 만 남았습니다. Xcode 디버거에서는 더 보입니다(여기서 실행하지 않음).
  • JSON.parse 원문 접근과 JSON.rawJSON 은 이 Mac 의 jsc 에서만 확인했습니다. 파이썬 4,300자리 제한은 3.12.14 에서 ValueError: Exceeds the limit (4300 digits) for integer string conversion 이 났고, 3.9.6 에서는 5,001자리를 출력했습니다. 제한은 3.9.14 부터 들어갔습니다.
  • Dart 에서 변환한 자바스크립트는 jsc 에서 실행했고 브라우저에서는 시험하지 않았습니다. Node.js 도 실행하지 않았습니다.
  • 시간은 한 대에서 잰 값입니다. 비율을 보세요.

연습 문제

1. 자바에서 3000000000 을 출력하는 것은 어느 것인가요?

int price = 2_000_000, qty = 1500;
long a = price * qty;
long b = (long) price * qty;
long c = (long) (price * qty);

2. API 가 {"id": 9007199254740993} 을 돌려주고, 웹 클라이언트는 그 ID 를 되돌려 보내 레코드를 지웁니다. jsc 에서 ID 는 무엇이 되고, API 는 어떻게 바꿔야 할까요?

3. 파이썬에서 x = 2**31 은 문제없습니다. 같은 값이 오류가 나는 곳을 하나 들고 오류 메시지를 적어 보세요.

정답

1. b 뿐입니다. 실행 결과는 a b c 순서로 -1294967296 3000000000 -1294967296 이었습니다. a 와 c 는 둘 다 먼저 32비트로 곱하고, c 의 캐스트는 오버플로 뒤에 일어납니다.

2. JSON.parse 결과는 1 작은 9007199254740992 여서 클라이언트는 ...993 이 아니라 ...992 를 지우려 합니다. ID 를 "id": "9007199254740993" 처럼 문자열로 돌려주고 클라이언트에서도 문자열로 다룹니다.

3. struct.pack('<i', 2**31) 이 struct.error: 'i' format requires -2147483648 <= number <= 2147483647 를 냈습니다. 바이너리 파일 형식, C 라이브러리, 32비트 DB 열에 쓸 때도 같은 일이 생깁니다.

다음 회

3회는 반올림입니다. 파이썬 round(2.5) 가 왜 2 인지, toFixed 가 실제로 무엇을 하는지, 부가세를 품목마다 계산하느냐 합계에서 계산하느냐에 따라 결과가 어떻게 달라지는지 봅니다.

자주 묻는 질문

JSON.parse 를 거치면 ID 뒷자리가 바뀌는 이유는?

자바스크립트 숫자는 double 이라서 모든 정수를 정확히 담는 건 2^53 - 1(Number.MAX_SAFE_INTEGER, 9007199254740991)까지입니다. 그 위로는 가장 가까운 double 이 선택됩니다. jsc 에서 1234567890123456789 는 1234567890123456800, 9007199254740993 은 9007199254740992 가 됐습니다. 큰 ID 는 JSON 문자열로 보내고 계산이 필요할 때만 BigInt 로 바꿉니다.

자바나 C# 에서 int 가 넘치면 어떻게 되나요?

기본적으로 둘 다 조용히 한 바퀴 돕니다. Integer.MAX_VALUE + 1 은 -2147483648, 2,000,000 × 1,500 은 -1294967296 이 나왔습니다. 자바 Math.addExact, Math.multiplyExact 는 ArithmeticException: integer overflow 를 던지고, C# 은 checked(...) 안이나 CheckForOverflowUnderflow 를 켰을 때 OverflowException 을 던집니다.

파이썬 정수도 오버플로가 나나요?

나지 않습니다. 필요한 만큼 자릿수가 늘어나서 (2**63 - 1) + 1 은 9223372036854775808 로 출력됐습니다. 한계는 바깥 세계와 만나는 곳에서 나옵니다. struct.pack('<i', 2**31) 은 struct.error 가 나고, 2022년 보안 릴리스(3.11, 3.10.7, 3.9.14 이후)부터는 4,300자리가 넘는 int 를 문자열로 바꾸면 기본적으로 ValueError 가 납니다.

  • #숫자 계산
  • #초급
  • #정수 오버플로
  • #BigInt
  • #JSON
  • #자바스크립트

t.laboratory

직접 만들고 운영하는 앱·서버·서비스에서 겪은 문제와, 그 해결에 쓴 코드를 기록하는 기술 블로그입니다.

운영자 소개 · 앱

↑