분수의 덧셈
프로그래머스에서 분수의 덧셈 문제를 풀었다.
다른 기본적인 구현은 하실 줄 아는 상황에서 두 분이 이 문제를 가져오셨다.
이 문제에서 요구되는 바는 다음과 같다.
1. 분수의 더하기, 빼기 등의 연산
2. 기약분수의 이해
얼추 예시들을 보고 유추할 수 있겠지만
해결하는 방법에 있어서는 분수에대한 정보는 필요했다.
우선, 분수는
전체의 일부, 동일한 부분의 수 로 정의된다.
( 무언가를 할때 정의는 굉장히 중요하다.
이는 내가 무엇을 해야할지 정확히 알 수 있기 때문이다. )
분수는 또한 비율로 표시된다.
예를들면, 1/2 는 전체를 2등분 한 것중 1개만큼의 크기라는 뜻이된다.
그리고 2/4를 보면 전체를 4등분 한 것중 2개만큼의 크기로 실질적으로 1/2와 같은 크기가 된다.
이는 비율의 특성이다.
여기서 우리는 분모, 분자에 같은 크기를 곱하거나 나눈다면, 실제 값은 동일하다는 것을 알 수 있다.
이렇게 설명한 김에 이번에는 기약분수를 알아보자.
기약분수는 분모와 분자가 1을 제외한 같은 수로 나누어 떨어지지 않는 상태이다.
( 나누어 떨어진다 했으니 우리는 기본적으로 정수의 범위에서 생각해야 함을 알 수 있다. )
즉, 2/4는 2로 분모와 분자가 모두 나누어 떨어져서 1/2가 됨 을 알 수 있다.
또한 1/2는 1을 제외하고 나누어 떨어지도록 만드는 수가 없기때문에
기약분수 상태임을 알 수 있다.
분수에 대해 알아보았으니,
이번에는 분수의 연산을 알아보자.
1/2 + 1/3 을 생각해보자.
케이크로 생각해본다면,
분수는 분모의 갯수 만큼의 동일한 조각으로 나눈 것중에, 분자 만큼의 갯수를 의미하게 될 것이다.
1/2와 1/3은 간단히 생각해보아도 크기가 다를 것이다.
케이크 절반과 1/3개를 더하면 그건 케이크의 몇분의 몇 만큼의 크기일까?
이것이 1/2 + 1/3 이다.
그대로 연산하게 된다면 우리는 알 수 없다.
하지만 위에서 언급한 비율의 특성을 고려한다면 더할 수 있게된다.
비율의 특성상, 분모와 분자에 같은 수를 곱하거나 나누어도 우리는 같은 값이 됨을 보았다.
그러면 조각의 크기를 맞추면 연산을 할 수 있을 것이다.
1/2 -> 3을 곱해 -> 3/6
1/3 -> 2를 곱해 -> 2/6
이 될 것이고, 우리는 조각의 크기가 같아졌으니 이를 더할 수 있게 됐다.
5/6이 결과 값이 될 것이고, 더이상 같은 수로 나누어 떨어지지 않으니 이는 기약분수가 될 것이다.
이처럼, 우리는 분수의 연산과 기약분수를 구할 수 있게 되었으니
해당 문제를 풀 수 있을까?
사실, 우리는 머리속으로 그동안 익숙하게 봐온 숫자들로 인해
2와 3을 6으로 만들면 된다는 것을 알 수 있었고,
5/6이 기약분수임을 5와 6이 나누어 떨어지지 않으므로 될 것이다.
라는 생각을 하고있다.
만약 숫자가 좀 더 크고 복잡해진다면 어떤가?
읽는 사람마다 다르겠지만
1/13579 + 1/2468910 이라면 어떤가?
나는 대충 쓴 숫자라 모르겠다.
대신 원리를 알기때문에 어떻게 구할 수 있을지 방법을 알 뿐이다.
그리고 이 원리를 이용하면
컴퓨터가 어떻게 수행하게 할지 코딩을 할 수 있게 될 것이다.
우선 많이들 잊고있던 개념인 최소공배수와 최대공약수의 개념을 알아보자.
수업한 분중 3분께 기억이 나는지 여쭤보았지만
3분다 기억이 안난다고 하셨다.
그러니 이 글을 보는 분들 중 이게 기억이 안난다고해서 부끄러워하지말자
대신 이번에는 알아가자.
먼저 최대공약수를 보자.
뜻부터 살펴보자, 최대는 가장 큰 것이고
공약수는 공통의 약수이다.
약수는 해당 값을 나누어 떨어뜨리는 숫자이다.
( 모두 여기서는 정수를 사용한다. 3에 1.5를 나누면 2가 된다고 해서 1.5는 3의 약수라고 표현하지 않는다.
또한, 음수도 일반적으로 사용하지 않는다. 4에 -2를 나눠서 -2가 되고 나머지가 0이라해서 -2를 -4의 약수라고 표현하진 않는다.
대신 개념은 확장해서 활용할 수 있으니 일반적으로 그렇게 사용한다는 것만 알아두자. )
( 0은 무언가를 나눌 수 없다. 극한에서는 유사하게 사용하는 개념이 있지만 혼동하지 말자.
0으로 나누는 것에대한 재미있는 수학적,프로그래밍적 논리등이 있으니 궁금하면 찾아보도록 하자. )
약수의 예시를 보자,
4는 1 2 4 의 약수를 갖게된다.
6은 1 2 3 6 의 약수를 갖게된다.
그리고 이러한 약수중에 공통의 약수를 우리는 생각해 볼 수 있는데,
이는 약수는 나누어 떨어지게 만드는 숫자이고,
이러한 공통의 약수는 분수에서 분모와 분자를 둘 다 나누어 떨어지게 만드는 숫자이기 때문이다
즉, 기약분수를 만드는 방법이 될 것이다.
그런데 공통의 약수가 100개쯤 된다면, 이 걸 100개나 나눠보기는 싫을 것이다.
약수는 어차피 곱하기로 이루어져있고,
분자와 분모를 공통으로 나눈다는 것의 반복은 여러 개의 약수를 곱하고, 그걸로 한번에 나누는 것과
같기 때문이다.
이 부분이 조금 갑자기 점프한 느낌이 드는 분이 있을 수 있으니
좀 더 설명을 해보겠다.
100
ㅡㅡㅡ
120
이라는 분수가 있다고 하자, 표기가 갑자기 달라졌지만 알다시피 100/120 이다.
여기서 분모와 분자를 2로 나누어 보자.
100
ㅡ
2
ㅡㅡㅡ
120
ㅡ
2
가 될 것이다.
한번 더 2로 나누어 보자.
100
ㅡ
2 * 2
ㅡㅡㅡ
120
ㅡ
2 * 2
가 될 것이다.
이처럼 분모와 분자를 나누는 행위의 반복은
그 나누는 값들의 곱을 나누는 것과 결과가 같다.
즉, 곱하기로 이루어진 가장 큰 약수로 나누는 것은
한번에 기약분수로 만드는 결과 값을 가져올 수 있다.
다른데서도 많이 쓰이겠지만, 우선 최대공약수의 이유과 용도를 짐작할 수 있을것이다.
다시 약수로 돌아와서
4는 1 2 4가 약수이고,
약수의 곱으로 4를 표현하게 된다면
4 = 1 * 2 * 2
가 될 것이다. 지금은 자기 자신을 써버리는 순간 약수의 곱으로 표현하는 것이 아닌 그냥 그 자체가 되어버리니
이 경우에는 사용하지 않고 해보자 자세한 이유는 아래서 마저 설명하겠다.
그리고 1은 무엇을 곱해도 그 결과가 곱한 수가 되는 항등원 이기 때문에
( 항등원은 특정 연산에 대해
어떤 수가 항등원과 특정 연산을 했을때 결과가 어떤 수가 그대로 나오는 것으로,
곱하기의 경우 1과 곱할 경우 원 값이 그대로 나오는 경우를 생각해 보면 된다. )
1은 앞으로 제외하고 약수의 곱을 나타내겠다.
또한, 약수의 종류는 2가 같은 값이니 1번, 약수의 곱으로 표현할때는 4안에는 2가 2개 있으니 2번 곱해준 것을
볼 수 있다.
한 수의 약수를 보았으니
이번에는 두 수의 약수를 비교하는 것을 보자.
우리는 약수를 공약수, 최대공약수까지 가져갈 것이기 때문이다.
8과 12를 비교해보자.
8을 약수의 곱으로 표현하면
8 = 2 * 2 * 2
12를 약수의 곱으로 표현하면
12 = 2 * 2 * 3
으로 표현할 수 있다.
이때, 약수는 보다시피 우리가 4를 사용하지않고, 2를 2번씩 사용하고 있다.
이유는 만약 12의 약수 중 6을 사용할 경우 공통의 약수를 볼때 2가 2개 있어야하는데
6에 들어가서 볼 수 없는 경우 사용하지 않을 수 있기 때문이다.
이렇듯 하나를 놓치면 정확한 최대공약수를 구할 수 없다.
그리고 어떤 기준으로 이렇게 2와 3을 구분했느냐 한다면
이렇게 표현한 약수들은 1과 자기 자신외에는 나누어 떨어지지 않는 숫자들로 나타낸다.
음. 그렇구나 하는 분도 계실거고
어? 1과 자기 자신외에는 나누어 떨어지지 않는 수?
하시는 분도 있을거다.
실제로 그랬다.
무튼, 이러한 숫자들을 우리는 따로 부르고있다.
바로 소수이다.
약수의 곱으로 특정수를 표현할때는 소수로 구성되어있는 것이 가장 좋다. ( 이유는 방금 위에서 언급됐다. )
그리고 그렇기 때문에 지금의 4, 8, 12는 약수의 곱으로 나타낼때 자기 자신이 표현되지 않았다.
7, 29 이런 소수들은 1 * 7, 1 * 29 등으로 자기자신외에는 나타낼 수 없기때문에 당연히 사용된다.
그래서
8 = 2 * 2 * 2
12 = 2 * 2 * 3
이렇게 표현했음을 알아두자.
그렇다면, 우리는 정확한 공통의 약수를 알 수 있다.
2, 2가 공통의 약수이고
2 * 2가 공통의 약수의 곱이고
전체 공통의 약수의 곱이기때문에 이는, 최대공약수가 될 것이다.
예시를 많이 보는 것이 이해에 제일 좋다고 생각하기때문에
한가지 예시를 더 같이 공부해보자.
이번에는 반대로 약수를 통해 숫자를 만들어보자.
이번에는 2 * 3 * 5 가 공통의 약수인 수를 만들것이고
( 2 * 3 * 5 ) * 3
( 2 * 3 * 5 ) * 7
로 공통의 약수가 아닌 숫자가 3과 7인 수를 보자
90 과 210이 될 것이고, 이 둘의 최대공약수는 30이 될 것이다.
이 수를 가지고 또 요리조리 해보면 반대로 나오는 것도 볼 수 있을 것이다.
지면이 아니라 포스팅으로 자유롭게 여러 방법으로 구하는 법을 보여드리지 못하는 것을 양해해달라.
학교에서 배운 방법을 써보아도 된다. 나누기를 써도 되고
이처럼 두 수를 비교할때는 최대공약수 * 자신만의 수로 두 숫자가 구성됨을 알 수 있다.
다음 최소공배수를 보자.
뜻부터 살펴보자, 최소는 가장 작은 것이고
공배수는 공통의 배수이다.
배수는 특정 수에 어떤 수를 곱했을때 나오는 값이다.
( 모두 여기서는 자연수를 사용한다. 2에 1.5를 곱하면 3이 된다고 해서 3은 2의 배수라고 표현하지 않는다.
또한, 음수도 일반적으로 사용하지 않는다. 2에 -2를 곱해서 -4가 된다고 해서 -4를 2의 배수라고 표현하진 않는다. )
( 특정 상황에서는 0을 자연수로 보는 경우는 있지만, 일반적이지 않기때문에 제외한다. )
2의 배수는 우리가 구구단에서 보았던, 2 4 6 8 10 12 14 16 ... 이런 수들이다.
배수를 알았으니 공배수를 알아보자.
( 앞으로도 많이 적겠고, 수업때도 자주 하는 말이지만
뭐든지 하나씩 하나씩 하다보면 보다 쉽게 해결된다.
나무를 보지말고 숲을 보라고들 말하지만, 나무를 봐야 숲을 알 수 있다. )
공배수는 공통의 배수이다.
2와 3을 보자.
2의 배수는
2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24 ...
3의 배수는
3, 6, 9, 12, 15, 18, 21, 24...
이다. 공통의 배수들이 보이는가?
6, 12, 18, 24..
이렇게 될 것이다.
이러한 것들이 공배수가 될 것이다.
그리고 하나 더 보이는가?
저건 6의 배수다.
그리고 6은 우리가 제일 먼저 보았던 공배수중에 제일 작은 숫자, 최소인 공배수
최소공배수다.
안신기할 수 있겠지만, 공통의 배수가 최소공배수의 배수라는 점은
공배수의 원리 그 자체이다.
공배수의 원리를 보기위해 좀 더 복잡한 수를 보자.
12와 18의 공배수를 알아보자.
우선 두 수를 약수의 곱으로 표현해보자.
우리는 이 것을 위해 위에서 약수를 사실 배워왔다.
12 = 2 * 2 * 3
18 = 2 * 3 * 3
이 될 것이다.
최대공약수는 어떻게 되었는가.
( 2 * 3 ) 이 될 것이고 각자, 2와 3을 곱해 12, 18의 값을 갖게 되어있다.
공배수는 둘의 배수중 같은 배수들의 묶음이고,
그 말은 공배수는 두 수로 나누어 떨어지는 숫자이고,
그 말은 공배수는 이 두수가 모두 약수인 숫자들이다.
즉, ( 2 * 3 ) * 2 도 약수로 갖고있고
( 2 * 3 ) * 3 도 약수로 갖고있다는 것이다.
모두 약수는 곱으로 값을 만들기때문에
( 2 * 3 ) * 2 * 3 이 약수가 되면
( 2 * 3 ) * 2
( 2 * 3 ) * 3 모두로 나누어 떨어지게 될 것이다.
결국은 공배수는
( 2 * 3 ) * 2 * 3 * n이 될것이고, n이 1인 경우가 가장 작은 수일 것이다.
즉, ( 2 * 3 ) * 2 * 3 이 최소공배수가 된다.
이걸 일반화 시킨다면
( 최대공약수 ) * 각자가 가진 약수 를 하면 최소공배수가 되는 것이다.
12, 18의 예시를 한번 더 보고
다음의 예시로 같이 한번 더 해보자.
21과 36의 약수를 각각 표현해보면
21 = 3 * 7
36 = 2 * 2 * 3 * 3
이고, ( 숫자는 일반적으로 작은수부터 기재하는 것이 활용하기 편하다. 곱하기이기 때문에 순서는 값과 무관하다. )
공통의 약수는 3이 될 것이고,
3 * ( 3 * 7 ) * ( 2 * 2 * 3 ) 이 최소공배수가 될 것이다.
3 * 21 * 12 이고
756이 될 것이다.
해당 문제는 이러한
분수의 덧셈, 기약분수를 알면 풀수 있고
이는 분수의 덧셈을 위한 분수의 성질, 기약분수를 만드는 방법을 알아야하는 것이고
이는 공배수와 공약수의 성질을 이용하면 풀 수 있는 문제다.
무엇이든 단계적으로 하나하나 바라볼 수 있어야 하고,
내가 가진 것, 해야하는 것을 바라볼 때 해결이 좀 더 쉬워질 수 있다.
수업 중 말씀드린 흐름을 잡는 것에대한 조언으로 마무리하겠다.
이는 스스로 문제에대한 고민 후에 너무 길을 못 잡겠다 싶을때 참고하시기 바라고
다른 누군가의 고민이였으므로 본인의 고민에는 해당하지 않을 수 있다.
실제로 이 문제를 가져온 2분은 서로 고민하시는 부분이 달랐다.
잘 해결한 부분도 달랐다.
1) 공통의 분모를 만들어야 덧셈을 할 수 있다. 공통의 분모를 어떻게 만들어줄 것인지 생각해보자.
2) 사실 사람은 알게모르게 섬세하게 생각을 거치지 않고 연산을 하는 과정이 있다. 이 부분을 컴퓨터가
어떻게 수행하게 할 것인지 고민해보자.
3) 어떤 값으로 나누어떨어지는 지 사람은 작은 수의 경우 쉽게 알 수 있지만, 컴퓨터는 그걸 바로 생각해내지 못한다.
또한, 사람도 값이 커지면 모른다.이 경우 어떻게 컴퓨터가 찾아내게 할 것인지 고민해보자.
4) 어떤 값들을 어떻게 찾으라고 미리 정해줄 수 있는 경우도 있지만, 사실 알 수 없는 경우가 있다.
이러한 경우 어떻게 컴퓨터는 해결하게 할 것인지 고민해보자.
5) 사람이 29라는 낯선 숫자를 보았을때 어떻게 약수를 찾아가는지 생각해보자.
이것도 사실 자주 언급할 부분이다. 어느 포스팅에 어느부분이 먼저, 혹은 일부만 접할지 모르기 때문이다.
코딩을 할때는
내가 무엇을 할 수 있는지, 무엇을 갖고있는지
내가 무엇을 해야하는지
그 무엇은 어떻게 접근해야하고 그것의 단계가 어떻게 되는지
하나하나 단계적으로 보시기 바라고,
하나하나 출력을 찍어보면서 경과가 어떻고 무엇이 내 생각과 어떻게 다른지
생각난 방법이 있으면 우선 한번씩 도전해보는 것이
실제적으로 결과가 가장 빠르고 좋다.
'알고리즘' 카테고리의 다른 글
퀵정렬 설명과 함께 작성한 코드 (1) | 2023.06.06 |
---|---|
페이징에 대한 이해 (0) | 2023.04.24 |
BOJ3052 - 서로 다른 나머지의 개수 (0) | 2022.01.13 |
StringBuilder, StringBuffer (0) | 2022.01.11 |
StringTokenizer (0) | 2022.01.11 |