U E D R , A S I H C RSS

Primary Arithmetic/sun

풀이 방향

단순히 사람이 덧셈을 하는 식으로 풀었다. 끝자리 부터 하나씩 더해가며, 올림수가 발생했을 경우 같이 더하는 방식을 이용했다.

~cpp 
    1234
   + 567
   ----
    1081

위에서처럼, 그동안 더 큰수를 위에 놓고 더하는데에 익숙해져 있기에 같은 방식을 따랐다. (경험상, 어떤 특별한 알고리즘을 따르는게 아니라면, 현실 세계를 모델링하는게 편한것 같다.)

숫자 생성기

풀이 방향을 정하고 보니, 숫자를 하나씩 끝에서부터 떼어올 필요가 생겼다.

테스트 작성 (NumberGeneratorTest.java)

~cpp 
package primaryarithmetic;

import junit.framework.TestCase;

public class NumberGeneratorTest extends TestCase {

	public void testNoNumber() {
		NumberGenerator ng = new NumberGenerator();
		assertFalse( ng.hasNext() );
	}
	
	public void test123() {
		NumberGenerator ng = new NumberGenerator(123);
		assertEquals( 3, ng.next() );
		assertEquals( 2, ng.next() );
		assertTrue( ng.hasNext() );
		assertEquals( 1, ng.next() );
		assertFalse( ng.hasNext() );
	}
}

지금 생각해보면 ~cpp testNoNumber는 필요없는것 같다. 나중에 글을 쓰다보니, 같이 쓰게 됬는데 원래는 위의 테스트를 먼저 작성하고 테스트 통과후 아래쪽 테스트를 추가했다. 이번 작업과 별도로 코딩후에 뭔가하자는 결국 놓치는게 많다는걸 다시한번 증명하게 된다. :) see NowOrNever

위 테스트를 만족하는 코드 작성 (NumberGenerator.java)

~cpp 
package primaryarithmetic;

public class NumberGenerator {

	private int number;
	private byte[] numbers;
	private int numPointer;

	public NumberGenerator() {
		number = -1;
	}

	public NumberGenerator( int number ) {
		if( number < 0 ) throw new ArithmeticException( "0 또는 그 이상의 정수만 가능합니다: " + number );
		this.number = number;
		init();
	}

	private void init() {
		numbers = String.valueOf(number).getBytes();
		numPointer = numbers.length - 1;
	}

	public boolean hasNext() {
		if( number == -1 ) return false;
		return numPointer >= 0;
	}

	public int next() {
		return numbers[numPointer--] - '0';
	}
}

PrimaryArithmetic

여기서도 마찬가지로 테스트를 작성하게 됬는데, 코드를 추가하다보니 비슷한 패턴으로 테스트를 하게 되서, 테스트 셋 추가로 이뤄지도록 테스트를 구성

테스트 작성 (PrimaryArithmeticTest.java)

~cpp 
package primaryarithmetic;

import junit.framework.TestCase;

public class PrimaryArithmeticTest extends TestCase {

	public void testCases() {
		int [][] sets = {
				{ 0, 1, 1 },
				{ 1, 5, 5 },
				{ 3, 555, 555 },
				{ 0, 123, 456 },
				{ 1, 123, 594 }
		};
		
		for( int i=0; i<sets.length; i++ ) {
			int expected = sets[i][0];
			int num1 = sets[i][1];
			int num2 = sets[i][2];
			
			verify( expected, num1, num2 );
		}
	}

	private void verify(int expected, int num1, int num2) {
		int result = PrimaryArithmetic.add(num1, num2);
		try {
			assertEquals( expected, result );
		}
		catch( Throwable e ) {
			throw new ArithmeticException( "We expected " + expected + ", but was " + result + " (num1=" + num1 + ", num2=" + num2 + ")" );
		}
	}
}

(역시나, 하는 중간에 문서를 작성하지 않으니 커다란 동기가 없는한 자세히 쓰지 않게 된다. 흑흑)

테스트를 만족하는 코드 작성 (PrimaryArithmetic.java)

~cpp 
package primaryarithmetic;

public class PrimaryArithmetic {

	public static int add( int num1, int num2 ) {
		NumberGenerator ng1 = new NumberGenerator( Math.max(num1, num2) );
		NumberGenerator ng2 = new NumberGenerator( Math.min(num1, num2) );
		
		int counts = 0;
		int sumUp = 0;
		
		while( ng1.hasNext() && ng2.hasNext() ) {
			int n1 = ng1.next();
			int n2 = ng2.next();
			int sum = n1 + n2 + sumUp;
			
			if( sum >= 10 ) {
				sumUp = 1;
				counts ++;
			}
			else sumUp = 0;
		}
		
		while( sumUp == 1 && ng1.hasNext() ) {
			int sum = ng1.next() + sumUp;
			if( sum >= 10 ) counts ++;
			else break;
		}
		
		return counts;
	}
}

응용프로그램으로

언어 특성상 라인수가 길어지는걸 느끼며 (PrimaryArithmeticApp.java)

~cpp 
package primaryarithmetic;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class PrimaryArithmeticApp {
	
	public static void main( String [] args ) throws IOException {
		BufferedReader in = new BufferedReader( new InputStreamReader( System.in ));
		String line;
		
		while( (line=in.readLine()) != null ) {
			String [] numbers = line.split( " " );
			int num1 = Integer.parseInt( numbers[0] );
			int num2 = Integer.parseInt( numbers[1] );
			if( num1 == 0 && num2 == 0 ) break;
			
			int counts = PrimaryArithmetic.add( num1, num2 );
			print( counts );
		}
	}

	private static void print( int counts ) {
		String occurs = (counts == 0) ? "No" : String.valueOf(counts);
		String postfix = (counts > 1) ? "s" : "";
		System.out.println( occurs + " carry operation" + postfix + "." );
	}
}

부록 (써프라이즈 버전)

문제 풀이를 위해서 별다른 알고리즘이 아닌 현실에서의 덧셈 방법을 사용했고, 코드량이 별로 되지 않음에도 1시간이 걸린것은 도중에 msn으로 친구과 채팅을 하며 했기 때문이다. 본인이 느끼기에는 msn을 얼마 하지 않았던것 같은데 실제로는 시간이 꽤 지나있는걸 보면 아인슈타인의 상대성원리에 따라 시간이 흐름을 알 수 있다. 직장인의 경우 이것을 좀 더 일반화 해보면, '왠지 오늘 하루 일하기 싫다'라고 느껴지고, 휴가를 쓸 수 없을땐 근무중에 메신저를 하면 시간이 금방 감을 알 수 있겠다.

단, 기술에는 언제나 어두운 면이 있듯이, 시간을 엄청나게 빨리 보내는 도중 상사와의 원치않는 메시징은 반대의 효과를 나타낼수도 있다. (즉, 이럴땐 '오프라인으로 보임'을 이용하도록 하자)

Valid XHTML 1.0! Valid CSS! powered by MoniWiki
last modified 2021-02-07 05:24:02
Processing time 0.0208 sec