2021년 4월 11일 일요일

나머지 연산 % (modulo) 특징

SW작업시 간혹 나머지 (C언어 %) 연산을 사용하는 경우가 있습니다.

대표적으로 연산결과가 특정값을 넘어가지 않게 하기 위함이죠. 주어진 배열을 넘어가지 않도록 하기 위함인데, 그것 외에도 연산을 여러번 하면서 특정값을 유지하고 싶은때가 있습니다.

예를 들어보자면 계산 결과가 굉장히 큰 연산이 있습니다. 중간에 overflow되기도 하고요. 그렇다면 최종 결과에 % 연산과 중간 중간에 %연산을 한 경우 결과가 어떻게 될까요?

https://opentutorials.org/module/1544/9532

위 링크 아래 내용 참고하면 + , * 연산에 대해서 항상 참이 됩니다.

나머지의 법칙

 나머지 연산은 기본적으로 결합, 분배, 교환법칙이 모두 성립하지 않습니다. 그래서 사용할때에 항상 계산순서와 위치에 주의를 해야합니다. 단 나머지 연산에서 성립하는 독특한 성질들도 있습니다. 

 a를 b로 나눈 나머지를 a mod b = a % b라고 표현하기로 합시다. 이 때 나머지는 다음과 같은 식들이 항상 성립합니다. 

 ( a + m ) % m = a % m

 ( (a % m) + ( b % m) ) % m = ( a + b ) % m 

 ( ( a % m) * ( b % m) ) % m = ( a * b) % m 


막상 해보면 맞는것 같지만, programming 할때 주의해야할 점이 있습니다.


단순 계산에서는 문제가 없습니다. C언어로 구현한 SW를 살펴보도록 하겠습니다.

// mod
#include <stdio.h>

#define MOD 34502
void test1()
{
	int i,a,b;
	for(i=0;i<0x7ffffff0;i++){
		a = (i*34500)%MOD;
		b = ((i%MOD)*34500)%MOD;
		if (a!=b) {
			printf("t1 i=%d, %d %d\n",i,a,b);
			printf("error\n");
			break;
		}
	}
}
void test2()
{
	unsigned int i,a,b;
	for(i=0;i<0x7ffffff0;i++){
		a = (i*34500)%MOD;
		b = ((i%MOD)*34500)%MOD;
		if (a!=b) {
			printf("t2 i=%d, %d %d\n",i,a,b);
			printf("error\n");
			break;
		}
	}
}
int main()
{
	printf("%d\n",sizeof(int));
	test1();
	test2();
	return 0;
}

테스트하면 아래와 같습니다.

4
t1 i=62246, -6812 13516
error
t2 i=124492, 6704 27032
error

이렇게 되는 사유는 중간에 overflow가 일어나기 때문입니다. 

결론은 중간식이 overflow가 되지 않도록 관리가 필요하고 + 연산에 대해서만 동작합니다. overflow가 되어서 - 연산이 이루어지지 않도록 해야 합니다.



댓글 없음:

댓글 쓰기