두 수를 인자로 받고, 리턴값으로 두 수의 나머지를 표현하는 함수를 작성하라
- 조건 1. % 연산자를 활용하지 마라. -> % 연산자를 함수로 만들어라
- 조건 2. 수를 이해하는 것에서 ‘나머지’를 구하는 연산 자체를 이해해라.
놀랍겠지만, 나는 수학적으로 나머지를 구하는 방법을 알지 못했다. 나머지에 대해서 생각해본것이 초등학교 1학년? 2학년까지 였지 싶다. 그래서 이 문제를 만나고 적지 않게 당황했다.
그래도 수학을 좋은 선생님께 배우긴 했던 것 같다. ‘모르면 대입하라고.’ 선생님은 말했다. 맞다. 대입을 해보면 된다. 경우의 수를 찾고 경우에 따른 모든 실행을 진행하면 된다. 그리고 규칙을 발견하면 ‘유레카!’
그래서 풀어낸 나의 첫 번째 코드는 아래와 같다. (길고, 무식하지만 우직하달까.)
function modulo(num1, num2) {
// 1. 둘 중 하나가 NaN 인지 아닌지
if (num1 === NaN || num2 === NaN){
return NaN;
} else {
// 2. num1, num2 중 하나가 0 일때
if (num1 === 0) {
return 0;
} else if (num2 === 0) {
return NaN;
} else if (num1 === 1){
return 1;
} else if (num1 === -1){
return -1;
} else if (num1 === num2){
return 0;
} else if (num1 > num2) {
if (num1 > 0 && num2 < 0) {
let numPlus2 = num2 * -1
return (num1 - Math.floor(num1/numPlus2) * numPlus2) ;
} else if (num1 > 0 && num2 > 0){
return num1 - Math.floor(num1/num2) * num2;
} else if (num1 < 0 && num2 < 0){
return num1;
}
} else if (num1 < num2){
if (num1 > 0 && num2 > 0){
return num1
} else if (num1 < 0 && num2 > 0){
let numPlus = num1 * -1;
return (numPlus - Math.floor(numPlus/num2) * num2) * -1;
} else if (num1 < 0 && num2 < 0){
let numPlus = num1 * -1;
let numPlus2 = num2 * -1;
return (numPlus - Math.floor(numPlus/numPlus2) * numPlus2) * -1;
}
}
}
}
-> 와우. 이게 뭔가. 모든 과정을 다 경우로 따져서 계속 반복하여 콘솔에 값을 입력했다. 그래도 얻은 것은 나머지를 이해했다는 사실이다.
- (두 수가 모두 양수일 때) 큰 수를 작은 수로 나눌때의 나머지는 두 수의 차이가 작은 수가 되기 직전까지 빼주고 그 때의 값이 나머지!
- 딱 0으로 되면 값은 0이다.
- 결국 나머지는 양수의 값들의 크기를 비교하면서 계속 빼고, 음수일 때 ‘-‘ 기호를 결과에 붙여주면 된다.
그래서 아래와 같은 코드 리펙토링 과정을 거치게 되었다. 이 모든 것은 경우의 수를 모두 따진 결과라고 할 수 있다.
문제를 쪼개서 풀어보자 1. - 두 개의 수를 인자로 받고, NaN을 결과로 뱉는 함수를 먼저 설정하자.
function getRest (num1, num2){
// 단계 1. num2가 NaN or 0 이라면 나누기 자체가 성립하지 않아!
if (num2 === NaN || num2 === 0) {
return NaN;
}
}
문제를 쪼개서 풀어보자 2. - 절대값을 취해주고, 그 전에 결과에 +/- 를 변환하는 매직을 하나 쓰자!
function getRest (num1, num2){
// 단계 1. num2가 NaN or 0 이라면 나누기 자체가 성립하지 않아!
if (num2 === NaN || num2 === 0) {
return NaN;
}
// 단계 2. 결과값에 +/-를 자동으로 붙여줄 매직을 하나 부려본다.
// 삼항 조건 연산자를 이용해서 인자로 들어온 num1, num2 값에 대한 +/- 설정을 해준다.
let plusMinus = num1 > 0 ? 1 : -1
// 단계 3. 우리는 큰 수에서 계속 작은 수를 빼야하기 때문에 절대값을 취해야 한다.
num1 = Math.abs(num1)
num2 = Math.abs(num2)
}
-> 단계 2를 단계 3보다 위에 작성한 것은 절대값을 취하면 모든 수는 양수가 되기 때문이다.
문제를 쪼개서 풀어보자 3. - 조건안에서 나머지를 구하는 반복을 취하고 값을 내자
function getRest (num1, num2){
// 단계 1. num2가 NaN or 0 이라면 나누기 자체가 성립하지 않아!
if (num2 === NaN || num2 === 0) {
return NaN;
}
// 단계 2. 결과값에 +/-를 자동으로 붙여줄 매직을 하나 부려본다.
// 삼항 조건 연산자를 이용해서 인자로 들어온 num1, num2 값에 대한 +/- 설정을 해준다.
let plusMinus = num1 > 0 ? 1 : -1
// 단계 3. 우리는 큰 수에서 계속 작은 수를 빼야하기 때문에 절대값을 취해야 한다.
num1 = Math.abs(num1)
num2 = Math.abs(num2)
// 단계 4. 조건이 있는 반복문? -> while!
// 큰 수가 num2 보다 작아지기 전까지 반복하자!
while (num1 >= num2) {
num1 = num1 - num2
}
// 단계 5. 결과에는 +/- 구분이 필수!
return num1 * plusMinus
}
결과적으로 위의 정답같은 코드를 이해하는 과정까지 많은 시간이 필요했다. 왜 plusMinus의 위치가 반드시 절대값 위인지를 알기 위해서 모든 경우를 다시 콘솔에 찍었다. ;; 그래도 그 과정이 좋은 과정이었음을 의심하지 않기로 했다!