JS/[web] 코어 JS 튜토리얼

[코어 JS] 5.2 - 숫자형

web_seul 2021. 10. 18. 14:50
반응형

5.2 숫자형

숫자형

모던 JS에서 숫자를 나타내는 두가지 자료형

1. 일반적인 숫자는 '배정밀도 부동소수점 숫자(double precision floating number)'로 알려진 64비트 형식의 IEEE-754에 저장

2. 임의의 길이를 가진 정수 BigInt, 일반적인 숫자의 범위 2-53 ~ 253 밖의 숫자

 

숫자를 입력하는 다양한 방법

let billion = 1000000000; //0의 갯수가 많아서 오류가 생길 수 있음

let billion = 1e9;  // 10억, 1과 9개의 0
alert( 7.3e9 );  // 73억 (7,300,000,000)

'e' 의 오른쪽에 오는 수만큼 10의 거듭제곱

1e3 = 1 * 1000
1.23e6 = 1.23 * 1000000

 

1마이크로초(백만 분의 1초)

let ms = 1e-6; // 1에서 왼쪽으로 6번 소수점 이동

'e' 의 오른쪽에 음수가 있으면 음수의 절대값만큼 10을 거듭제곱한 수로 나눔

 

16진수, 2진수, 8진수

alert( 0xff ); // 255
alert( 0xFF ); // 255 (대·소문자를 가리지 않으므로 둘 다 같은 값을 나타냅니다.)

16진수 : 0x / 2진수 : 0b / 8진수 : 0o

let a = 0b11111111; // 255의 2진수
let b = 0o377; // 255의 8진수

alert( a == b ); // true, 진법은 다르지만, a와 b는 같은 수임

JS는 2, 8, 16진법을 지원함, 이 외의 진법은 parseInt를 사용

 

toString(base)

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

let num = 255;

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

base는 2~36까지 사용가능하며 기본값은 10

- base=16 : 16진수 색, 문자 인코등 등을 표현할 떄, 0~9, A~F 사용

- base=2 : 비트 연산 디버깅에 주로 사용, 숫자0 또는 1

- base=36 : 사용할 수 있는 base 중 최댓값으로 0~9, A~Z 를 사용해 숫자 표현, url을 줄이는 것과 같이 숫자로 된 긴 식별자를 짧게 줄일때 유용 ??? url을 줄이는것..???  예시 이해못함

alert( 123456..toString(36) ); // 2n9c

 

! 점 두개와 메서드 호출

숫자를 대상으로 메서드 toString을 직접 호출할 때 ..를 붙임

12345.toSting(36)처럼 점을 하나만 사용하면 첫번째 점 이후는 소수부로 인식되어 error, 점을 하나 더 추가하면 JS는 소수부가 없다고 판단하고 함수 호출

(12345).toString(36)도 가능

 

어림수 구하기

Math.floor 소수점 첫째 자리에서 내림(버림) ex) 3.1 -> 3, -1.1 -> -2

Math.ceil 소수점 첫째 자리에서 올림 ex) 3.1 -> 4, -1.1 -> -1

Math.round 소수점 첫째 자리에서 반올림 ex) 3.1 -> 3, 3.6 -> 4, -1.1 -> -1

Math.trunc(ie x) 소수부 무시 ex) 3.1 -> 3, -1.1 -> -1

 

소수점 n번째 기준으로 어림수 구하기

1. 곱하기와 나누기

10의 거듭제곱 수를 곱한 후 원하는 어림수 내장함수 호출하고 다시 나누기

let num = 1.23456;

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

 

2. 소수점 n번째 수까지의 어림수를 구한후 문자형으로 반환하는 toFixed(n) 메서드 사용

toFixed는 Math.round와 유사하게 가장 가까운 값으로 올림 혹은 버림, 

반환값이 문자열이라 소수부의 길이가 인수보다 작으면 끝에 0추가

let num = 12.34;
alert( num.toFixed(1) ); // "12.3"

let num = 12.36;
alert( num.toFixed(1) ); // "12.4"

let num = 12.34;
alert( num.toFixed(5) ); // "12.34000", 소수부의 길이를 5로 만들기 위해 0이 추가되었습니다.

+num.toFixed(5)처럼 단항 덧셈 연산자를 앞에 붙이거나 Number()를 호출하면 숫자를 숫자형으로 변환 가능

 

부정확한 계산

숫자는 내부적으로 64비트 형식 IEEE-754으로 표현되기때문에 숫자를 저장하려면 정확히 64비트가 필요,

64비트 중 52비트는 숫자 저장, 11비트는 소수점 위치 저장(정수는 0), 1비트는 부호 저장

숫자가 너무 커질경우 64비트 공간이 넘쳐서 infinity로 처리

alert( 1e500 ); // Infinity

정밀도 손실(loss of precision)

alert( 0.1 + 0.2 == 0.3 ); // false
alert( 0.1 + 0.2 ); // 0.30000000000000004

숫자는 0과 1로 이루어진 이진수로 변환되어 연속된 메모리 공간에 저장되는데 0.2, 0.2와 같은 분수는 이진법으로 무한 소수가 되므로 IEEE-754 에서 가능한 가장 가까운 숫자로 반올림

alert( 0.1.toFixed(20) ); // 0.10000000000000000555

두 숫자를 더하게되면 정밀도 손실도 같이 더해짐

 

! JS뿐만이 아닙니다

JS와 동일한 숫자 형식을 사용하는 PHP, Java, C, Perl, Ruby 에서 같은결과 발생

 

해결

toFixed(n)메서드를 사용해 어림수 만들기

문자열을 반환하기 때문에 소수점 다음 숫자는 항상 2개

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의 거듭 제곱수 곱하기, 연산 후 다시 나누기

소수 대상의 연산보다 에러가 적지만 결과값에서 수소발생 가능

alert( (0.1 * 10 + 0.2 * 10) / 10 ); // 0.3
alert( (0.28 * 100 + 0.14 * 100) / 100); // 0.4200000000000001

소수점 아래를 완전히 차단해야하는 경우는 어림수를 만드는 방법 뿐

 

! 흥미로운 발견

// 숫자가 스스로 증가하네요!
alert( 9999999999999999 ); // 10000000000000000이 출력됩니다.

숫자를 저장할 때 사용되는 64비트 중 실제 숫자를 저장하는 52비트의 저장공간 부족으로 최소 유효 숫자(the least significant digit)가 손실되는 정밀도 손실 발생, JS에서 오류가 발생하지는 않음

! 두 종류의 0

JS에서 숫자의부호가 단일 비트에 저장되는데 0을 포함한 모든 숫자를 부호에 설정하거나 설정하지 않을 수 있음, 연산에서의 차이는 두드러지지 않는 편

 

isNaN과 isFinite

- Infinity와 -Infinity 그 어떤 숫자보다 큰 혹은 작은 특수 숫자값

- NaN 에러를 나타내는 값

두 특수 숫자는 숫자형에 속하지만 '정상적인' 숫자형이 아니므로 정상 숫자와 구별하기 위한 특별한 함수 존재

- isNaN(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) );

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

 

! Object.is와 비교하기

Object.is는 === 처럼 값을 비교할 때 사용되는 특별한 내장 메서드로 ===보다 더 신뢰할 수 있는 결과를 보여주는 경우가 있음

1. NaN을 대상으로 비교할 때 : Object.is(NaN, NaN) === true

2. 0과 -0이 다르게 취급되어야 할 때 : Object.is(0, -0) === false

이 외의 경우에서는 Object.is(a, b)와 a===b 의 결과는 동일, 비교 결과가 정확해야 하는 경우 Object.is 사용, Object.is에서 사용되는 비교방식을 SameValue로 부름

 

parseInt와 parseFloat

단항 덧셈 연산자 + 또는 Number()를 사용하여 숫자형으로 변형할 때 적용되는 규칙은 엄격하여 피연산자가 숫자가 아닐 경우 형 변환 실패

alert( +"100px" ); // NaN

문자열의 처음 또는 끝의 공백을 무시할 때는 규칙적용x

100px, 12pt와 같이 단위가 함께 오는 경우 숫자만 추출하기 위한 함수 parseInt, parseFloat

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는 숫자가 아니므로 숫자를 읽는 게 중지됩니다.

 

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

parseInt()의 두번째 매개 변수는 선택적 사용가능하므로 radix로 원하는 진수 설정 가능, parseInt를 사용하면 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

 

요약

0이 많이 붙은 큰 숫자 요약 방법

- 0의 개수를 'e'뒤에 추가 ex) 123e6 = 123000000

- 'e' 다음에 음수가 오면 음수는 절댓값만큼 10을 거듭제곱한 수로 나눔 ex) 123e-6 = 0.000123

다양한 진법 사용

- JS는 특별한 변환없이 16진수(0x), 8진수(0o), 2진수(0b)를 바로 사용하도록 지원

- parseInt(str, base)를 사용하면 str을 base진수로 바꿔줌(단 2<=base <= 36)

- num.toString(base)는 숫자를 base진수로 바꾸고, 이를 문자열 형태로 반환함

단위가 있는 값을 숫자로 변환하기

- parseInt/parseFloat를 사용하면 문자열에서 숫자만 읽고 읽은 숫자를 에러가 발생하기 전에 반환하는 '약한' 형변환

소수를 처리하는데 쓰이는 메서드

- Math.floor, Math.ceil, Math.trunc, Math.round, num.toFixed(precision)를 사용하여 어림수 구하기

- 정밀도 손실에 주의

 

 

 

반응형