자바스크립트의 BigInt 타입에 대한 종합 가이드로, 기능, 사용법, 큰 정수 연산 처리에서의 활용 사례를 다룹니다. 자바스크립트의 한계를 극복하고 정밀하게 복잡한 계산을 수행하는 방법을 배워보세요.
JavaScript BigInt: 큰 정수 연산 마스터하기
자바스크립트는 다재다능한 언어이지만, 매우 큰 정수를 다룰 때 한계가 있습니다. 표준 `Number` 타입은 `Number.MAX_SAFE_INTEGER`로 알려진 특정 한계까지만 정수를 정확하게 표현할 수 있습니다. 이 한계를 넘어서면 계산이 부정확해져 예상치 못한 결과를 초래할 수 있습니다. 바로 이 지점에서 BigInt
가 해결사로 등장합니다. ECMAScript 2020에 도입된 BigInt
는 표준 `Number` 타입의 한계를 뛰어넘어 임의의 크기의 정수를 표현하고 조작할 수 있는 방법을 제공하는 내장 객체입니다.
BigInt의 필요성 이해하기
BigInt
이전에는 자바스크립트 개발자들이 큰 정수 계산을 처리하기 위해 라이브러리나 사용자 정의 구현에 의존해야 했습니다. 이러한 해결책들은 종종 성능 오버헤드와 복잡성 증가를 동반했습니다. BigInt
의 도입은 큰 정수를 다룰 수 있는 네이티브하고 효율적인 방법을 제공하여 다음과 같은 다양한 분야에서의 활용 가능성을 열었습니다:
- 암호학: 암호화 알고리즘에서 큰 소수를 안전하게 처리하는 것은 매우 중요합니다.
- 금융 계산: 정밀도 손실 없이 큰 금액을 정확하게 표현합니다.
- 과학 컴퓨팅: 극도로 크거나 작은 숫자를 포함하는 복잡한 계산을 수행합니다.
- 고정밀 타임스탬프: 나노초 단위의 정밀도로 타임스탬프를 표현합니다.
- ID 생성: 고유하고 매우 큰 식별자를 생성합니다.
BigInt 값 생성하기
자바스크립트에서 BigInt
값을 만드는 주된 방법은 두 가지가 있습니다:
- `BigInt()` 생성자 사용: 이 생성자는 숫자, 문자열 또는 불리언 값을
BigInt
로 변환할 수 있습니다. - `n` 접미사 사용: 정수 리터럴에 `n`을 추가하여
BigInt
를 생성합니다.
예제:
`BigInt()` 생성자 사용:
const bigIntFromNumber = BigInt(12345678901234567890);
const bigIntFromString = BigInt("98765432109876543210");
const bigIntFromBoolean = BigInt(true); // 결과는 1n
const bigIntFromFalseBoolean = BigInt(false); // 결과는 0n
console.log(bigIntFromNumber); // 출력: 12345678901234567890n
console.log(bigIntFromString); // 출력: 98765432109876543210n
console.log(bigIntFromBoolean); // 출력: 1n
console.log(bigIntFromFalseBoolean); // 출력: 0n
`n` 접미사 사용:
const bigIntLiteral = 12345678901234567890n;
console.log(bigIntLiteral); // 출력: 12345678901234567890n
중요 참고사항: 산술 연산에서 BigInt
와 Number
값을 직접 혼합하여 사용할 수 없습니다. 계산을 수행하기 전에 명시적으로 같은 타입으로 변환해야 합니다. 직접 혼합하려고 하면 `TypeError`가 발생합니다.
BigInt 산술 연산
BigInt
는 다음을 포함한 대부분의 표준 산술 연산자를 지원합니다:
- 덧셈 (`+`)
- 뺄셈 (`-`)
- 곱셈 (`*`)
- 나눗셈 (`/`)
- 나머지 (`%`)
- 거듭제곱 (`**`)
예제:
const a = 12345678901234567890n;
const b = 98765432109876543210n;
const sum = a + b;
const difference = a - b;
const product = a * b;
const quotient = a / 2n; // 참고: 나눗셈은 0을 향해 소수점 이하를 버립니다
const remainder = a % 7n;
const power = a ** 3n; // 거듭제곱은 예상대로 작동합니다
console.log("Sum:", sum); // 출력: Sum: 111111111011111111100n
console.log("Difference:", difference); // 출력: Difference: -86419753208641975320n
console.log("Product:", product); // 출력: Product: 1219326311370217957951669538098765432100n
console.log("Quotient:", quotient); // 출력: Quotient: 6172839450617283945n
console.log("Remainder:", remainder); // 출력: Remainder: 5n
console.log("Power:", power); // 출력: Power: 187641281029182300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000n
중요 고려사항:
- 나눗셈:
BigInt
값의 나눗셈은 0을 향해 소수점 이하를 버립니다. 즉, 결과의 소수 부분은 버려집니다. 더 정밀한 나눗셈이 필요하다면, 임의 정밀도 산술을 지원하는 라이브러리를 사용하는 것을 고려해보세요. - 단항 플러스 연산자 (+): 단항 플러스 연산자(+)는 레거시 asm.js 코드와 충돌할 수 있기 때문에
BigInt
값과 함께 사용할 수 없습니다. BigInt를 Number로 변환해야 할 경우(정밀도를 잃을 수 있다는 점을 인지하고) `Number()` 변환 함수를 사용하세요. - 비트 연산자:
BigInt
는 `&`, `|`, `^`, `~`, `<<`, `>>`와 같은 비트 연산자도 지원합니다. 이 연산자들은BigInt
값의 이진 표현에 대해 예상대로 작동합니다.
비교 연산자
표준 비교 연산자(`==`, `!=`, `<`, `>`, `<=`, `>=`)를 사용하여 BigInt
값을 다른 BigInt
값이나 심지어 Number
값과도 비교할 수 있습니다. 하지만, 타입 강제 변환의 가능성에 유의해야 합니다.
예제:
const a = 10n;
const b = 20n;
const c = 10;
console.log(a == b); // 출력: false
console.log(a != b); // 출력: true
console.log(a < b); // 출력: true
console.log(a > b); // 출력: false
console.log(a <= b); // 출력: true
console.log(a >= b); // 출력: false
console.log(a == c); // 출력: true (타입 강제 변환)
console.log(a === c); // 출력: false (타입 강제 변환 없음)
권장 사항: BigInt
와 Number
값을 비교할 때 예상치 못한 타입 강제 변환을 피하기 위해 엄격한 동등성(`===`)과 엄격한 부등성(`!==`)을 사용하세요.
BigInt와 Number 간 변환
BigInt
와 Number
간의 직접적인 산술 연산은 허용되지 않지만, 두 타입 간에 변환할 수는 있습니다. 그러나 BigInt
값이 `Number.MAX_SAFE_INTEGER`를 초과하는 경우 BigInt
를 Number
로 변환할 때 정밀도 손실이 발생할 수 있다는 점에 유의해야 합니다.
예제:
const bigIntValue = 9007199254740991n; // Number.MAX_SAFE_INTEGER
const numberValue = Number(bigIntValue); // BigInt를 Number로 변환
console.log(numberValue); // 출력: 9007199254740991
const largerBigIntValue = 9007199254740992n; // Number.MAX_SAFE_INTEGER 초과
const largerNumberValue = Number(largerBigIntValue);
console.log(largerNumberValue); // 출력: 9007199254740992 (부정확할 수 있음)
const numberToBigInt = BigInt(12345); // Number를 BigInt로 변환
console.log(numberToBigInt); // 출력: 12345n
사용 사례 및 예제
암호학
암호화 알고리즘은 보안을 위해 종종 매우 큰 소수에 의존합니다. BigInt
는 이러한 숫자들을 효율적으로 표현하고 조작하는 방법을 제공합니다.
// 예제: 간단한 (안전하지 않은) 키 쌍 생성
function generateKeyPair() {
const p = 281n; // 소수
const q = 283n; // 또 다른 소수
const n = p * q; // 모듈러스
const totient = (p - 1n) * (q - 1n); // 오일러의 토션트 함수
// 1 < e < totient 이고 gcd(e, totient) = 1인 e(공개 지수)를 선택
const e = 17n;
// (d * e) % totient = 1이 되는 d(개인 지수)를 계산
let d = 0n;
for (let i = 1n; i < totient; i++) {
if ((i * e) % totient === 1n) {
d = i;
break;
}
}
return {
publicKey: { n, e },
privateKey: { n, d },
};
}
const keyPair = generateKeyPair();
console.log("Public Key:", keyPair.publicKey);
console.log("Private Key:", keyPair.privateKey);
참고: 이것은 시연 목적으로만 사용된 단순화된 예제입니다. 실제 암호학에서는 훨씬 더 큰 소수와 더 정교한 알고리즘을 사용합니다.
금융 계산
특히 국제 거래에서 큰 금액을 다룰 때 정밀도는 매우 중요합니다. BigInt
는 반올림 오류를 방지하고 정확한 계산을 보장할 수 있습니다.
// 예제: 복리 계산
function calculateCompoundInterest(principal, rate, time) {
const principalBigInt = BigInt(principal * 100); // 센트로 변환
const rateBigInt = BigInt(rate * 10000); // 1만분의 1 퍼센트 단위로 변환
const timeBigInt = BigInt(time);
let amount = principalBigInt;
for (let i = 0n; i < timeBigInt; i++) {
amount = amount * (10000n + rateBigInt) / 10000n;
}
const amountInDollars = Number(amount) / 100;
return amountInDollars;
}
const principal = 1000000; // 1,000,000달러
const rate = 0.05; // 5% 이자율
const time = 10; // 10년
const finalAmount = calculateCompoundInterest(principal, rate, time);
console.log("Final Amount:", finalAmount); // 출력: Final Amount: 1628894.6267774413 (대략)
이 예제에서는 계산 중 반올림 오류를 피하기 위해 원금과 이자율을 BigInt
값으로 변환합니다. 결과는 표시를 위해 다시 Number
로 변환됩니다.
큰 ID 작업하기
분산 시스템에서는 여러 서버에 걸쳐 고유 ID를 생성하는 것이 어려울 수 있습니다. BigInt
를 사용하면 충돌 가능성이 거의 없는 매우 큰 ID를 만들 수 있습니다.
// 예제: 타임스탬프와 서버 ID를 기반으로 고유 ID 생성
function generateUniqueId(serverId) {
const timestamp = BigInt(Date.now());
const serverIdBigInt = BigInt(serverId);
const random = BigInt(Math.floor(Math.random() * 1000)); // 약간의 무작위성 추가
// 값들을 결합하여 고유 ID 생성
const uniqueId = (timestamp << 20n) + (serverIdBigInt << 10n) + random;
return uniqueId.toString(); // 쉬운 처리를 위해 문자열로 반환
}
const serverId = 123; // 예제 서버 ID
const id1 = generateUniqueId(serverId);
const id2 = generateUniqueId(serverId);
console.log("Unique ID 1:", id1);
console.log("Unique ID 2:", id2);
BigInt와 JSON
BigInt
값은 기본적으로 JSON에서 지원되지 않습니다. BigInt
를 포함하는 자바스크립트 객체를 `JSON.stringify()`를 사용하여 직렬화하려고 하면 `TypeError`가 발생합니다. JSON으로 작업할 때 BigInt
값을 처리하기 위한 몇 가지 옵션이 있습니다:
- 문자열로 변환: 직렬화하기 전에
BigInt
를 문자열로 변환합니다. 이것이 가장 일반적이고 간단한 접근 방식입니다. - 사용자 정의 직렬화/역직렬화: 사용자 정의 직렬화/역직렬화 함수를 사용하여
BigInt
값을 처리합니다.
예제:
문자열로 변환:
const data = {
id: 12345678901234567890n,
name: "Example Data",
};
// 직렬화 전에 BigInt를 문자열로 변환
data.id = data.id.toString();
const jsonData = JSON.stringify(data);
console.log(jsonData); // 출력: {"id":"12345678901234567890","name":"Example Data"}
// 역직렬화할 때, 문자열을 다시 BigInt로 변환해야 함
const parsedData = JSON.parse(jsonData, (key, value) => {
if (key === "id") {
return BigInt(value);
}
return value;
});
console.log(parsedData.id); // 출력: 12345678901234567890n
사용자 정의 직렬화/역직렬화 (`replacer`와 `reviver` 사용):
const data = {
id: 12345678901234567890n,
name: "Example Data",
};
// 사용자 정의 직렬화
const jsonData = JSON.stringify(data, (key, value) => {
if (typeof value === 'bigint') {
return value.toString();
} else {
return value;
}
});
console.log(jsonData);
// 사용자 정의 역직렬화
const parsedData = JSON.parse(jsonData, (key, value) => {
if (typeof value === 'string' && /^[0-9]+$/.test(value)) { // 문자열이면서 숫자인지 확인
try {
return BigInt(value);
} catch(e) {
return value;
}
}
return value;
});
console.log(parsedData.id);
브라우저 호환성
BigInt
는 최신 브라우저에서 널리 지원됩니다. 하지만 구형 브라우저나 환경에 대한 호환성을 확인하는 것이 중요합니다. Can I use와 같은 도구를 사용하여 브라우저 지원 여부를 확인할 수 있습니다. 구형 브라우저를 지원해야 하는 경우 폴리필(polyfill) 사용을 고려할 수 있지만, 폴리필이 성능에 영향을 줄 수 있다는 점을 인지해야 합니다.
성능 고려사항
BigInt
는 큰 정수를 다루는 강력한 방법을 제공하지만, 잠재적인 성능 영향에 대해 인지하는 것이 중요합니다.
BigInt
연산은 표준Number
연산보다 느릴 수 있습니다.BigInt
와Number
간의 변환 또한 오버헤드를 유발할 수 있습니다.
따라서, 필요할 때만 BigInt
를 사용하고, 많은 수의 BigInt
연산을 수행하는 경우 성능을 위해 코드를 최적화하세요.
결론
BigInt
는 자바스크립트에 추가된 귀중한 기능으로, 개발자들이 큰 정수 연산을 정밀하게 처리할 수 있게 해줍니다. 그 기능, 한계, 사용 사례를 이해함으로써, 암호학, 금융 계산, 과학 컴퓨팅 등 다양한 분야에서 견고하고 정확한 애플리케이션을 구축하는 데 BigInt
를 활용할 수 있습니다. 프로젝트에서 BigInt
를 사용할 때는 브라우저 호환성과 성능 영향을 고려하는 것을 잊지 마세요.
더 알아보기
- Mozilla Developer Network (MDN) - BigInt
- V8 Blog - BigInt: Arbitrary-Precision Integers in JavaScript
이 가이드는 자바스크립트의 BigInt
에 대한 포괄적인 개요를 제공합니다. 더 심도 있는 정보와 고급 기술에 대해서는 링크된 자료를 탐색해 보세요.