[TIL] 알고리즘 문제를 풀면서 궁금했던 사소한 것들
알고리즘 문제를 풀다보니 몇가지 사소한 궁금증이 쌓여있었다.
나름대로 검색해봐도 명쾌한 답을 찾기가 어려웠는데,
멘토님께 여쭤보고나서 드디어 정리가 되었다.
동등비교연산자 == VS ===
왠지 보기에 조금이라도 깔끔한게 좋아서 “” 보다는 ‘‘를 사용하거나
=== 보다 ==를 사용할때가 많았다.
=== 비교와 == 비교에 차이가 있다는 것은 알았지만,
타입까지 비교할 필요가 없는 경우가 대부분이었기때문에 그냥 == 를 주로 활용해왔다.
그런데 가끔 == 로는 안풀리는 효율성 테이스트케이스들이 있었다.
그럴때 마다 궁금했는데 이제 정리가 좀 되었다.
동등비교연산자를 사용할때 === 를 사용하는 것이 좋다.
== 연산은 타입을 제외하고 값만 비교하기 위해
두 데이터를 같은 타입으로 만드는 강제 형변환이 일어난다.
자바스크립트에는 falsy값이라는게 있는데,
false
0
""
의 세가지 값은 모두 false 형태로 강제 형변환되어
== 연산으로 비교했을때 같은 값이라고 나타난다.
null
undefined
를 비교할때도 둘은 같은 값이라고 나온다.
NaN
은 어떤 값과도 동일하지 않다고 나오고,
심지어 NaN == NaN
도 결과는 false가 된다. (도대체 왜…?)
=== 연산이 오히려 거치는 단계가 적은 것
위 내용들을 찾다보니 내가 착각하고 있던 부분을 알게되었다.
나는 타입까지 비교하는 === 가 더 많은 단계를 거쳐 연산하는 것이라 생각했다.
그런데 반대로 == 연산이 타입을 제외하고 비교하기위해
오히려 타입을 한가지로 변환시키는 과정이 더 필요했고 그래서 효율성 테스트케이스에서 차이가 났던 것 같다.
const 와 let의 사용
나는 사실 알고리즘 문제를 풀면서도 const와 let을 의도에 맞게 구분해서 쓰는 것이 좋았다.
그런데 여러 예제나 강의를 들으면서 빠른 구현에 초점을 두고 모두 let으로 사용해도 상관없구나 싶어서 또 한동안은 let만 사용했다.
그런데 둘의 사용 차이로도 효율성 테스트케이스에 영향이 있는지 궁금했다.
var
let
const
사용시 성능에 대한 글은 2017년쯤에나 몇개 있었다.
그리고 그마저도 지금은 성능 비교가 무의미하다는 의견들이었다.
비교할 수 있는 예제코드를 만들어 차이를 측정해보고 싶었는데
어떻게 그런걸 설계해서 테스트해볼 수 있을지 아직 잘 모르겠다.
그런데 어쨌든 const
와 let
을 성능상으로 비교하는것이 무의미하다면
일반 코딩 작업시에는 되도록 const
를 먼저 사용해서 의도치 않게 값이 변하지 않도록 제어해주는 것이 좋겠다.
만약 알고리즘 문제를 빠르게 풀어야하는 상황이면 깊게 고민하지 않고 모두 let
처리해도 상관 없겠다.
parseInt와 Math.floor
알고리즘 문제를 풀다보면 뒤의 소수점을 버림처리해야하는 경우가 많다.
특히 최근에는 이진탐색을 공부하다보니 mid값을 구하느라
let mid = parseInt((start + end) / 2)
를 자주 사용했다.
그런데 멘토님께서 parseInt
보다 Math.floor
를 사용하는 편이 낫다고 알려주셨다.
왜일까?
1
2
3
4
5
console.log(parseInt(1.25)); // 1
console.log(Math.floor(1.25)); // 1
console.log(parseInt(-1.25)); // -1
console.log(Math.floor(-1.25)); // -2
우선 음수를 처리할때 둘은 다른 값을 나타낸다.
parseInt
는 소수 뒷자리를 버림 처리해 앞자리 숫자만 반환하고
Math.floor
는 소수값을 내림 처리해서 소수점 앞자리 숫자보다 낮은 수가 반환된다.
Math.floor
를 버림처리 하는 메소드라고 생각했는데 자세히 다시보니 이것은 내림 처리를 하는 메소드다.
거의 양수값만 처리하다보니 내림과 버림의 차이를 잊고있었다.
그리고 둘은 성능의 차이도 있다.
parseInt
보다는 Math.floor
가 더 빠르다고 한다.
생각해보면 parseInt
는 애초에 문자를 파싱해서 특정진수의 숫자로 변환해주는 메소드이다. 값을 파싱한다는 것 자체가 데이터를 분해하고 분석해서 어떤 결정을 내린다는 것이다.
Math.floor
는 단순히 숫자를 처리하기 위한 메소드이기 때문에
parseInt
와는 내부에서 거치는 단계 자체가 다를 것 같다.
그래서 앞으로는 이 세가지 메소드를 적극 활용해야겠다.
- 내림처리
Math.floor()
- 버림처리
Math.trunc()
- 올림처리
Math.ceil()
parseInt와 Number
parseInt
에 대해 생각하다보니 Number
와의 차이도 그때그때 가볍게 찾아보고 지나와서 다시 정리해본다.
문자를 숫자로 변환할때 사실 두가지 메소드 차이에 집중해서 문제를 풀어야 하는 경우는 없었지만 항상 고민은 되었다.
1
2
3
4
5
6
7
8
9
10
11
console.log(parseInt("001")); // 1
console.log(Number("001")); // 1
console.log(parseInt("123가나다")); // 123
console.log(Number("123가나다")); // NaN
console.log(parseInt("가나다123")); // NaN
console.log(Number("가나다123")); // NaN
console.log(parseInt(1.25)); // 1
console.log(Number(1.25)); // 1.25
Number
는 문자열 전체가 숫자로 구성되어있지 않으면 NaN를 나타낸다.
소수점의 경우 어쨌든 숫자이기때문에 소수점 그대로 나타낸다.
parseInt
는 문자열 전체가 숫자가 아니라도 앞부분에 숫자가 있으면
숫자가 있는 만큼만 뽑아서 나타낸다. 숫자가 뒤에있으면 NaN가 나온다.
소수점의 경우 정수만 뽑아서 표시된다.
위에서 확인했듯이 parseInt
는 입력된 문자를 정수형으로 반환해서 특정 진수로 표현하는 것이 기본이고, 몇진수로 변환할지 입력하지 않으면 기본적으로 10진수를 출력하기 때문이다.
그래서 결국 이것도 성능상으론 심플하게 문자를 숫자로 바꾸기만하는 역할의 Number
메소드를 사용하는것이 좋겠다.
Leave a comment