-
[TIL] (230616) 분명 정상 코드이고 값도 잘 출력 되는데 틀린 답이라고 한다 -> 조건의 최대 범위를 꼭 확인하자.TIL 2023. 6. 16. 19:11728x90
오늘은 조건문과 반복문을 사용할 수 있는 기본예제 + 심화학습을 위해 프로그래머스의 코딩테스트 문제풀이를 진행했다.
무리 없이 풀어나가던 중 코드 실행 시 에러 메시지 없이 정상으로 출력되나 정답으로 제출하니 실패로 제출불가라는 메시지를 받았다.
어디가 어떻게 잘못된 건지 확인해 보자.
🔸문제 발생
문제링크: https://school.programmers.co.kr/learn/courses/30/lessons/82612#%EF%BB%BF
- 조건
기본입장료는 price이나 놀이기구를 N번째 이용한다면 다음 회차부터는 이용료의 N배를 내야 한다.
놀이기구를 count번 타게 되면 현재 자신이 가지고 있는 금액에서 얼마가 모자라는지를 return 하도록 solution 함수를 완성하라.
단, 금액이 부족하지 않으면 0을 return 함
* price : 1 ≤ price ≤ 2,500
* money : 1 ≤ money ≤ 1,000,000,000
* count : 1 ≤ count ≤ 2,500
-price, money, count는 모두 자연수✅ 처음 기재한 코드
class Solution { public long solution(int price, int money, int count) { long answer = -1; for(int i=1; i<=count; i++){ money -= price * i; } answer = (money < 0)? (long)money * (-1):0; return answer; } }
✅ 실행 결과 ( 부분 실패 뜸)
문제에서 요구하는 조건을 모두 기입했고, 중간 테스트도 정상이었는데 딱 19~22번 테스트에서만 실패가 떴다.
에러 메시지가 나왔다면 그 부분을 중점적으로 보고 고민하겠으나 이번 오류는 어디서부터 잘못된 건지, 아니 정말 잘못된 건 맞는 건지
한참을 고민하며 하나씩 점검해 보았다.
🔸시도해 본 것
일단 그동안의 경험상 처음부터 오류가 아니라면 코드의 진행 방향은 잘 잡았으나 구조적인 문제였던 걸 떠올렸다.
1. 첫 번째로 answer이 long형인데 price * i -> int형으로 반환되는 게 원인이라고 생각하여 (long)으로 직접 형변환을 시도했다(실패)
2. 두 번째로 answer = (money < 0)? (long) money * (-1):0; 역시 (-1)때문에 answer과 타입이 맞지 않는 것 같아서 여기도 (long)으로 형변환을 시도했다. (실패)
3. 세 번째로는 정말 모르겠어서 눈에 보이는 숫자형 타입의 변수를 전부 long 타입으로 바꿔봤다.(성공)
답은 무사히 제출되었으나 오히려 나는 더 깊은 의문에 빠졌다.
그 이유는 무작정 (long)으로 형변환을 하기 전에 int의 범위를 한번 더 찾아보고 또 price * i의 최댓값을 따로 실행해 보았기 때문이다.
각각 최댓값인 2500으로 설정하고 모두 더 해봤을 때 -774,309,592로 7억대가 나왔고, 만약 money가 최솟값인 1이라고 해도 int의 범위 약 -21억~21 억내에 존재한다고 생각했기 때문이다.
count는 반복문에 사용되었으니 확실히 관련이 없기 때문에 price와 money에서 문제 되는 변수가 하나인지 둘 다였는지 검수를 해봤다.
실행결과 int price int money 성공 long long 실패 long int 성공 int long money가 문제였고 주어진 범위는 최대 10억이었기 때문에 매개변수로 받아오는 값이 아닌
설정한 코드 money -= price * i;
즉, price * i가 문제였던 것으로 생각되어 값을 출력값을 다시 보았다.
...
아예 반복문에 출력문을 함께 찍어서 보니 중간에 값이 이상하게 나온 걸 확인할 수 있었고 등차수열의 합을 이용하여 직접 계산해 보았다.
첫항: 2500
마지막항: 2500*2500
n = 2500
-> 2500(2500+2500*2500)/2 = 7,815,625,000 (약 78억)
이러니 int money에서 오류가 발생하는 게 당연했다.
그리고 b를 long타입으로 변경 후 한번 더 계산해 봤다. (계산값 일치)
int형으로 표현할 수 있는 범위를 벗어나서 발생한 문제가 맞았다!!
🔸해결
👇 long형의 변수로 저장받고 내야 할 금액과 가지고 있는 금액의 비교로 진행하기.
class Solution { public long solution(int price, int money, int count) { long answer = 0; for(int i=1; i<=count; i++){ answer += price * i; } return (answer < money)? 0: answer-money; } }
price * i가 int의 범위를 벗어난다면 해결할 수 있는 방법은 여러 가지가 있지만 나는 이 세 가지가 바로 생각났다.
1. 애초에 매개변수를 int형이 아닌 long타입으로 받기
ex) public long solution(int price, long money, int count)
2. int형으로 넘어온 변수를 long으로 다시 변환 후 계산하기
ex) long longMoney = money;
3. ★ price * i를 long 변수로 받고 money값과의 대소비교로 return 하기 - 위의 코드 참조
1번의 경우 문제의 의도와 벗어난 것으로 간주했고
2번의 경우 사용할 변수가 하나 더 늘어나기 때문에 비용적인 관점에서 선택하지 않았다.
🔸알게 된 점
주어진 조건에 범위가 있다면 반드시 최솟값, 최댓값일 때의 유효성을 검사해 보자.
지금까지는 int형의 표현값을 벗어나는 상황을 만난 적이 없어서 표현값의 범위라는 것에 대해 안일하게 생각했었다.
다른 코드오류와는 달리 어떠한 메시지도 뜨지 않기 때문에 지금처럼 틀렸다고 알려주지 않았다면 영원히 몰랐을 것이다.
그리고 이게 실제 프로젝트였다면 다른 코드도 많아서 어느 부분의 오류인지 찾기가 정말 힘들었을 거고 그 작은 실수가 걷잡을 수 없는 오류를 만들게 될 것이다.
이번일을 계기로 받아온 매개변수의 타입과 계산을 진행해야 하는 변수의 타입이 불일치할 경우 새로운 변수로 다시 받아서 형태를 맞추거나 직접 계산하지 않고 서로의 값을 비교하는 방식이 더 안전하다는 것을 깨달았다.
앞으로는 조건이 주어지면 값의 표현범위를 먼저 확실하게 체크해야겠다.
728x90'TIL' 카테고리의 다른 글