과학

자바로 프로그래밍에 입문할래요: 1.5. 입출력 (2)

그림과 소리를 다루는 것을 마지막으로, 드디어 1장을 끝낼 수 있겠네.

프로그래밍 요소의 기본적인 것들은 전부 다뤘다고 생각하면 돼.

이 개념들만으로도 간단한 프로그램들은 어떤 프로그래밍 언어로든 충분히 만들 수 있어.

 

1.5. 입출력 (1)

1.4. 배열 (3)

1.4. 배열 (2)

1.4 배열 (1)

1.3. 조건문과 반복문 (2)

1.3. 조건문과 반복문 (1)

1.2. 내장 자료형 (2)

1.2. 내장 자료형 (1)

0.0. 여는 글, 1.1. 첫 프로그램 만들기

 

=============================

 

표준 그림(Standard drawing)

  이 시점까지 우리의 입출력 추상화는 오로지 문자열에만 국한되어 있었습니다. 이제 그림을 출력으로 생성할 수 있는 추상화를 소개해볼까 합니다. 이 라이브러리는 우리에게끔 단순 문자열보다 더 많은 정보를 전달할 수 있는 시각적 매체를 사용할 수 있게 만들어줍니다.

 

  이 라이브러리는 강의 사이트에서 다운받을 수 있으며, 앞서 표준 입력 라이브러리를 사용해왔다면 이미 다운로드 받아져 있을 것입니다. 표준 그림은 굉장히 단순합니다: 2차원의 선과 점을 그릴 수 있는 추상화된 그리기 도구를 상상하면 됩니다. 이 기기는 우리의 프로그램이 호출하는 StdDraw 클래스의 메소드를 통해, 명령에 응답할 수 있습니다.

 

 

  표준 입출력 메소드들처럼, 이 메소드들은 직관적입니다. StdDraw.line()은 말그대로 두 점을 잇는 선분을 긋습니다. StdDraw.point() 메소드는 해당 좌표에 점을 찍습니다. 

 

 

 

첫 그림(your first drawing)

  그래픽 프로그래밍의 <HelloWorld>는 삼각형을 그리고 중앙에 점을 찍는 것입니다. 삼각형을 그리기 위해서 우리는 세 선을 그어야합니다. (0,0), (1,0), (1/2, √3/2)를 각각 잇는 세 선분이죠. 마지막으로 중앙에 점을 하나 찍어내면 됩니다.

 

 
public class Triangle
{
	public static void main(String[] args)
	{
		double t = Math.sqrt(3.0)/2.0;
		StdDraw.line(0.0, 0.0, 1.0, 0.0);
		StdDraw.line(1.0, 0.0, 0.5,   t);
		StdDraw.line(0.5,   t, 0.0, 0.0);
		StdDraw.point(0.5, t/3.0);
	}
}

 

 

 

 

제어 명령(Control commands)

 

  가끔은 좌표계의 기준들을 좀 바꾸고 싶을 때도 있습니다. 이럴 때 다음 메소드를 활용할 수 있습니다.

 


  예를 들어, StdDraw.setXscale(0, N) 을 활용하면, 그림 도구에게 x좌표는 0부터 N까지만 사용하라고 말할 수 있습니다. 예를 들어 다음 그림은 X좌표와 Y좌표의 최소, 최대값을 0과 50으로 설정한 뒤 선을 긋는 모습입니다.

 

 

 

프로그램 1.5.5: Input-to-drawing filter

 
public class PlotFilter
{
	public static void main(String[] args)
	{	// Plot points in standard input.
		// Scale as per first four values.
		double xO = StdIn.readDouble();
		double yO = StdIn.readDouble();
		double xl = StdIn.readDouble();
		double yl = StdIn.readDouble();
		StdDraw.setXscale(xO, xl);
		StdDraw.setYscale(yO, yl);
		// Read and plot the rest of the points,
		while (!StdIn.isEmpty())
		{ // Read and plot a point.
			double x = StdIn.readDouble();
			double y = StdIn.readDouble();
			StdDraw.point(x, y);
		}
	}

}
% java PlotFilter < USA.txt

 


<프로그램 1.5.5>는 데이터를 그림으로 나타내는 일종의 필터입니다.

 

 

함수 그래프 그리기

  StdDraw 사용의 중요성은 실험 데이터나 수학적 함수를 그려낼 수 있다는 것입니다. 예를 들어, 함수 y = sin(4x) + sin(20x) 를 [0,π] 범위로 그려본다고 생각해보세요. 직선들로 어떻게 곡선을 그럴듯하게 표현할 수 있을까요? 이런 작업은 샘플링의 기초가 됩니다. 

 

  해당 범위 안에는 무한한 실수가 있겠지만, 우리는 그림으로 나타내기 위해서 유한한 점을 찍게 될 것입니다. 균일한 x값에 따라서 y값을 알아내는 함수를 만들어 점을 찍은 뒤, 그 점들을 전부 선분으로 잇는 것입니다. 이를 부분 선형 근사(piecewise linear approximation)라고 말합니다.

 

 
public class FunctionGraph
{
	public static void main(String[] args)
	{
		// number of line segments to plot
		int n = Integer.parseInt(args[0]);

		// the function y = sin(4x) + sin(20x), sampled at n+1 points
		// between x = 0 and x = pi
		double[] x = new double[n + 1];
		double[] y = new double[n + 1];
		for (int i = 0; i <= n; i++)
		{
			x[i] = Math.PI * i / n;
			y[i] = Math.sin(4 * x[i]) + Math.sin(20 * x[i]);
		}

		// rescale the coordinate system
		StdDraw.setXscale(0, Math.PI);
		StdDraw.setYscale(-2.1, +2.1);

		// plot the approximation to the function
		for (int i = 0; i < n; i++)
		{
			StdDraw.line(x[i], y[i], x[i + 1], y[i + 1]);
		}
	}
}

 

 

 

  이 프로그램은 함수 y = sin(4x) + sin(20x) 를 [0,π] 범위 내에서 근사적으로 그래프를 그립니다. 프로그램의 인자 n은 부분 선형 근사로 그래프를 그리기 위한 유한한 점의 개수입니다. 즉 n개의 점을 이어서 그래프를 표현하며, 따라서 n이 클수록 실제 그래프와 근사한 그래프가 나타나게 됩니다.

 

 

모양(Outline and filled shapes)

  StdDraw는 원, 사각형과 그 외 다각형을 그리는 메소드들 또한 있습니다. 각 도형은 테두리를 정의합니다. 메소드 이름이 그냥 도형의 이름일 경우 단순히 테두리만 그려집니다. filled라는 이름으로 시작될 경우, 단색으로 채워집니다. 다음 API를 참고하세요.

 

 

  circle()과 filledCircle()의 인자들은 원의 중심 (x,y)와 반지름 r을 정의합니다. square()와 filledSquare()의 인자들로, 각 변은 2r의 길이를 가지며 중심은 (x,y)가 됩니다. polygon()과 filledPolygon()은 각 꼭짓점의 x좌표 배열과 y좌표 배열을 인자로 받습니다. 다음을 참고하세요.

 

 

 

글과 색(Text and color)

  가끔, 여러분의 그림에 주석을 달거나 강조하고 싶을 때가 있습니다. StdDraw는 글자를 나타내는 메소드들 또한 갖고 있으며, 글자와 관련된 인자들과 펜의 색을 바꿀 수 있는 것들도 갖고 있습니다. 다음 API를 참고하세요.

 

 

 

  이 코드에서, Font와 Color는 기본 자료형들이 아닙니다. 이는 3.1절에서 배워볼 것입니다. 그 전까지는 이런 것들에 대해 신경쓰지 않는 게 좋겠군요. 펜 색깔로 유효한 것은 BLACK, BLUE, CYAN, DARK_GRAY, GRAY, GREEN, LIGHT_GRAY, MAGENTA, ORANGE, PINK, RED, WHITE, YELLOW가 있고, 이는 StdDraw에 정의되어 있습니다. 예를 들어, StdDraw.setPenColor(StdDraw.GRAY)는 펜의 색을 회색으로 바꿉니다.

 

 
StdDraw.square(.2, .8, .1)
StdDraw.filledSquare(.8, .8, .2);
StdDraw.circle(.8, .2, .2);
double[] xd = { .1, .2, .3, .2};
double[] yd = { .2, .3, .2, .1};
StdDraw.filledPolygon(xd, yd);
StdDraw.text(.2, .5, "black text");
StdDraw.setPenColor(StdDraw.WHITE);
StdDraw.text(.8, .8, "white text");

 

 

  모양, 색, 글자는 기가 막힌 이미지들을 수도 없이 만들어낼 수 있지만, 남용해서는 안 됩니다. StdDraw는 현대 그래픽 라이브러리의 표준에 따라 거칠게 만들어져있기 때문에, 여러분이 상상한 이미지를 그리기 위해 무지막지한 호출이 필요할 수도 있습니다. 다만 종종 유용한 정보를 표기하기 위해 사용하는 것은 여전히 가치 있습니다.

 

 

애니메이션(Animation)

  StdDraw 라이브러리는 재밌는 효과를 만들어내기 위한 것들도 제공합니다.

 

 

 

 

  기본 캔버스의 크기는 512*512 픽셀입니다. 만약 바꾸고 싶다면, 무언가를 그리기 이전에 setCanvasSize()를 호출하면 됩니다. clear()와 show() 메소드는 컴퓨터 화면에 동적인 변화를 줄 수 있습니다. 

 

 

튕기는 공(Bouncing ball)

  애니메이션의 <HelloWorld>는 검정색 공을 캔버스 위에서 움직이게 하는 것입니다. 공의 위치를 (rx, ry)라고 생각해보고, 공이 앞으로 이동할 위치를 정의해보죠. 예를 들면, (r+ .01, ry + .02)와 같이 말입니다. 우린 두 단계를 거칩니다.

 

  1. 그림을 지웁니다.
  2. 검정색 공을 새로운 위치에 다시 그립니다.

 

  움직이는 것처럼 보이게 하기 위해, 이를 계속해서 반복할 것입니다. 하지만 이것만으로는 부족한데, 컴퓨터가 워낙 빨라서 그저 검정색과 흰색 화면을 깜빡거리는 것처럼만 보일 것이기 때문입니다. 이를 해결하기 위해, StdDraw는 show() 메소드를 갖고 있습니다. show() 메소드는 그림을 보여주는 것에 대한 제어를 제공합니다. 여러분이 미리 점, 선, 면을 그려놓고 show() 메소드를 통해 한 번에 보여줄 수 있습니다.

 

  show()는 인자를 통해 몇 밀리초(milliseconds) 동안 그림을 보여줄 것인지에 대해 정할 수 있습니다. 따라서 다음 단계를 반복하면 되겠네요.

 

  1. 그림을 지웁니다.(하지만 그 결과를 show()하진 않습니다)
  2. 검정색 공을 새로운 위치에 다시 그립니다.
  3. 앞의 두 명령의 결과를 보여주고, 잠시 기다립니다.

 

 

프로그램 1.5.6: Bouncing ball

 
public class BouncingBall
{
	public static void main(String[] args)
	{ // Simulate the movement of a
		StdDraw.setXscale(-1.0, 1.0);
		StdDraw.setYscale(-1.0, 1.0);
		double rx = .480, ry = .860;
		double vx = .015, vy = .023;
		double radius = .05;
		while (true)
		{ // Update ball position and draw it there.
			if (Math.abs(rx + vx) + radius > 1.0)
				vx = -vx;
			if (Math.abs(ry + vy) + radius > 1.0)
				vy = -vy;
			rx = rx + vx;
			ry = ry + vy;
			StdDraw.clear();
			StdDraw.filledCircle(rx, ry, radius);
			StdDraw.show(20);
		}
	}
}

 

  <프로그램 1.5.6>은 세 단계를 지속적으로 거쳐서 움직이는 공을 만들어냅니다. 현재 공의 위치는 (rx, ry)이며, 새로운 위치를 구하기 위해 vx, vy를 각각 더해줍니다. vx, vy는 고정된 값이며, 이를 속도로 생각하면 됩니다. 

 

  벽에 닿게 되면 튕기게 되는데, 이는 생각보다 구현하기 쉽습니다. x방향의 움직임을 바꾸는 것은 공이 수직 벽에 부딪혔을 때, vx를 -vx로 만들면 됩니다. y방향도 마찬가지입니다. 

 

 

 

표준 소리(Standard audio)

  출력 추상화의 마지막 예제입니다. StdAudio는 소리 파일들을 다루고 재생시킬 수 있는 라이브러리입니다. 여러분은 음악을 재생하기 위해 프로그램을 사용해본 적이 있을 것입니다. 여러분들도 이젠 그런 프로그램을 작성할 수 있습니다. 또한 이 시간에 여러분들은 컴퓨터 과학과 특정 컴퓨팅에 대한 중요한 분야에 대해 배워볼 것입니다. 바로 디지털 신호 처리(digital signal processing)입니다.

 

 

콘서트 A(Concert A, 440Hz의 표준 음높이)

  소리는 분자의 진동에 의한 것이며, 특히 우리의 고막을 진동시키기 때문에 들리는 것입니다. 따라서 진동을 이해하는 것이 곧 소리를 이해하는 방법입니다. 가온 다(중간에 있는 도 음) 위에 있는 라 음을 생각해보면 좋습니다. 이 음은 사인파(sine wave) 그 이상 그 이하도 아니며, 1초에 440번 진동합니다. sin(t)는 2π마다 1회 진동하므로, t를 초 단위로 생각하고, sin(2πt * 440)의 함수를 이용하면 440번 진동하는 효과를 얻을 수 있습니다.

 

  여러분이 진동수를 두 배로 늘리거나 반절로 줄일 시, 이는 옥타브를 위 아래로 왔다갔다 하는 것이 됩니다. 예를 들어, 880Hz는 콘서트 A보다 한 옥타브 높으며, 110Hz는 콘서트 A보다 두 옥타브 낮습니다. 사람은 보통 20에서 20000Hz까지만 들을 수 있다는 점을 참고하세요.

 

 

 

샘플링(Sampling)

  디지털 소리에서 우리는 균일한 범위로 사인파의 곡선을 샘플링합니다. 범위를 잘게 쪼개면 잘게 쪼갤수록, 더 선명한 사인파를 얻게 됩니다. 보통은 초당 44,100 샘플로 쪼개 디지털 소리를 만듭니다.

 



  우리의 표준 소리 라이브러리 StdAudio.play() 메소드는 배열을 취해 소리를 재생합니다. 예를 들어 여러분이 콘서트 A 음을 10초동안 재생하고 싶다면, 44,100 개의 샘플을 1초마다 저장해야 되니 441,001 크기의 실수 값 배열을 넘겨주면 됩니다. 이 배열을 채우기 위해서 for 반복문을 사용합니다. sin(2πt * 440) 함수를 t가 0일 때부터 441000일 때까지 채워줍니다.

 

 
public class HelloAudio
{
	public static void main(String args[]) {
		int sps = 44100;
		int hz = 440;
		double duration = 10.0;
		int N = (int) (sps * duration);
		double[] a = new double[N+1];
		for (int i = 0; i <= N; i++)
			a[i] = Math.sin(2*Math.PI * i * hz / sps);
		StdAudio.play(a);
	}
}

 

  <HelloAudio>는 초당 44100의 샘플링을 가지며, 440Hz로 10초동안 음을 재생해줍니다.

 

 

파일로 저장하기

  음악은 여러분 컴퓨터의 공간을 꽤 많이 차지합니다. 초당 44,100 샘플일 경우, 4분짜리 음악은 4*60*44100 = 10,584,000 개의 숫자만큼 자리를 차지할 것입니다. 따라서 이런 숫자들을 이진 포맷(binary format)으로 표현해, 십진수의 문자열로 표현하는 것보다 더 적은 공간을 차지하게끔 만들게 됩니다. 

 

  StdAudio는 .wav 포맷을 사용합니다. 여러분은 .wav 포맷에 대해 좀 더 깊숙히 공부해볼 수 있지만, 꼭 그럴 필요는 없습니다. StdAudio가 편리하게 제공해주기 때문이죠. 

 

 

 

프로그램 1.5.7: Digital signal processing

 
public class PlayThatTune
{
	public static void main(String[] args)
	{	// Read a tune from Stdin and play it.
		int sps = 44100;
		while (!StdIn.isEmpty())
		{ // Read and play one note,
			int pitch = StdIn.readInt();
			double duration = StdIn.readDouble();
			double hz = 440 * Math.pow(2, pitch / 12.0);
			int N = (int) (sps * duration);
			double[] a = new double[N + 1];
			for (int i = 0; i <= N; i++)
				a[i] = Math.sin(2 * Math.PI * i * hz / sps);
			StdAudio.play(a);
		}
	}
}
% java PlayThatTune
7 .25 6 .25 7 .25 6 .25 7 .25 2 .25 5 .25 3 .25 0 .50

 

 

 

  <프로그램 1.5.7, PlayThatTune)은 음악을 쉽게 만들수 있다는 것을 보여줍니다. 표준음 A를 기준으로, 반음계에 대해 음을 연주해줍니다. 예를들어 7 .25의 경우 A를 기준으로 7개의 반음을 올린 음을 0.25초 동안 재생해줍니다.

 

  입출력은 추상화의 힘을 보여주는 사례입니다. 표준 입력, 표준 출력, 표준 그림, 표준 소리는 몇 번이고 다른 물리적 기기들로 의존이 바뀔 수 있지만(예를 들어 사용자는 컴퓨터의 스피커를 교체할 수 있습니다), 그럼에도 불구하고 프로그램을 수정할 필요가 없습니다. 특정 기기들만을 위해 프로그램을 작성하는 것이 아닌, 추상화된 입출력에 의존해 프로그램을 작성했기 때문입니다. 이 개념은 중요합니다. 꼭 명심하세요!

 

끝.

16개의 댓글

2021.05.18

이 미친!!! 공짜강의라니!!!

계속 써주시라효...

0
2021.05.18

고맙다

이글 읽고 구글이랑 스페이스X에서 동시 스카우트 제의왔다

2
2021.05.19

c언어 자바 암것도 몰라도 이거 봐도되나요..?

0
2021.05.19
@비빔냉면

처음 프로그래밍에 입문한다는 것을 전제로 작성된 글이라서 봐도 돼. 근데 내가 번역을 잘 못하기도 하고, 책을 기반으로 옮겨적는 글이기도 해서 유튜브같은 영상매체보다는 확실히 효과가 덜할 것 같아.

0

java 개발자로서 Java Code Conventions 을 따르지 않은 걸 보기 힘드네요ㄷㄷ

0
2021.05.19
@눈팅10년만에가입함

Convention을 따르지 않은 것들이 익숙지 않아서 보기가 불편하다는 소리야, 아니면 Convention을 전부 다 따르고 있다는 소리야?ㅋㅋ 중의적이어서 잘 모르겠네.

중괄호 위치는 Convention을 따르고 있지 않아서 전자같긴 한데.. 이것 때문에 불편한 것이라면 미안하다..

0
@스비니

아니 미안할것까진 없고... js류로 처음 개발 시작하신분들이 주로 그러시는거같더라고... 나는 java로 시작해서 그냥 개인적으로 보기 불편할뿐....

0
2021.05.19
@눈팅10년만에가입함

책에서 저렇게 쓰여있으니 충실할 뿐이긴 한데, 생각해보니 좀 의문이긴 하네. 웹사이트에 개정된 코드들 보면 전부 컨벤션에 맞게 코드들이 작성돼있긴 해. 다음부턴 너말대로 그냥 컨벤션에 맞게 작성해야겠다.

0
@스비니

eclipse 를 쓴다면 save action 으로 import 정리 및 code style 정리옵션 주는걸 추천.... 따로 신경쓸 필요가 없어서..

intellij 를 쓴다면 같은 기능을 해주는 plugin 을 설치하면 됨..

0
@눈팅10년만에가입함

우리회사는 c개발로 저 컨벤션 쓰는데 자바는 표준 컨벤션이 있나?

예전에 앱 개발할 때는 줄바꿈{ 이 아니라 {줄바꿈 이었던거 같긴 해

0
2021.05.19

부디 글 나중에라도 삭제하지 마십쇼

0
2021.05.19

자바 문법은 너무 장황해

0
2021.05.19
@한국장학재단

근데 또 자바만 하다보면 못느끼겠음 ㅋㅋ

0
2021.05.19

꾸준히 열심히하는모습 보기 좋고

0
2021.05.19

꾸준히하는모습응원한다. 자바배울생각없었는데 나도 너랑함꼐공부할게

0
2021.05.20

요즘 레스트API하게 되었는데 도움 많이됨 ㄱㅅㄱㅅ

0
무분별한 사용은 차단될 수 있습니다.
번호 제목 글쓴이 추천 수 날짜
516 [과학] 자바로 프로그래밍에 입문할래요: 3.2. 자료형 생성하기 (1) 3 스비니 0 18 시간 전
515 [과학] 자바로 프로그래밍에 입문할래요: 3.1. 자료형 (4) 11 스비니 3 2 일 전
514 [과학] 자바로 프로그래밍에 입문할래요: 3.1. 자료형 (3) 2 스비니 3 3 일 전
513 [과학] SF스압) 최후의질문 / 원래는..(How It Happened) 11 기타치는고라니 14 5 일 전
512 [과학] [양자역학 3부] 슈뢰딩거의 고양이에 대해서. 26 기타치는고라니 3 6 일 전
511 [과학] 자바로 프로그래밍에 입문할래요: 3.1. 자료형 (2) 2 스비니 3 7 일 전
510 [과학] (기상)우리나라 더위의 발생 형태 4가지. 51 마리괭이 20 11 일 전
509 [과학] 자바로 프로그래밍에 입문할래요: 3.1. 자료형 (1) 4 스비니 1 14 일 전
508 [과학] 자바로 프로그래밍에 입문할래요: 2.3. 재귀 (2) 24 스비니 5 22 일 전
507 [과학] 자바로 프로그래밍에 입문할래요: 2.3. 재귀 (1) 3 스비니 3 29 일 전
506 [과학] 블랙홀, 핵융합, 조류(鳥類), 의학사(醫學史) 등 과학 분야 ... 미분가능하지않은... 3 29 일 전
505 [과학] [물리학] 우리는 끝에 도달해 있는 가? 45 특이한 13 2021.07.02
504 [과학] 자바로 프로그래밍에 입문할래요: 2.2. 라이브러리와 클라이... 7 스비니 1 2021.06.28
503 [과학] 양자역학이 탄생하게된 '안'간단한 역사적 배경(2) 43 기타치는고라니 15 2021.06.24
502 [과학] 양자역학이 탄생하게된 '안'간단한 역사적 배경(1) 32 기타치는고라니 38 2021.06.24
501 [과학] 양자역학이 탄생하게 된 간단한 역사적 배경 19 Kuqi 10 2021.06.23
500 [과학] 자바로 프로그래밍에 입문할래요: 2.2. 라이브러리와 클라이... 4 스비니 0 2021.06.21
499 [과학] 자바로 프로그래밍에 입문할래요: 2.2. 라이브러리와 클라이... 4 스비니 8 2021.06.14
498 [과학] 아무도 알고싶지 않을수도 있는 이야기 - NASA의 인증을 받은... 26 Te2t1c1e 16 2021.06.11
497 [과학] 자바로 프로그래밍에 입문할래요: 2.1. 정적 메소드 (2) 8 스비니 0 2021.06.06