나눗셈과 모듈로 연산의 고찰 - C, C++, Python, Java

시스템 프로그래밍 수업을 듣다 보니, 비트와 관련한 연산 주제들을 많이 다루고 있다. 그런데 수업 중에 유독 이해가 안가는 부분이 있었는데, 나눗셈과 관련된 부분이었다.

C언어에서는 정수 나눗셈을 하면 그 값을 Ceil 시킨다는 것이었다.

이 부분에서 수학적으로 나머지가 항상 0보다 크거나 같다는 생각을 가지고 있었고, 정수 나눗셈이 몫을 구하는 연산이라고 생각하고 있어서 이상하다고 생각했다.

그러나 자세히 알아보니 수학적으로 나머지가 항상 0일 필요는 없다. 더욱이 각 언어마다 나머지를 어떻게 정의하느냐에 따라서 몫과 그 나머지 계산이 다 달라지게 된다.


일단, C언어에서 정수 나눗셈의 나머지는 피제수와 같은 부호를 가지게 된다.(C99 전에는 어느 것을 선택해도 가능했다.)

그리고 나눗셈의 결과는 몫을 나타내게 된다.

예를 들면 아래와 같은 코드는 그 아래와 같은 결과를 나타낸다.
#include <stdio.h>

int main(void)
{
    printf("7 / 3     = %d\n", 7 / 3); 
    printf("7 %% 3     = %d\n", 7 % 3); 
    printf("7 / -3    = %d\n", 7 / -3);
    printf("7 %% -3    = %d\n", 7 % -3);
    printf("-7 / 3    = %d\n", -7 / 3); 
    printf("-7 %% 3    = %d\n", -7 % 3); 
    printf("-7 / -3   = %d\n", -7 / -3);
    printf("-7 %% -3   = %d\n", -7 % -3);
    
    return 0;
}
7 / 3     = 2
7 % 3     = 1
7 / -3    = -2
7 % -3    = 1
-7 / 3    = -2
-7 % 3    = -1
-7 / -3   = 2
-7 % -3   = -1
피제수가 양수일 때 7 / 3 또는 7 / -3은 나머지가 1이 된다. 그러나 -7 / 3 또는 -7 / -3의 나머지는 -1이 된다. 그리고 나눗셈의 결과는 몫을 나타내게 된다.

따라서 나눗셈을 하게 되면 소수의 정수부를 얻는 것과 같은 결과를 얻게 된다.


그렇다면 C++에서는 어떻게 되는지 살펴보자. 코드부터 살펴보면 아래와 같다.
#include <iostream>

using namespace std;

int main(void)
{
    cout<<"7 / 3   = "<<7 / 3<<endl
        <<"7 % 3   = "<<7 % 3<<endl
        <<"7 / -3  = "<<7 / -3<<endl
        <<"7 % -3  = "<<7 % -3<<endl
        <<"-7 / 3  = "<<-7 / 3<<endl
        <<"-7 % 3  = "<<-7 % 3<<endl
        <<"-7 / -3 = "<<-7 / -3<<endl
        <<"-7 % -3 = "<<-7 % -3<<endl;

    return 0;
}
7 / 3   = 2
7 % 3   = 1
7 / -3  = -2
7 % -3  = 1
-7 / 3  = -2
-7 % 3  = -1
-7 / -3 = 2
-7 % -3 = -1
즉, C++ 역시 C언어와 같다는 것을 알 수 있다.


그럼 이번에는 파이썬을 살펴보자.

파이썬의 경우에는 나머지의 부호는 제수의 부호와 같게 된다. 또한, 나눗셈의 결과는 몫을 나타낸다.(파이썬 2의 경우에는 나눗셈만 해도 그 결과는 몫이고, 3의 경우에는 몫 연산자를 사용할 경우 몫이 나온다.)
print('7 // 3     = ', 7 // 3)
print('7 % 3      = ', 7 % 3)
print('7 // -3    = ', 7 // -3) 
print('7 % -3     = ', 7 % -3) 
print('-7 // 3    = ', -7 // 3)
print('-7 % 3     = ', -7 % 3)
print('-7 // -3   = ', -7 // -3) 
print('-7 % -3    = ', -7 % -3) 

print('7.2 // 3   = ', 7.2 // 3)
print('7.2 % 3    = ', 7.2 % 3)
print('7.2 // -3  = ', 7.2 // -3) 
print('7.2 % -3   = ', 7.2 % -3) 
print('-7.2 // 3  = ', -7.2 // 3)
print('-7.2 % 3   = ', -7.2 % 3)
print('-7.2 // -3 = ', -7.2 // -3) 
print('-7.2 % -3  = ', -7.2 % -3)
7 // 3     =  2
7 % 3      =  1
7 // -3    =  -3
7 % -3     =  -2
-7 // 3    =  -3
-7 % 3     =  2
-7 // -3   =  2
-7 % -3    =  -1

7.2 // 3   =  2.0
7.2 % 3    =  1.2
7.2 // -3  =  -3.0
7.2 % -3   =  -1.8
-7.2 // 3  =  -3.0
-7.2 % 3   =  1.8
-7.2 // -3 =  2.0
-7.2 % -3  =  -1.2
이번에는 제수가 양수일 때 나머지의 부호가 양수가 되고, 음수일 때는 부호가 음수가 된다.

따라서 C언어와 비교했을 때 몫이 다르게 나옴을 알 수 있다. 즉, C언어와는 달리 소수의 정수부를 얻지 못한다. 이럴 경우에는 int 함수를 통해서 정수부를 구할 수 있다.

그런데, 파이썬에서는 C나 C++과 달리 소수에 대해서도 몫 연산과 나머지 연산이 가능하다. 자바에서도 마찬가지로 가능한데, 소수이더라도 정수와 같은 규칙이 적용되어 몫과 나머지가 구해진 것을 알 수 있다.


마지막으로 자바를 보자.
public class Divide
{
    public static void main(String[] args)
    {   
        System.out.println("7 / 3     = " + 7 / 3); 
        System.out.println("7 % 3     = " + 7 % 3); 
        System.out.println("7 / -3    = " + 7 / -3);
        System.out.println("7 % -3    = " + 7 % -3);
        System.out.println("-7 / 3    = " + -7 / 3); 
        System.out.println("-7 % 3    = " + -7 % 3); 
        System.out.println("-7 / -3   = " + -7 / -3);
        System.out.println("-7 % -3   = " + -7 % -3);

        System.out.println("7.2 / 3   = " + (int)(7.2 / 3));
        System.out.println("7.2 % 3   = " + 7.2 % 3); 
        System.out.println("7.2 / -3  = " + (int)(7.2 / -3));
        System.out.println("7.2 % -3  = " + 7.2 % -3);
        System.out.println("-7.2 / 3  = " + (int)(-7.2 / 3));
        System.out.println("-7.2 % 3  = " + -7.2 % 3); 
        System.out.println("-7.2 / -3 = " + (int)(-7.2 / -3));
        System.out.println("-7.2 % -3 = " + -7.2 % -3);
    }   
}
7 / 3     = 2
7 % 3     = 1
7 / -3    = -2
7 % -3    = 1
-7 / 3    = -2
-7 % 3    = -1
-7 / -3   = 2
-7 % -3   = -1

7.2 / 3   = 2
7.2 % 3   = 1.2000000000000002
7.2 / -3  = -2
7.2 % -3  = 1.2000000000000002
-7.2 / 3  = -2
-7.2 % 3  = -1.2000000000000002
-7.2 / -3 = 2
-7.2 % -3 = -1.2000000000000002
자바의 경우에는 C나 C++과 같은 결과를 보여준다는 것을 알 수 있다. 즉, 나머지의 부호는 피제수의 부호와 같다. 그리고 나눗셈의 경우 당연히 몫을 나타내고 있다.

그리고 파이썬과 마찬가지로 소수에 대한 나머지 계산이 가능한데, 이 경우에도 위와 같은 규칙으로 나머지가 구해지고 int로 캐스팅 했을 때 위와 같은 몫이 나온다는 것을 알 수 있다.


이런 점에서 나눗셈을 통해서 몫이나 나머지를 구하거나 연산할 때 주의해야 할 필요가 있다


참고 문헌:
http://en.wikipedia.org/wiki/Remainder

댓글 1개:

  1. Why Are Casino Slots RTP So Good? - TrickToAction
    If 꽁머니 토토 you're looking to play blackjack, then you need to know that the majority of slots in 메이저사이트 넷마블 the casino have 검증 놀이터 lower 먹튀사이트 payouts than 토토 사이트 도메인 in

    답글삭제

크리에이티브 커먼즈 라이선스