(Javascript) 1. Data type? -2- : Primitive type

김동우·2021년 6월 8일
0

wecode

목록 보기
4/32

잠깐! 시작하기 전에

이 글은 wecode 사전 스터디에서 실제 공부하고, 이해한 내용들을 적는 글입니다. 글의 표현과는 달리 어쩌면 실무와는 전혀 상관이 없는 글일 수 있습니다.

또한 해당 글은 다양한 자료들과 작성자 지식이 합성된 글입니다. 따라서 원문의 포스팅들이 틀린 정보이거나, 해당 개념에 대한 작성자의 이해가 부족할 수 있습니다.

설명하듯 적는게 습관이라 권위자 발톱만큼의 향기가 조금은 날 수 있으나, 엄연히 학생입니다. 따라서 하나의 참고자료로 활용하시길 바랍니다.

글의 내용과 다른 정보나 견해의 차이가 있을 수 있습니다.
이럴 때, 해당 부분을 언급하셔서 제가 더 공부할 수 있는 기회를 제공해주시면 감사할 것 같습니다.

Number

MDN을 처음 펴 본 여러분은 시작과 동시에 묘한 기분이 들 수 있을겁니다.

IEEE-754? 이중정밀도 64비트 지원? 이게 뭐야? 무슨 말이야? 하고 말이죠. 제가 그랬거든요.

그래서 간단하게 설명해드리자면, binary digit 의 할당 칸 수 만큼 실수를 표현한다는 말이 됩니다.

컴퓨터는 연산의 결과로 수를 표현하는 과정에서 메모리의 일부에 수를 저장한 뒤 출력하게 됩니다.

이 때 수가 저장되는 메모리의 bit는 일종의 2진법 주판의 형태로, 2진법 계산으로 범위를 결정합니다.

부동소수점 표기는 소수점이 고정되지 않는 표현방식을 일컫는데요, 컴퓨터의 경우 2진법으로 실수를 표현하게 됩니다.

예를 들어 10진법의 8.25의 경우 1000.01(2)이 됩니다.

이후 당연하게도 1000.01을 그대로 사용하는 것이 아니라 컴퓨터의 연산 과정에는 변환이 존재하게 됩니다.

1.00001 * 2^3 이런식으로 가수부와 지수부를 나누어 메모리에 저장하게 되는데요, 이 때 사용되는 bit가 64개일 경우 64bit 배정밀도 라고 표현하는 것이죠. 32 bit의 경우 단정밀도로 표현합니다.

우리가 사용하는 Js는 첫 줄에 나와있는 이중정밀도(배정밀도), 64bit 에 해당하는 범위 내 실수를 Number의 기본으로 사용합니다.

(1). 정수

Js에서는 Integer, 정수형의 개념이 존재하지 않고, 자연계에 존재하는 실수가 곧 Number인겁니다. (BigInt는 엄연히 다른 개념입니다. 착각하시면 안됩니다.)

즉, Js는 우리가 1을 넣든 1.1을 집어넣든, 실제 내부 연산에서는 0.999999...혹은 1.000000..., 1.100000... 혹은 1.099999... 로 이루어진 실수를 활용한다는 것이죠.

다만, 이러한 불편함을 해소하기 위해 기존 프로그래밍 언어 기준의 정수를 처리하는 작업에서는 32bit 정수를 구현합니다. 부호까지 적용된 signed로 표현됩니다.

이러한 범위는 -2^31 ~ ((2^31 - 1), 2^31일 경우는 bit 초과)) 로 정의됩니다.

소수점 계산만 아니면 비교적 연산이 괜찮다는 말이기도 합니다.

(2). double의 범위

그러나, 우리는 대부분 8 Byte, 64 bit, double에 해당하는 실수범위의 수를 Number로 인식하고 있어야 합니다.

64bit double에 해당하는 범위는 -1.8 x 10^308 ~ 1.8 x 10^308 이므로, 큰 수를 계산할 일 없는 프론트엔드 개발에서는 정수처리, 실수처리 양 쪽 모두 다 채울 상황이 거의 없다는 것이죠.

실수부만 봐도 10의 308거듭제곱인데, 사실 연산에 안전한 표현이 가능한 범위는 아닙니다. 이는 뒤에 BigInt에서 나옵니다.

이러한 수의 범위를 인식하기 위해서는 1개의 비트로 이루어진 sign(부호), 11개의 exponential(지수), 52개의 fraction(가수) 비트 그림을 머리속으로 떠올려야 합니다.

그림만 떠오르고 수는 떠오르지 않는다구요? 괜찮습니다. 사실 사람이 그림을 떠올린다고 헤아릴 수 있는 범위는 아니라고 생각합니다. 저도 당연히 범위 끝의 수가 떠오르지 않거든요.

(3). 소수점 표현

추가적으로, Js의 소수점 중 예외의 경우(정수부가 한 자리일 때) 16번째 자리까지 출력이 가능합니다. (총 자리수는 17개가 되겠네요.)

그 외에는 정밀도가 15임에 따라 16을 초과하는 자리수를 출력하지는 않습니다.

console.log( 1.11111111111111111111111111111111111111 );
// output : 1.1111111111111112 예외

console.log( 111111111.111111111111111111111 );
// output : 111111111.1111111 정석

이런, 아이러니하게도 반올림 처리한다던 Js 녀석은 어디갔는지 반올림은 커녕 이처럼 자기 멋대로 처리하는 모습을 볼 수 있습니다.

물론 실생활에서 저정도 오차는 유의미하지 않습니다만, 컴퓨터의 연산에서 저런 오차는 유의미합니다.

1.1 + 2.2 = 3.3이 아닌 곳의 영역이니까요.

즉, 우리는 소수점 연산을 보다 멀리하고 최대한 정수연산을 열심히 넣어주는게 좋겠습니다.

(4). double 정수표현? BigInt?

물론 Js는 double을 통해 상당히 넓은 범위의 실수를 다룰 수 있습니다. 그러나 첫번째 항목에서 말했듯 어지간한 크기의 정수는 엄연히 32bit signed int로 표현됩니다.

그렇다고 signed int32 의 범위를 벗어나는 값을 표현할 수 없는가? 그것은 당연히 아닙니다.

그런데 최근 64 bit 실수형의 가수부 범위를 초과하는 정수들의 사용이 가끔 이루어지다보니, Js는 내부 표현방식의 문제를 경험했습니다.

가수부가 52개의 bit로 이루어져 있기 때문에, 정수를 아무리 길게 표현해도 2^53-1(= 9007199254740991) ~ -(2^53-1) 범위를 벗어나는 값은 안전하게 표현할 수 없었습니다.

이에 새롭게 등장한 BigInt입니다.

정말 범위에 제한이 없나? 싶을 정도로 길게 늘어진 수를 이용할 수 있게 해주는 소중한 녀석이 됩니다.

또한 글에서는 Number의 하위항목에 들어가있지만, 실제로는 따로 분리되어 다뤄지는 자료형입니다.

후에 보안에 대해 공부하시거나, 백엔드에서 더 많은 수를 활용해야 한다면 한 번 참고해보시는것도 나쁘지 않을것 같습니다.

(5). 연산자

그 이외에도 기본적인 사칙연산 기호 = 표준 산술 연산자(+, -, *, /)를 지원하고, parseInt()등의 내장함수를 통해 우린 문자열이나 다양한 진법의 수 표현을 오갈 수 있습니다.

(6). Math

계산이 더 복잡하고, 공학적인 사항이 요구될 때는 Math라는 내장 obj를 활용할 수 있도록 지원하고 있답니다. (Python, C++에도 있는 친숙한 녀석입니다.)

(7). parseInt()의 활용법

parseInt()는 상당히 많은 역할을 합니다.

여기서 전부 다뤄보지는 않겠습니다.

먼저, String 형태의 숫자 data를 number로 변환해줄 수 있습니다.

둘째, 다양한 진법 (2, 8, 10, 16)의 수를 argument(전달인자)로 지정해주면 해당 정수를 진법에 맞게 바꿔주기도 합니다.

ex1)

parseInt('01', 2); // 1

이와 같이 말이죠. 보시는 것과 같이 2는 argument로 들어가있고, 이는 2진법을 의미합니다.

또한 String이 숫자가 아닌경우에는 "NaN"이라는 독성을 가진 값을 반환하는데, 이 때 주의하셔야 할 점은 NaN의 경우 독성을 가졌기 때문에 계산식 끝, 처음, 혹은 어딘가에서 NaN이 반환되었다면 무조건 최종 결과는 NaN으로 반환합니다.

이를 위해 우리는 isNaN() 함수를 사용해 반환값을 검사할 수 있습니다.

(8). Infinite, -Infinite

무한을 뜻하는 값을 Js는 가지고 있습니다.

대부분 코딩에서 이러한 값을 의도적으로 볼 일이 거의 없을거라 생각하기에 원치 않는 오류로 등장할 수 있으니 알아둡시다.

(9). "+"연산자와 parseInt()

대부분 + 연산자에 대해 들어는 보셨을겁니다. String 값을 단항연산자를 활용해 숫자로 변환해주는 녀석이죠.

이는 JS가 상당히 엄격하지 않은 언어라는 말이 되기도 합니다.

다른 자료형끼리의 연산이 가능하다는 말은 어디서 실수가 발생했는지 정확히 알 수 없다는 말로 이해할 수 있습니다.

그럼에도 확실한 문제의 예시로는 String 내부에 숫자도 존재하지만, 글자가 함께 섞여있는 경우입니다.

123a456b789c 라는 String 값을 parseInt()로 볼 경우 NaN이 나오지는 않습니다. 글자 이전에 등장하는 숫자를 반환해주기 때문이죠.

단, "+"연산자의 경우 글자가 섞여있기 때문에 그 즉시 NaN을 반환합니다.

이런 경우를 주의하시며, 코드를 작성해야겠습니다.

String

Js에서의 문자열은 우리가 늘 지정해주던 HTML 내의 UTF 형식을 기본으로 탑재하고 있습니다.

신경쓸 부분이 줄어든 점에서 상당히 기쁘지 않나요? 심지어 우린 어느 국가의 언어든 다 표현할 수 있습니다.

UTF-16 코드의 나열로 이루어진 문자열을 통해서요! 이건 정말 기쁜 일이지만, 사실 요즘 언어에서는 당연한 일이기도 하죠.

그러니 우린 편하게 Js에서 문자열을 활용하면 된답니다.

Boolean

Js에서는 당연히 다양한 용도에 쓰일 수 있는 true, false 값을 가지고 있습니다.

이는 조건문에 주로 사용되는 형태로, 우린 Boolean을 활용해 다양하고, 동적인 웹, 앱의 애니메이션을 만들어 볼 수 있겠죠.

null, undefined

Js는 값이 없는 상태를 나타내는 데에 null과 undefined를 활용합니다.

둘은 말 그대로 비어있다, 정의되지 않았다. 로 지금 설명에서는 Boolean으로 활용 시 false를 의미한다. 정도만 알고 계셨으면 좋겠습니다.

이후 값에 대한 설명에서 둘은 자세하게 다뤄볼 예정이거든요.

정확히 언제인지는 모르겠네요.

그 외에도 Boolean으로 활용 시 false를 나타내는 값들에는 0, false, ""(공백 string), NaN(number가 아님)(+ null, undefined) 등이 있습니다.

Boolean() function을 사용하면 인자값을 Boolean으로 반환할 수 있습니다. 그러나, 대부분의 조건에 값이 전달될 경우, JS는 사용자 몰래 그냥 거짓 or 참 값으로 알아서 변경해줄겁니다.

즉, 신경써야 할 부분은 값의 반환이 어떻게 이루어졌고, 어째서 조건의 결과가 false || true 로 반환되었는지 정확히 알고 있으면 되는 것은 아닐까 생각합니다.

자, 이것으로 첫 번째 노트인 자료형의 1/3 정도를 맛보기로 보신겁니다.

이번 글은 여기서 마치도록 하겠습니다. 감사합니다.

0개의 댓글