PS 공부의 바이블 중 하나인 '알고리즘 문제 해결 전략 세트'에서는 아래와 같은 'PS 시 하기 쉬운 실수들'에 대해 정리해놓았다. 이는 분명 앞으로 PS 뿐만 아니라 모든 유형의 코딩을 함에 있어서 충분히 도움이 될만한 사항이라 판단해 Velog에 한 번 더 정리하고자 한다. 단, 너무 세부적으로 정리하기 시작하면 끝이 없으므로, 제목과 간단한 사항만 적는 식으로 정리한다. 어차피 내가 보려고 만드는 것이므로.
1) 실수 자료형의 비교 및 코드의 수치적 안정성
=> IEEE 754에서 부동 소수점 방식(소수점이 둥둥 떠다니는 방식, 즉, 우리가 Exponent와 Mantissa를 조정해 표현가능한 실수의 크기 범위를 조정)으로 실수를 표현함을 인지하고, 이 과정에서 실수의 비교를 위해 절대 오차와 상대 오차 개념을 사용해야함을 기억하자. (다른 포스팅에서 다룬 바 있다)
2) 산술 Overflow, 특히나 중간값에서의 발생 주의
=> 특정한 수식의 중간 부분에서 산술 오버플로우가 발생할 수 있음을 늘 인지하자. 예를 들어 최소공배수 LCM을 구하는 수식이나, 또는 Combination 등의 계산 말이다. 중간 과정에서 정수 자료형의 크기를 벗어나는 값의 발생을 방지하기 위해 곱하기와 나눗셈의 순서를 바꾸거나, 또는 알려진 특수한 관계식(예를 들어 조합 계산 시 사용되는 Pascal's Identity)을 적절히 이용하자.
3) 디버깅 및 테스팅
=> 굳이 언어에서 제공하는 정석 디버깅 프로세스를 따를 필요가 없음을 인지하는 것이 중요. 평소 내가 하던 것처럼, 눈버깅(눈으로)이나, 중간값 출력 등의 방식이 결코 나쁜 방식이 아님을 인지하자.
4) 여러 번의 Test Case가 있는 경우, 전역 변수의 초기화를 반드시 기억
=> 제목이 곧 내용
5) 너무 느린 입출력 방식
=> 입력 또는 출력이 방대한 경우 입출력 함수의 종류도 충분히 영향을 줄 수 있음. 이미 알고 있는 것처럼, cin과 cout의 경우
ios_base::sync_with_stdio(false);
cin.tie(null);
를 사용하여 stdio에 근접하게 속도를 향상시킬 수 있다.
6) 연산자 우선순위에 주의하라.
=> 솔직히 각 연산자 간의 우선순위 관계를 다 외우는 것은 어려우므로, 헷갈릴 경우 ()를 사용하는 것이 바람직하다.
7) 입력의 최소와 최대에서 발생할 수 있는 예외 주의
=> 제목이 곧 내용
8) 너무 깊은 재귀에서 발생하는 Stack Overflow
=> STL 컨테이너는 Stack 대신 Heap에 메모리를 두므로, STL을 적극 사용한다.
9) 배열 인덱스 주의
=> 배열을 사용할 때, 인덱스의 범위를 일관되게 통일하고, 범위 밖의 인덱스에 접근하는 실수를 늘 유의하자. 또한, 다차원 배열에서 행/열/높이 등의 인덱스의 의미 관계 등을 정확히 규정하는 것도 중요하다.
10) Off-by-one Error
=> 특히나 A[i]부터 A[j]까의 평균을 구하는 상황에서 j - i + 1이 아니라 j - i로 나눌 때 발생할 수 있다.