JS

17 JS 숫자형

와라리요 2022. 11. 15. 14:35

 - 숫자형에 대해 공부했는데 일반적으로 2의 53승 이상이거나  -2의 53승 이하로 만 표기가 가능하지만 Bigint를 사용하면 그 이상도 표기가 가능하다. 하지만 공부한 곳에서는 Bigint만 따로 다루기에 오늘 내용에는 없다.

 

입력 방법

예)

let num1 = 123;
let num2 = 100000000;

  이렇게 입력해도 되지만 num2처럼 0이 많은 숫자는 오류가 나기 쉽다. 그래서 e를 이용해 간단하게 표현할 수 있으며 e 뒤에 양수를 입력하면 숫자만큼 0이 붙고 음수를 입력하면 수만큼 0의 개수가 소수점으로 붙는다. 

let num2 = 1e8; // 1뒤에 0을 8개 붙임 즉, 1억임
let num3 = 1.23e7; //이렇게 표현하면 1230만을 표현할 수 있다.
let num4 = 1e-5; // 소숫점 밑으로 0이 붙는다. 0.00001

 

16진수, 2진수, 8진수

 - 16진수는 색을 나타내거나 문자를 인코딩할 때 등 다양한 곳에서 두루 쓰입니다. 다양한 곳에서 쓰이는 만큼 당연히 16진수를 짧게 표현하는 방법도 존재하겠죠. 16진수는 0x를 사용해 표현할 수 있습니다. 2진수와 8진수는 아주 드물게 쓰이긴 하지만, 접두사 0b 0o를 사용해 간단히 나타낼 수 있다.

 

let a = 0xff; // 255
let b = 0b11111111; // 255의 2진수
let c = 0o377; // 255의 8진수
consol.log(a == b, b == c, c == a) //true로 반환된다.

 


 

toSting(base)

num.toString(base) 메서드는 base진법으로 num을 표현한 후, 이를 문자형으로 변환해 반환한다.

예)

let num = 255;

alert( num.toString(16) );  // ff
alert( num.toString(2) );   // 11111111

base는 2에서 36까지 쓸 수 있는데, 기본값은 10이다

base별 유스 케이스는 다음과 같다.

  • base=16 – 16진수 색, 문자 인코딩 등을 표현할 때 사용합니다. 숫자는 0부터 9, 10 이상의 수는 A부터 F를 사용하여 나타냄.
  • base=2 – 비트 연산 디버깅에 주로 쓰며 숫자는 0 또는 1이 될 수 있음
  • base=36 – 사용할 수 있는 base 중 최댓값으로, 0..9와 A..Z를 사용해 숫자를 표현함. 알파벳 전체가 숫자를 나타내는 데 사용되고 주로 36 베이스는 url을 줄이는 것과 같이 숫자로 된 긴 식별자를 짧게 줄일 때 유용하게 사용됨.

base = 36 예)

console.log(123456..toString(36)); // 2n9c

 ※ ..을 2개 넣은 이유는 숫자 뒤. 은 소수점으로 인식해서 1개 더 붙여줘야 됨. 만약 1개만 붙이고 싶다면 숫자를 ()로 감싸면 됨.

 


 

어림수 구하기

 - 숫자를 다룰 때 가장 많이 사용되는 연산 중 하나이다. 쉽게 이해하면 소수점 뒤의 숫자를 조작하는 데 사용된다.

어림수 관련 내장 함수는

  • Math.floor() - 소수점 첫자리에서 내린다.
  • Math.ceil() - 소수점 첫 자리에서 올린다.
  • Math.round() - 소수점 첫 자이레서 반올림 힌디.
  • Math.trunc() - 소수점 밑을 숫자를  버린다.

예시 표

  Math.floor() Math.ceil() Math.round() Math.trunc()
2.1 2 3 2 2
2.6 2 3 3 2
-4.1 -5 -4 -4 -4
-4.6 -5 -4 -5 -4

 

  소수점 자르는 방법

1. 곱하기와 나누기

  - 원하는 소수점 자리까지 10의 거듭제곱 수을 곱하고 어림수 내장 함수를 이용해 소수점 밑을 버린 후 곱한 10의 거듭제곱 수를 나누면 된다.

let num = 1.23456;

console.log(Math.floor(num * 100) / 100); // 1.23456 -> 123.456 -> 123 -> 1.23

 

2. toFixed(n)

  - 메서드를 이용해 소수점 n번째 수까지 표현할 수 있으며 반환 값을 round()와 비슷하게 반올림한다. 그리고 소수점 자릿수를 벗어나게 n의 개수를 입력하면 0을 붙인다. 이 메서드의 특징은 문자형으로 반환한다는 것이다.

let num = 1.2345;

console.log(num.toFixed(1)); //'1.2'
console.log(num.toFixed(3)); //'1.235'
console.log(num.toFixed(7)); //'1.2345000'

 


 

부정확한 계산

 - 숫자는 내부적으로 64비트 형식으로 표현되기 때문에 숫자를 저장하려면 정확히 64비트가 필요하다. 64비트 중 52비트는 숫자를 저장하는 데 사용되고, 11비트는 소수점 위치를(정수는 0), 1비트는 부호를 저장하는 데 사용된다.

  그런데 숫자가 너무 커지면 64비트 공간이 넘쳐서 Infinity로 처리된다.

alert( 1e500 ); // Infinity

원인을 이해하려면 집중이 필요하긴 하지만, 꽤 자주 발생하는 현상인 정밀도 손실(loss of precision)도 있다.

예시를 살펴보면

console.log(0.1 + 0.2 == 0.3); // false
console.log(0.1 / 0.2); //0.30000000000000004

※ 왜 이런 일이 발생하는 걸까요?

  숫자는 0과 1로 이루어진 이진수로 변환되어 연속된 메모리 공간에 저장된다.. 그런데 10진법을 사용하면 쉽게 표현할 수 있는 0.1, 0.2 같은 분수는 이진법으로 표현하면 무한 소수가 됩니다.

  0.1은 1을 10으로 나눈 수인 1/10이다. 10진법을 사용하면 이러한 숫자를 쉽게 표현할 수 있다. 1/10과 1/3을 비교해보면 1/3은 무한 소수 0.33333(3)이 된다.

  이렇게 10의 거듭제곱으로 나눈 값은 10진법에서 잘 동작하지만 3으로 나누게 되면 10진법에서 제대로 동작하지 않는다. 같은 이유로 2진법 체계에서 2의 거듭제곱으로 나눈 값은 잘 동작하지만 1/10같이 2의 거듭제곱이 아닌 값으로 나누게 되면 무한 소수가 되어버린다.

  10진법에서 1/3을 정확히 나타낼 수 없듯이, 2진법을 사용해 0.1 또는 0.2를 정확하게 저장하는 방법은 없다.

  IEEE-754에선 가능한 가장 가까운 숫자로 반올림하는 방법을 사용해 이런 문제를 해결한다. 그런데 반올림 규칙을 적용하면 발생하는 '작은 정밀도 손실’을 우리가 볼 수는 없지만 실제로 손실은 발생한다.

  아래와 같이 코드를 작성하면 정밀도 손실을 눈으로 확인할 수 있다.

console.log(0.1.toFixed(20)); // '0.10000000000000000555'

  그리고 두 숫자를 합하면 정밀도 손실도 더 해진다. 이것은 JS 뿐만 아니라 PHP, Java, C 등 다른 프로그래밍 언어에서도 동일한 결과를 얻는다.

 

해결하는 방법!

  이 문제를 해결함에 있어 가장 신뢰하는 방법은 toFixed() 메서드를 이용하는 것이다.

let sum = 0.1 + 0.2;
alert(sum.toFixed(2)); // '0.30'

  그런데 이렇게 사용 시 반환되는 값이 문지열 이므로 다시 연산에 사용하기 위해선 앞에 +를 붙여주면 숫자형으로 반환한다.

let sum = 0.1 + 0.2;
alert(+sum.toFixed(2)); // 0.3

  다른 방법으로 10의 거듭제곱을 곱하고 던한 뒤 10의 거듭제곱을 나누는 방법도 있다. 하지만 이것 또한 수가 커지면 무한소수를 반환한다.

예로

console.log((0.1 * 10 + 0.2 * 10) / 10); // 0.3
console.log((0.28 * 100 + 0.14 * 100) / 100); // 0.4200000000000001

 

해결 방법은 정답은 없다. 구성된 코드에 따라 위의 코드를 사용하거나 다른 방법을 모색해봐야 한다!

 


 

isNaN과 isFinite

  • Infinity와 -Infinity – 그 어떤 숫자보다 큰 혹은 작은 특수 숫자 값
  • NaN – 에러를 나타내는 값

두 특수 숫자는 숫자형에 속하지만 정상적인 숫자는 아니기 때문에, 정상적인 숫자와 구분하기 위한 특별한 함수가 존재한다.

  • isNaN(value) – 인수를 숫자로 변환한 다음 NaN인지 테스트함
console.log(isNaN(NaN)); // true
console.log(isNaN("str")); // true

  그런데 굳이 이 함수가 필요할까요? "=== NaN 비교를 하면 되지 않을까?"라는 생각이 들 수 있다. 안타깝게도 대답은 '필요하다’이다. NaN NaN 자기 자신을 포함하여 그 어떤 값과도 같지 않다는 점에서 독특하다.

consoel.log(NaN === NaN); // false
  • isFinite(value) – 인수를 숫자로 변환하고 변환한 숫자가 NaN/Infinity/-Infinity가 아닌 일반 숫자인 경우 true를 반환함
console.log(isFinite("15")); // true
console.log(isFinite("str")); // false, NaN이기 때문
console.log(isFinite(Infinity)); // false, Infinity이기 때문

isFinite는 문자열이 일반 숫자인지 검증하는 데 사용되기도 함.

let num = +prompt("숫자를 입력하세요.", '');

// 숫자가 아닌 값을 입력하거나 Infinity, -Infinity를 입력하면 false가 출력됩니다.
alert(isFinite(num));

 ※ 유의!

 - 빈 문자열이나 공백만 있는 문자열은 isFinite를 포함한 모든 숫자 관련 내장 함수에서 0으로 취급된다

 

 


 

parseInt와 parseFloat

 - 단항 덧셈 연산자 + 또는 Number()를 사용하여 숫자형으로 변형할 때 적용되는 규칙은 꽤 엄격 하디. 피연산자가 숫자가 아니면 형 변환이 실패한다.

console.log(+"100px"); //NaN

  엄격한 규칙이 적용되지 않는 유일한 예외는 문자열의 처음 또는 끝에 공백이 있어서 공백을 무시할 때이다.

  그런데 실무에선 CSS 등에서 '100px', '12pt'와 같이 숫자와 단위를 함께 쓰는 경우가 흔하다. 대다수 국가에서 '19€'처럼 금액 뒤에 통화 기호를 붙여 표시하기도 하죠. 숫자만 추출하는 방법이 필요해 만들어진 내장 함수가 parseInt와 parseFloat이다.

  두 함수는 불가능할 때까지 문자열에서 숫자를 읽는다.. 숫자를 읽는 도중 오류가 발생하면 이미 수집된 숫자를 반환한다. parseInt는 정수, parseFloat는 부동 소수점 숫자를 반환한다.

console.log(parseInt('100px')); // 100
console.log(parseFloat('12.5em')); // 12.5

console.log(parseInt('12.3')); // 12, 정수 부분만 반환됩니다.
console.log(parseFloat('12.3.4')); // 12.3, 두 번째 점에서 숫자 읽기를 멈춥니다.

  NaN을  반환할 때도 있는데 읽을 수 있는 숫자가 없을 때 그렇다.

console.log(parseInt('a123')); // NaN, a는 숫자가 아니므로 숫자를 읽는 게 중지된다.
더보기

※ parseInt(str, radix)의 두 번째 인수

parseInt()의 두 번째 매개 변수는 선택적으로 사용할 수 있습니다. radix는 원하는 진수를 지정해 줄 때 사용합니다. 따라서 parseInt를 사용하면 16진수 문자열, 2진수 문자열 등을 파싱 할 수 있습니다.

console.log(parseInt('0xff', 16)); // 255
console.log(parseInt('ff', 16)); // 255, 0x가 없어도 동작합니다.

console.log(parseInt('2n9c', 36)); // 123456

 

 


 

기타 수학 함수

  자바스크립트에서 제공하는 내장 객체 Math엔 다양한 수학 관련 함수와 상수들이 들어있다.

  예로 몇 개만 살펴보면

Math.random() - 0과 1 사이의 난수를 반환함(1은 제외)

 - 자신이 원하는 숫자 범위의 가장 큰 수를 곱하고 어림수 관련 내장 함수를 이용하면 무작위 범위를 정할 수 있다.

console.log(Math.random()); //0.123456789 등 무작위로 반환죔

console.log((Math.random() * 2).toFixed(0)); //0~2까지 무작위로 숫자를 반환함.
console.log((Math.random() * 10).toFixed(0)); //0~10까지 무작위로 숫자를 반환함.

 

Math.max() / Math.min() - 인수 중 최대 / 최솟값을 반환함.

console.log(Math.max(1, 2, 3, 4, 5)); // 5
console.log(Math.min(1, 2, 3, 4, 5)); // 1

 

Math.pow(n, power)

n을 power에 들어간 숫자만큼 거듭제곱함.

alert( Math.pow(2, 10) ); // 2의 10제곱 = 1024

 

Math 더 많은 함수와 상수를 알고 싶다면  MDN 문서

 

 

공부한 곳! -  모던 JavaScript 튜토리얼

https://ko.javascript.info/number

'JS' 카테고리의 다른 글

18-2 JS 문자열2  (0) 2022.11.18
18-1 JS 문자열1  (0) 2022.11.16
16 JS 원시값의 메서드  (0) 2022.11.11
15 JS 객체를 원시형으로 변환하기  (0) 2022.11.10
14 JS 심볼형  (0) 2022.11.09