Number vs BigInt

JOY·2024년 12월 25일
0

JS

목록 보기
15/18
post-thumbnail

알고리즘 문제를 풀다 수의 범위에 대한 이해가 부족함을 느꼈고
Number와 BigInt의 개념을 정리해보려 합니다.


제가 풀었던 문제에서

도시의 개수를 나타내는 정수 N(2 ≤ N ≤ 100,000)가 주어진다.
제일 왼쪽 도시부터 제일 오른쪽 도시까지의 거리는 1이상 1,000,000,000 이하의 자연수이다. 
리터당 가격은 1 이상 1,000,000,000 이하의 자연수이다. 

라는 입력이 주어졌습니다.
도시간 거리를 이동할 기름을 계산해야 해 10^18의 범위까지 반영해야했습니다.
처음엔 Number를 썼지만

const fs = require('fs')
const filePath = process.platform === 'linux' ? '/dev/stdin' : './example.txt'
const input = fs.readFileSync(filePath).toString().trim().split('\n')

const N = Number(input[0])
const distances = input[1].split(' ').map(Number) // 도시간 거리 배열
const prices = input[2].split(' ').map(Number) // 도시의 리터탕 기름값 배열

let answer = 0;
let currentPrice = prices[0];

for (let i = 0; i < N - 1; i++) {
  answer += currentPrice * distances[i];

  if (prices[i + 1] < currentPrice) {
    currentPrice = prices[i + 1];
  }
}

console.log(answer)

모든 케이스를 반영하지 못했습니다.

const distances = input[1].split(' ').map(BigInt)
const prices = input[2].split(' ').map(BigInt)

let answer = 0n;

console.log(String(answer))

이렇게 BigInt를 사용함으로써 더 큰 수도 반영할 수 있게 됐습니다.

어떻게 이렇게 해결한 것인지 알아봅시다.


Number 데이터 타입

Number는 JavaScript의 기본 숫자 타입입니다. (모든 숫자는 기본적으로 Number로 저장됨)
Number는 부동 소수점 값입니다. 이는 정밀도가 제한적이라는 것을 의미하고 따라서 number 타입만으로는 모든 수를 다 표현할 수 없습니다.

Number 객체의 MAX_SAFE_INTEGER, MIN_SAFE_INTEGER 프로퍼티로 안전한 최대, 최소 정수를 알 수 있습니다.

Number.MAX_SAFE_INTEGER // js에서 안전한 최대 정수. (2^53 - 1)  =>  9007199254740991

Number.MIN_SAFE_INTEGER // js에서 안전한 최소 정수. (-(2^53 - 1)) => -9007199254740991

여기서 안전함이라는 말은 정수를 정확히 표현할 수 있다는 뜻입니다.

Number 데이터 타입을 통해 계산한 결과가 -(2^53 - 1) ~ (2^53 - 1) 까지는 안전한 결과 값을 계산합니다.

MAX_SAFE_INTEGER를 초과하거나 MIN_SAFE_INTEGER보다 작은 결과값으로 평가되는 표현식은 에러는 발생시키지 않지만 정상적인 값을 출력하지 않는 것입니다.

let max = Number.MAX_SAFE_INTEGER;

console.log(max); // 9007199254740991
console.log(max++); // 9007199254740991

➕ 현재 Number 데이터 타입의 값이 안전한 값인지 아닌지 확인하기 위해 Number.isSafeInteger() 메서드를 통해 확인할 수 있습니다.

let max = Number.MAX_SAFE_INTEGER;

console.log(Number.isSafeInteger(max));  // true
console.log(Number.isSafeInteger(++max)); // false

그럼 -(2^53 - 1) ~ (2^53 - 1)를 넘어가는 수는 어떻게 표현할까요?

BigInt 데이터 타입

BigInt는 Number가 안정적으로 나타낼 수 있는 최대치인 2^53 - 1보다 큰 정수를 표현할 수 있는 js 내장 객체입니다.

BigInt를 사용하면 숫자에 대한 안전한 정수 제한을 초과하여 큰 정수를 안전하게 저장하고 조작 할 수 있습니다.

BigInt 사용법

  • 정수 리터럴 뒤에 n을 붙이기
let x = 1234567890123456789 * 123;
console.log(x); // 151851850485185200000 ❌

x = 1234567890123456789n * 123n;
console.log(x); // 151851850485185185047n 🟢
  • BigInt() 생성자 함수 호출
x = BigInt(x);
console.log(typeof x); // bigint

BigInt 특징

  • BigInt는 Number와 일치하지 않지만 동등합니다
0n === 0 // false

0n == 0 // true

1n < 2 // true
  • if, &&, || 또는 Boolean()을 사용할 때, BigInt는 Number와 같은 논리를 따릅니다 (0n은 falsy 값)
if (0n) {
  console.log('if에서 안녕!');
} else {
  console.log('else에서 안녕!');
}
// "else에서 안녕!"

0n || 12n // 12n

0n && 12n // 0n

Boolean(0n) // false
  • 사용 가능 연산자 : +, *, -, **, %
const previousMaxSafe = BigInt(Number.MAX_SAFE_INTEGER);
// ↪ 9007199254740991

const maxPlusOne = previousMaxSafe + 1n;
// ↪ 9007199254740992n

const multi = previousMaxSafe * 2n;
// ↪ 18014398509481982n

const subtr = multi – 10n;
// ↪ 18014398509481972n

const mod = multi % 10n;
// ↪ 2n

const bigN = 2n ** 54n;
// ↪ 18014398509481984n

❗ 소수점 결과를 포함하는 연산을 BigInt와 사용하면 소수점 이하는 사라집니다

const rounded = 5n / 2n;
// ↪ 2.5n이 아니라 2n

❗ BigInt는 내장 Math 객체의 메서드와 함께 사용할 수 없습니다

const x = BigInt(100);
const y = BigInt(200);

console.log(Math.max(x, y)); // ❌ TypeError: Cannot convert a BigInt value to a number at Math.max (<anonymous>)

참고자료

profile
모든 일에 진심을 담아서

0개의 댓글