자바스크립트 교과서 - 3. 숫자 타입

Seoyong Lee·2023년 10월 1일
0

개발 공부

목록 보기
5/21
post-thumbnail

다음 책들과 MDN의 내용을 모아 자바스크립트 핵심 위주로 정리해 보았습니다. 여러 권의 책을 한 글로 훑어볼 수 있도록 최대한 간결하게 정리하겠습니다.

모던 자바스크립트 Deep Dive - 이웅모
You Don’t Know JS - Kyle Simson
자바스크립트는 왜 그 모양일까?(How JavaScript Works) - Douglas Crockford
자바스크립트 완벽 가이드(JavaScript: The Definitive Guide 7/E) - David Flanagan

숫자 리터럴

  • 자바스크립트 프로그램에 직접 기입한 숫자를 숫자 리터럴이라 부른다.
  • 자바스크립트의 수는 불변 객체이다.

자바스크립트에는 18437736874454810627개의 불변 숫자 객체가 내장되어 있는데, 각각은 고유하게 숫자를 나타냅니다. 숫자 리터럴은 각 리터럴의 값과 가장 잘 맞는 숫자 객체에 대한 참조를 생성합니다. 어떤 경우에는 딱 맞는 값이고, 어떤 경우에는 실제 값과 9.979201547… 만큼 차이가 나기도 합니다.

더글러스 크락포드 , 『자바스크립트는 왜 그 모양일까?』, 인사이트(2020), p15.

  • 이러한 숫자 리터럴 역시 내장된 특정 숫자 값에 대한 참조이며 실제 값과 정확하게 일치하지 않는 경우도 존재한다.

The JavaScript Number type is a double-precision 64-bit binary format IEEE 754 value, like double in Java or C#.
자바스크립트 Number 타입은 Java 또는 C#의 double과 같은 배정밀도 64비트 부동소수점 형식 IEEE 754 을 따릅니다.

mdn - JavaScript data types and data structures

  • 즉 자바스크립트의 모든 수는 실수로 처리하며, 정수만을 위한 데이터 타입이 따로 존재하지 않는다.

자바스크립트는 숫자형이 하나뿐이라는 이유로 자주 비판받았지만, 사실 이는 자바스크립트의 아주 큰 강점 중 하나입니다. 비슷한 여러 가지 타입 중에서 혹시 잘못된 타입을 사용할까 봐 고민하며 시간을 낭비하지 않아도 되니 개발자의 생산성이 증가합니다. 타입 변환으로 인한 오류도 없습니다. int형을 사용해서 발생하는 오버플로 문제도 발생하지 않습니다. 오버플로가 발생하지 않기 때문에 자바스크립트의 정수는 자바의 정수보다 훨씬 안정적입니다.

더글러스 크락포드 , 『자바스크립트는 왜 그 모양일까?』, 인사이트(2020), p13-14.

  • 실제로 자바 등의 언어에선 숫자 타입 변수와 관련해서 Integer overflow가 발생할 수 있다.
  • 자바스크립트는 하나의 타입으로 모든 숫자를 처리하므로 문제를 일으킬 요인이 적어진다.

정수 리터럴

  • 자바스크립트는 10진 정수 리터럴 및 16진수 값을 표현할 수 있다.
0
3
100000

0xff // 255 (15*16 + 15)
0xBADCAFE // 195939070
  • ES6 이후 버전에서는 다음과 같이 0b(0B)를 앞에 붙여 2진수, 0o(0O)를 앞에 붙여 8진수로 정수를 표현할 수 있다.
0b1010 // 21 (1*16 + 0*8 + 1*4 + 0*2 + 1*1)
0o377 // 255 (3*64 + 7*8 + 7*1)

부동 소수점 리터럴

  • 부동 소수점 리터럴은 소수점으로 표현하거나 지수 표기법을 사용한다.
  • 지수 표기법은 다음과 같이 작성한다.
    • [digits][.digits][(E|e)[(+|-)] digits]
3.14
2345.6789

6.02e23 // 6.02 x 10^23
  • 숫자 리터럴 안에 밑줄로 나눠 쓸 수도 있지만 아직 자바스크립트 정식 표준은 아니다.
let billion = 1_000_000_000; // 1000 단위 구분자로 사용
let bytes = 0x89_AB_CD_EF; // 바이트 구분자로 사용
  • 자바스크립트를 포함한 부동 소수점 숫자를 사용하는 모든 프로그래밍 언어에서는 다음과 같은 반올림 오류가 발생한다.

자바스크립트 숫자는 대단히 정밀한 편이며 0.1을 아주 가깝게 표현합니다. 하지만 가까울 뿐 완전히 정확한 것은 아니기 때문에 문제가 생길 수 있습니다. 다음 예제를 보십시오.

let x = .3 - .2;
let y = .2 - .1; 
x === y // false
x === .1 // false
y === .1 // true

...부동 소수점 근삿값 때문에 프로그램에 문제가 생긴다면 정수로 변환하는 것을 고려해 보십시오.

데이비드 플래너건 , 『자바스크립트 완벽 가이드』, 인사이트(2022), p33.

  • 그렇다면 프로그래밍 언어에서 사용되는 부동소수점 시스템은 어디서 온 것일까?

2진 부동소수점 시스템을 처음 사용한 사람들은 수학자들과 과학자들이었습니다. 수학자들은 컴퓨터가 유한한 장치이며, 실수를 정확하게 표현할 수 없다는 사실을 잘 알고 있었습니다. 그래서 수학자들은 수치 해석에 의존하여, 유한한 시스템에서 나온 결과에서 쓸모 있는 결과를 끄집어 내려고 애썼습니다. 과학자들은 노이즈 값이 많은 실험 데이터를 주로 다루었기 때문에 2진 부동소수점 시스템의 부정확성은 그다지 큰 문제가 되지 않았습니다.

더글러스 크락포드 , 『자바스크립트는 왜 그 모양일까?』, 인사이트(2020), p24-25.

  • 과거 특정 목적을 위해 개발된 부정확한 부동소수점 시스템을 자바스크립트 역시 여전히 사용하고 있는 만큼 최대한 안전한 정수 범위 내에서 작업하는 것을 여러 책에서 권장한다.

Number

Number 생성자는 숫자를 다루기 위해 상수와 메소드를 가지고 있습니다. 다른 타입의 값은 Number() 함수를 사용하여 숫자로 바꿀 수 있습니다.

mdn, Number

Number 함수에는 new를 사용해서는 안 됩니다. 여러분들이 원하는 대로 동작하지 않습니다.

const good_example = Number("432");
const bad_example = new Number("432");
typeof good_example  // "number"
typeof bad_example  // "object"
good_example === bad_example // false

더글러스 크락포드 , 『자바스크립트는 왜 그 모양일까?』, 인사이트(2020), p17.

  • new Number 와 같은 방식으로 사용하지 말자.

Infinity와 NaN

  • Infinity와 NaN은 전역 상수로 Number 객체의 프로퍼티로 존재한다.

Infinity

  • Infinity는 표현하기에 너무 큰 숫자를 나타낸다.

C와 같은 전통적인 컴파일 언어를 쓰는 개발자들은 ‘0으로 나누기(Divide By Zero)’ 비슷한 컴파일/런타임 에러를 숱하게 보았을것이다. 그러나 자바스크립트에서는 0으로 나누기 연산이 잘 정의되어 있어서 에러 없이 Infinify (Number.POSITIVE_INFINITY)라는 결괏값이 나온다.

var a = 1 / 0; // Infinity
var b = -1 / 0; // -Infinity

카일 심슨 , 『You Don’t Know JS - 타입과 문법, 스코프와 클로저』, 한빛미디어(2017), p56.

  • 참고로 분자가 음수면 0으로 나누기 결과는 -Infinity가 된다. 이 또한 IEEE 754와 연관된 특이한 점이다.
  • 인자가 유한한 숫자로 변환할 수 있는지 확인하기 위한 Number.isFinite( ) 라는 함수가 존재한다. 이 함수는 인자가 NaN, Infinity, -Infinity가 아닐 경우 true를 반환한다.

NaN

  • NaN은 Not A Number의 약자로 숫자 집합 내에서의 특별한 종류의 에러 상황을 나타낸다.

NaN은 너무 귀하신 몸이라 다른 어떤 NaN과도 동등하지 않다(즉, 자기 자신과도 같지 않다). 사실상 반사성(Reflective)이 없는 유일무이한 값이다. 따라서 NaN ≠= NaN이다. …비교 결과가 반드시 실패라면 NaN 여부는 어떻게 확인할 수 있을까? …내장 전역 유틸리티 isNaN( ) 함수가 NaN 여부를 말해준다.

카일 심슨 , 『You Don’t Know JS - 타입과 문법, 스코프와 클로저』, 한빛미디어(2017), p54.

  • NaN의 특이한 성질 때문에 실제 숫자가 NaN인지 확인하기 위해서 isNaN( )이라는 특별한 내장 함수를 사용해야 한다.
  • 그러나 isNaN은 다음과 같은 문제가 있다.

isNaN( )는 치명적인 결함이 있다. 이 함수는 NaN(’숫자 아님’)의 의미를 너무 글자 그대로만 해석해서 실제로 ‘인자 값이 숫자인지 여부를 평가’하는 기능이 전부다.

var a = 2 / "foo";	
var b = "foo";	
a; // NaN
b; // "foo"
window.isNaN(a); // true
window.isNaN(b); // true???

“foo”는 당연히 숫자가 아니지만, 그렇다고 NaN는 아니다! 이 버그는 자바스크립트 탄생 이후 오늘까지 계속됐다. …만약 지금 여러분이 isNaN( ) 를 사용하여 코딩 중이라면, 유감스럽게도 아직 터지지 않은 지뢰(버그)를 묻어놓은 셈이다!

카일 심슨 , 『You Don’t Know JS - 타입과 문법, 스코프와 클로저』, 한빛미디어(2017), p55-56.

  • 위 문제를 해결하기 위해 ES6에서 Number.isNaN( ) 이 등장하였고, NaN을 확인하려면 isNaN( ) 대신 이걸 사용하는 것이 일반적이다.
var a = 2 / "foo";
var b = "foo";

Number.isNaN(a); // true
Number.isNaN(b); // false

BigInt

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

mdn, BigInt

  • BigInt는 매우 큰 정수를 표현하기 위한 기능으로 ES2020에서 추가된 최신 기능이다.
  • 다음과 같이 정수 리터럴 뒤에 n을 붙이거나 BigInt( ) 함수를 호출해 생성한다.
const theBiggestInt = 9007199254740991n;
const alsoHuge = BigInt(9007199254740991); // 9007199254740991n
  • BigInt를 사용한다면 다음과 같은 주의 사항에 유의하자.

BigInt와 Number는 어떤 면에서 비슷하지만 중요한 차이점이 있습니다. 예컨대 BigInt는 내장 Math 객체의 메서드와 함께 사용할 수 없고, 연산에서 Number와 혼합해 사용할 수 없습니다. 따라서 먼저 같은 자료형으로 변환해야 합니다. 그러나, BigInt가 Number로 바뀌면 정확성을 잃을 수 있으니 주의해야 합니다.

mdn, BigInt


References

데이비드 플래너건 , 『자바스크립트 완벽 가이드』, 인사이트(2022)
더글러스 크락포드 , 『자바스크립트는 왜 그 모양일까?』, 인사이트(2020)
카일 심슨 , 『You Don’t Know JS - 타입과 문법, 스코프와 클로저』, 한빛미디어(2017)
이웅모 , 『모던 자바스크립트 Deep Dive』, 위키북스(2020)
mdn - JavaScript data types and data structures

0개의 댓글