오늘은 재미삼아 생활 속의 수학이야기를 해보려고 한다. 재미있을지는 잘 모르겠으나 어쩄든..
우리가 사는 일상생활속에는 수학과 관련된 것 들이 아주 많이 존재 한다. 그 중에서 숫자와 관련된 이야기를 해보려고 한다. 주민등록번호, 군번, 휴대폰번호, 신용카드번호 등 모두 다양한 숫자로 이루워져 있다. 그냥 보기에는 아무 번호나 막 갖다 붙인 듯(?) 보이지만 실제로는 규칙이 정해져 있다. 주민번호는 뭐 다들 아시다시피 성별, 행정구역 (뒷자리)등으로 숫자가 부여받게 되는 것은 누구나 잘 아는 규칙일 듯 싶다. 그 중에서 오늘 살펴볼 숫자는 신용(체크) 카드 번호의 비밀을 알아보고자 한다.

카드 앞쪽에는 16개의 숫자로 이루워져 있다. 딱 보기에는 별 의미 없어 보일 수도 있지만 여기에도 규칙이 숨어있다.
한번 알아보자.

카드의 맨앞자리 숫자는 카드 종류의 따라 결정 된다. 예를 들어 맨 앞자리 숫자가 4인 경우는 비자카드, 5인 경우는 마스터 카드, 9인 경우는 국내용 카드, 35이면 JBC 카드 기타 등등으로 종류가 나누어 진다.
그리고 맨 앞자리부터 여섯 번째 짜리까지는 BIN(Bank Identifier Number)로 카드의 발급 기간 식별이 가능하다. 여기까지는 카드 종류와 발급에 따라 숫자가 부여 된다.
그렇다면 만약 맨 앞 숫자가 9인 경우는 해외에서는 사용하지 못하는 걸까? 흠..

다음으로 나오는 7번째 부터 15번째 까지의(마지막 숫자만 제외) 숫자는 카드사가 임의의 규칙에 따라서 부여가 된다. 이건 카드사 마음대로 할 수 있는 부분인 듯하다. 카드사 마다 다르겠지만 어떤 특정한 알고리즘을 사용할 수 도 있고 아니면 그냥 임의의 숫자를 랜덤으로 돌릴 수도 있을 듯하다. 이건 카드사의 개발자나 관리자들만 알겠지..

그럼 마지막 숫자는 무엇일까? 눈치 빠른 사람은 벌써 눈치 챘겠지만 주민등록번호에도 존재하는 숫자이다. 바로 체크 숫자라고 불리는데 이 숫자는 복잡한(?) 수학 공식에 따라 결정이 된다.

이 마지막 체크 숫자는 어떠한 공식에 의해 부여가 되는데 그 공식이 룬 공식(LUHN Formula) 이라고 한다.
이 공식만 알면 우리는 마지막 숫자를 알 수 있게 된다. 그럼 룬 공식이 뭔가? 룬 공식의 규칙을 알아보자.

  1. 카드 번호의 매 홀 수 자리의 숫자마다 2를 곱해서 더한다. 이 때, 나온 숫자가 두 자리 수이면 각자리의 숫자를 더한다.
  2. 앞에서 연산하지 않은 매 짝수 자리는 각 숫자를 더한다.
  3. 1에서 나온 숫자와 2에서 나온 숫자를 더한다.
  4. 마지막으로 나온 값이 10으로 나누어 떨어지도록 체크 숫자를 정하면 된다.

말로는 이해가 안될 수도 있으니 한번 예제를 들어보자. 만약 아래와 같은 번호가 있다고 하자.

4, 7, 1, 6, 1, 0, 8, 9, 5, 6, 3, 5, 4, 5, 9, 9

위의 카드 번호는 테스트 할 수 있는 유효한 카드 번호이다. 근데 실제로 있는건 아니겠지?..
1번을 보면 매 홀 수자리 마다 2를 곱해서 더한다고 했으니 다음과 같다.

(4 × 2) + (1 × 2) + (1 × 2) + (8 × 2) + (5 × 2) + (3 × 2) + (4 × 2) + (9 × 2)

그리고 나서 곱한 수가 두자리 라면 각 자리 수를 더한다.

8 + 2 + 2 + (1 + 6) + (1 + 0) + 6 + 8 + (1 + 8) = 43

위의 소괄호는 알아보기 쉽게 두자리가 나온 숫자들이다. 다 더하면 43이 나온다.
그 다음 마지막을 제외 하고 매 짝수자리를 다 더한다.

7 + 6 + 0 + 9 + 6 + 5 + 5 = 38

위의 두개의 숫자를 더하면 81이 나온다. 그럼 어떤 숫자가 와야지 10으로 딱 떨어지게 되나? 뭐 안봐도 뻔하지만 마지막숫자는 9가 되어야만 10 으로 떨어지게 된다. 한 번 자신의 카드를 꺼내서 확인 해보도록 하자.

여기서 끝내면 조금 아쉽다. 우리는 개발자다. 한번 위의 공식을 코드로 나타내 보자. 뭐 알고리즘이라고 할 것도 없이 너무 간단해서 쉽게 풀 수 있을 것이다.

아래는 필자가 대충 짠 코드가 있긴한데 한번 자신이 짜보도록 하자.

@Test
public void creditCardNumberTest() {
  final int[] list = {4, 7, 1, 6, 1, 0, 8, 9, 5, 6, 3, 5, 4, 5, 9, 9};
  System.out.println(creditCardNumber(list));
}

private boolean isCreditCardNumber(int[] array) {
  int sum = 0;
  for (int i = 0; i < array.length - 1; i++) {
    if ((i - 1) % 2 == 0) {
      sum += array[i];
    } else {
      final int two = array[i] * 2;
      sum += (two / 10 + two % 10);
    }
  }
  sum += array[array.length - 1];
  return sum % 10 == 0;
}

에러 처리나 카드 번호가 꼭 16개인지는 체크 하지 않았다. 그냥 알고리즘만 보면 되어 대충 해놨으니 그냥 참고만 하도록하고 직접 해보자!

또 한 15개의 카드 번호만 입력후에 어떤 값이 체크숫자인지도 출력하는 코드도 함께 작성해보자!. 뭐 이건 위의 코드를 아주 살짝만 건드면 되니.. 대충 이런코드가 되지 않나 싶다.

private int creditCardNumber1(int[] array) {
  int sum = 0;
  for (int i = 0; i < array.length; i++) {
    if ((i - 1) % 2 == 0) {
      sum += array[i];
    } else {
      final int two = array[i] * 2;
      sum += (two / 10 + two % 10);
    }
  }
  return 10 - (sum % 10);
}

아주 간단하게 풀어봤다. 수학카테고리도 종종 이용해야 겠군..
오늘은 이상이다!