숫자형 종류
- 일반적인 숫자는 '배정밀도 부동소수점 숫자(double precision floating point number)'로 알려진 64비트 형식의 IEEE-754에 저장됩니다. 튜토리얼 전체에서 이 형식을 사용하여 숫자를 표현할 예정입니다.
- 임의의 길이를 가진 정수는 BigInt 숫자로 나타낼 수 있습니다. 일반적인 숫자는 253이상이거나 -253이하일 수 없다는 제약 때문에 BigInt라는 새로운 자료형이 만들어졌습니다. BigInt는 아주 특별한 경우에만 사용되므로, 별도의 챕터 BigInt에서 자세한 내용을 다루겠습니다.
숫자를 입력하는 다양한 방법
10억을 입력하는 방법
1
let billion = 1000000000;
2.
숫자 옆에 ‘e’를 붙이고 0의 개수를 그 옆에 붙여주면 숫자를 줄일 수 있다.
let billion = 1e9; // 10억, 1과 9개의 0
alert( 7.3e9 ); // 73억 (7,300,000,000)
자매품 - 소숫점을 입력하는 방법
let ms = 1e-6; // 1에서 왼쪽으로 6번 소수점 이동
16진수, 2진수, 8진수
16진수
색을 나타내거나 문자를 인코딩할 때 등 다양한 곳에서 두루 쓰인다. 16진수는 0x를 통해서 나타낸다
alert( 0xff ); // 255
alert( 0xFF ); // 255 (대·소문자를 가리지 않으므로 둘 다 같은 값을 나타냅니다.)
2진수와 8진수는 아주 드물게 쓰이긴 하지만, 접두사 0b와 0o를 사용해 간단히 나타낼 수 있습니다.
let a = 0b11111111; // 255의 2진수
let b = 0o377; // 255의 8진수
alert( a == b ); // true, 진법은 다르지만, a와 b는 같은 수임
toString(base)
num.toString(base) 메서드는 base진법으로 num을 표현한 후 이를 문자형으로 변환합니다
let num = 255;
num.toString(16) // ff
num.toString(2) // 11111111
base별 유스케이스
- base = 16
- 16진수 색, 문자 이코딩 등을 표현할 때 사용한다. 숫자는 0부터 9, 10 이상의 수는 A부터 F를 사용하여 나타낸다.
- base = 2
- 비트 연산 디버깅에 주로 쓰인다. 숫자는 0 또는 1이 될 수 있다.
- base = 36
/* 123456..toString(36)에 있는 점 두 개는 오타가 아닙니다. 위 예시처럼 숫자를 대상으로 메서드 toString을 직접 호출하고 싶다면 숫자 다음에 점 두 개 ..를 붙여야 합니다. 123456.toString(36)처럼 점을 한 개만 사용하면, 첫 번째 점 이후는 소수부로 인식되어 에러가 발생할 수 있습니다. 점을 하나 더 추가하면 자바스크립트는 소수부가 없다고 판단하고 함수를 호출합니다. (123456).toString(36)도 가능합니다. */ alert( 123456..toString(36) ); // 2n9c
- 사용할 수 있는 base 중 최댓값으로, 0..9와 A..Z를 사용해 숫자를 표현한다. 알파벳 전체가 숫자를 나타내는데 사용된다. 36 베이스는 url을 줄이는 것과 같지 숫자로 된 긴 식별자를 짤벡 줄일 때 유용하다
어림수 구하기
내장 함수들
- Math.floor
- 소숫 점 첫째 자리에서 내림
- Math.ceil
- 소수점 첫째 자리에서 올림
- Math.round
- 소수점 첫째 자리에서 반올림
- Math.truncMath.floor Math.ceil Math.round Math.trunc
3.1 3 4 3 3.6 3 4 4 -1.1 -2 -1 -1 -1.6 -2 -1 -2 - 소수부 무시
소수점 n-th번째 수를 기준으로 어림수를 구해야 하는 상황
예를 들어서 1.2345가 있는데 나는 1.23만 (소수점 두 번째 자릿수만 남김) 남기고 싶다.
1. 곱하기와 나누기
숫자에 100 또는 100보다 큰 10의 거듭제곱 수를 곱한 후 어림수 내장 함수를 호출하고 처음 곱한 수를 다시 나눈다.
let num = 1.23456;
Math.floor(num * 100) / 100 // 1.23456 -> 123.456 -> 123 -> 1.23
2. 소수점 n번째 수까지의 어림수를 구한 후 이를 문자형으로 반환해주는 메서드인 toFixed(n)을 사용한다.
Math.round와 유사하게 가장 가까운 값으로 올림 혹은 버림해준다.
let num = 12.34;
num.toFixed(1) // "12.3"
주의할 점은 반환값이 문자열이라는 것이다. 소수부의 길이가 인수보다 작으면 끝에 0이 추가된다.
let num = 12.34;
alert( num.toFixed(5) ); // "12.34000", 소수부의 길이를 5로 만들기 위해 0이 추가되었습니다.
부정확한 계산
숫자는 내부적으로 64비트 형식으로 표현되기 때문에 숫자를 저장하려면 정확히 64비트가 필요하다. 52비트는 숫자를 저장하고 11비트는 소수점 위치를(정수는 0), 나머지 1비트는 부호를 저장하는데 사용된다.
근데 숫자가 너무 커지면 64비트 공간이 넘쳐서 Infinity로 처리된다.
alert( 1e500 ); // Infinity
이것 말고도 꽤 자주 발생하는 현상인 정밀도 손실도 있다.
alert(0.1 + 0.2 == 0.3) // false
alert( 0.1 + 0.2 ); // 0.30000000000000004
원인
숫자는 0과 1로 이루어진 이진수로 변환되어 연속된 메모리 공간에 저장되는데 10진법을 사용하면 쉽게 표현할 수 있는 0.1, 0.2 같은 분수는 이진법으로 표현하면 무한 소수가 된다.
0.1은 1을 10으로 나눈 수인 1/10 이다. 10진법을 사용하면 이러한 숫자를 쉽게 표현할 수 있다. 1/3은 무한소수 0.33333(3)이 된다.
이렇게 10의 거듭제곱으로 나눈 값은 10진법에서 잘 동작하지만 3으로 나누게 되면 10진법에서 제대로 동작하지 않는다. 같은 이유로 2진법 세계에서 2의 거듭제곱으로 나눈 값은 잘 동작하지만 1/10같이 2의 거듭제곱이 아닌 값으로 나누게 되면 무한소수가 되어버린다.
즉 10진법에서 1/3을 정확히 나타낼 수 없듯이, 2진법을 사용해 0.1 혹은 0.2를 정확하게 저장하는 법은 없다.
IEEE-754 에서는 가장 가까운 숫자로 반올림 하는 방법을 사용해 이런 문제를 해결하고 있다. 하지만 이렇게 반올림을 하더라도 우리가 볼 수 없는 작은 정밀도 손실은 발생한다.
alert( 0.1.toFixed(20) ); // 0.10000000000000000555
0.1은 사실 이런 숫자이기 때문에 0.1 + 0.2 == 0.3은 false이다. 사실 이 문제는 java, PHP 등에서도 똑같이 일어나는 문제이다.
해결
toFixed(n) 메서드를 사용해서 어림수 만드는 방법이 있다.
let sum = 0.1 + 0.2
sum.toFixed(2) // 0.30
toFixed() 는 항상 문자열을 반환하기 때문에 소수점 다음에 오는 숫자가 항상 2개가 될 수 있다. 이걸 다시 숫자형으로 변환하려면 + 기호를 붙이면 된다
let sum = 0.1 + 0.2;
alert( +sum.toFixed(2) ); // 0.3
다른 방법으로 숫자에 임시로 100(혹은 더 큰 숫자)를 곱하여 정수로 바꾸고 원하는 연산을 다시 한 후 다시 100으로 나누는 방법도 있다. 하지만 어쨋든 마지막에 나누기가 들어가기 때문에 소수가 재등장 할 수 있긴 하다
alert( (0.1 * 10 + 0.2 * 10) / 10 ); // 0.3
alert( (0.28 * 100 + 0.14 * 100) / 100); // 0.4200000000000001
isNaN과 isFinite
inNaN(value)
인수를 숫자로 변환한 다음 NaN인지 테스트
alert( isNaN(NaN) ); // true
alert( isNaN("str") ); // true
그런데 굳이 이 함수가 필요할까? 답은 필요하다 이다. NaN은 자기자신을 포함하여 어떤 값과도 같지 않다.
alert(NaN == NaN); //false
isFinite(value)
인수를 숫자로 변환하고 변환한 숫자가 NaN/Infinity/-Infinity 가 아닌 일반 숫자인 경우 true 반환
alert( isFinite("15") ); // true
alert( isFinite("str") ); // false, NaN이기 때문입니다.
alert( isFinite(Infinity) ); // false, Infinity이기 때문입니다.
또한 문자열이 일반 숫자인지 검증하는데 사용한다.
let num = +prompt("숫자를 입력하세요.", '');
// 숫자가 아닌 값을 입력하거나 Infinity, -Infinity를 입력하면 false가 출력됩니다.
alert( isFinite(num) );
parseInt와 parseFloat
문자형을 숫자형으로 변환할때 규칙은 굉장히 엄격하다 예를들어서 아래 코드처럼 px이라는 문자가 붙어있다면 NaN이 떨어진다.
alert( +"100px" ); // NaN
이런 경우를 위하여 parseInt와 parseFloat 가 만들어졌다.
두 함수는 불가능할 때 까지 문자열에서 숫자를 읽는다. 숫자를 읽는 도중 오류가 발생하면 이미 수집된 숫자를 반환한다.
alert( parseInt('100px') ); // 100
alert( parseFloat('12.5em') ); // 12.5
alert( parseInt('12.3') ); // 12, 정수 부분만 반환됩니다.
alert( parseFloat('12.3.4') ); // 12.3, 두 번째 점에서 숫자 읽기를 멈춥니다.
만약 첫글자가 문자 처럼 읽을 수 없는 숫자가 없다면 NaN이 떨어진다
alert( parseInt('a123') ); // NaN, a는 숫자가 아니므로 숫자를 읽는 게 중지 됩니다.
두번째 인수를 지정해서 16진수 문자열, 2진수 문자열 등을 파싱할 수도 있습니다.
alert( parseInt('0xff', 16) ); // 255
alert( parseInt('ff', 16) ); // 255, 0x가 없어도 동작합니다.
alert( parseInt('2n9c', 36) ); // 123456
기타 수학 함수
Math.random()
0과 1사이의 난수 반환(1은 제외)
alert( Math.random() ); // 0.1234567894322
alert( Math.random() ); // 0.5435252343232
alert( Math.random() ); // ... (무작위 수)
Math.max(a, b, c...) / Math.min(a, b, c...)
인수 중 최대/최솟값 반환]
alert( Math.max(3, 5, -10, 0, 1) ); // 5
alert( Math.min(1, 2) ); // 1
Math.pow(n, power)
n을 power번 거듭제곱한 값 반환
alert( Math.pow(2, 10) ); // 2의 10제곱 = 1024
'JavaScript 개념' 카테고리의 다른 글
iterable 객체 (0) | 2024.04.30 |
---|---|
문자열 (1) | 2024.04.30 |
원시값의 메서드 (0) | 2024.04.29 |
객체 (0) | 2024.04.29 |
테스트 자동화와 Mocha (0) | 2024.04.29 |