자바(JAVA)는 컴퓨터 프로그래밍 언어 중의 하나로 썬마이크로시스템스(Sun Microsystems, 이하 썬) 라는 회사에서 개발하여 1996년 1월에 초기 버전이 발표된 객체 지향 (object-oriented) 언어이다. 썬의  제임스 고슬링, 아서 밴 호프와 같은 엔지니들이 처음 설계하였다고 알려져 있다.


    

[그림 1] 자바의 창시자인 제임스 고슬링과 마스코트(duke) 이미지


 원래는 썬의 엔지니어들에 의해서 가전 제품에 탑재될 소프트웨어를 만들려는 목표로 1990년에 개발이 시작되었다. 프로젝트의 초기에는 C++을 확장하여 사용하려 했지만 적합하지 않다고 판단하여 C++의 장점은 취하고 단점은 보안한 새로운 언어인 Oak 가 만들어졌다. 이후에 인터넷에 적합하도록 개발 방향이 바뀌면서 자바로 이름을 바꾸고 정식 버전을 1996년 1월에 발표하였다. 인터넷이 보급되면서 운영 체제와 상관 없이 어디에서든 실행할 수 있는 자바의 특성과 자바 애플릿(applet)의 인기에 힘입어 널리 사용되기 시작하였다.


 자바는 “Write once, run anywhere”라는 모토에 충실하여 한번 작성되어 컴파일된 실행 파일은 운영 체제와 상관없이 실행 가능하다. 이것이 가능한 이유는 자바 컴파일러는 소스 프로그램을 특정 기계어로 번역하지 않고 가상 언어로 번역한다. 그리고 그 가상 언어를 특정 기계어로 번역하여 실행하는 시스템을 자바 가상 머신(Java virtual machine, JVM)이라고 한다. (이름에 머신이라는 말이 붙어 있지만 이것도 프로그램이다.) 이 자바 가상 머신(Java Virtual Machine)은 여러 OS용으로 만들어져 있으므로 이것이 설치된 곳이라면 윈도PC, 맥, 리눅스, 서버 컴퓨터, 심지어 가전 제품 등 가리지 않고 어디에서든 자바 프로그램을 실행할 수 있다. 이러한 장점으로 인해서 자바는 다양한 기종의 컴퓨터와 운영 체제가 공존하는 인터넷 환경에 적합한 언어로서 인터넷의 발전과 함께 많은 사용자를 확보해 나갔다. 또한 기존의 C++언어의 장점은 채택하되 잘 사용하지 않는 부분은 배제하고 비교적 배우기 쉬운 간결한 문법도 사용자층을 넓히는데 한몫했다. 그리고 풍부한 클래스 라이브러리(Java API)가 공개되어 있기 때문에 프로그래머는 이것을 잘 활용하면 손쉽게 강력한 기능의 프로그램을 작성할 수 있다.


 자바를 처음 개발해서 보급했던 썬마이크로시스템스는 2010년에 데이터베이스로 유명한 오라클 (Oracle) 이라는 회사에 합병되었으며 따라서 현재 자바는 오라클사에 의해서 유지/배포되고 있다. 한 예로 구글의 안드로이드는 자바의 API를 이용하여 작성한 달빅(Dalvik)이라는 가상 머신 위에서 자바로 작성된 앱을 구동하며 자바 개발자들을 안드로이드로 끌어들여 큰 성공을 거두었다. 하지만 이로 인해서 오라클과 구글 간 자바  API의 사용료(저작권료)에 대한 소송이 진행되고 있기도 하다.


 자바 언어의 특징은 다음과 같이 요약할 수 있다.


  1. 운영체제에 독립적이다. 한번 만들어진 실행 파일은 자바 가상 머신이 설치된 곳이라면 어느 곳에서든지 바로 실행할 수 있다.

  2. 겍체 지향 언어이면서 배우기 쉽고 간결한 문법을 가지고 있다.

  3. 포인터(pointer)를 다룰 필요 없이 메모리 관리를 가상 머신이 자동으로 수행한다.

  4. 네트워크, 분산 처리, 멀티 쓰레딩을 지원한다.

  5. 최근에는 성능도 많이 개선되어 c/c++로 작성된 프로그램에 비해서도 그 실행 속도가 뒤지지 않는다.


 앞으로는 이러한 특징을 가지는 자바 언어의 기본적인 개발 방법에 대해서 알아보도록 하겠다.



Posted by 살레시오
,

 자바에는 기본형에 대응하는 wrapper 클래스가 있다. 예를 들면 int 는 Interger, double은 Double 이다. 제네릭 클래스에는 기본형을 사용할 수 없으므로 이 wrapper 클래스를 사용해야 한다.


 그런데 기본형과 wrapper클래스의 성능 차이가 궁금해서 다음과 같은 간단한 프로그래으로 시험해 보았다.


package wrappertest01;

public class WrapperTest01 {
   public static long iter = 1000000L;
   public static int id;
   public static double db, dSum;
   public static long le, ls;

   public static Double[] dArr;
   public static double[] darr;

   public static void main(String[] args) {
       dArr = new Double[100];
       for(int k=0;k<100;k++) dArr[k]=new Double(1.0);
       
       darr = new double[100];
       //for(int k=0;k<100;k++) dArr[k]=new Double(1.0);

       lst = new ArrayList<>();
       for(int k=0;k<100;k++) lst.add(new Double(1.0));

       doIt();
       doIt();
       doIt();
   }
   
   public static void doIt() {
       double dSum1 =0, dSum2=0;
       long id;
       for(int n=0;n<10;n++) {
           
           ls = System.nanoTime();
           for(int k=0;k<iter;k++)
               for(int x=0;x<100;x++) {
                   db=dArr[x];
                   dArr[x]=db;
               }
           le = System.nanoTime();
           dSum1 += (le-ls)/1e9;

           ls = System.nanoTime();
           for(int k=0;k<iter;k++)
               for(int x=0;x<100;x++) {
                   db=darr[x];
                   darr[x]=db;
               }
           le = System.nanoTime();
           dSum2 += (le-ls)/1e9;
        }
       System.out.println("Double Arr: "+dSum1/10+ "sec.");
       System.out.println("double arr: "+dSum2/10+ "sec.");
   }
}


단순히 배열을 만들어서 배열의 요소를 읽고 쓰는 동작만 1억x100 번을 10번 실행한 평균 시간을 구한 것이다. wrapper클래스가 오버헤드가 있으므로 당연히 다소 느릴거라는 예상 했다. 결과는 기본형의 배열이 훨씬 더 동작이 빠르다는 것이다.



수치상으로는 거의 40배 빠르다.  이 실험만으로 전반적인 성능 비교는 물론 안되겠지만 성능이 중요한 곳에서는 왠만하면 기본형을 사용해야하며  제네릭 클래스를 구현하는 경우와 같이 어쩔 수 없는 경우에만 wrapper 클래스를 사용해야 한다는 언급이 맞는 것 같다.




Posted by 살레시오
,

 자바에서는 일차원 배열뿐 아니라 이차원, 삼차원.. 등등의 다차원 배열도 사용할 수 있다. 삼차원 이상의 배열은 이차원 배열과 사용법이 동일하므로 여기서는 이차원 배열에 대해서만 설명하겠다.


 이차원 배열은 선언할 때 변수명 뒤에 대괄호 쌍 두 개가 온다. 예를 들면 다음과 같다.


int num[][];
double val[][];
char mch[][];


위의 선언문은 사용했다고 해서 바로 배열을 사용할 수는 없고 일차원 배열에서와 마찬가지로 실제 메모리를 할당받아야 하는데 new 연산자를 이용한다. new 키워드 다음에 자료형[차수][차수] 형태로 입력한다. 예를 들면 다음과 같다.


num = new int[3][4];
val = new double[2][3];
mch = new[100][1000];


메모리를 할당하면 배열의 요소는 자동으로 기본값(정수형, 실수형은 0)으로 채워진다. 위와 같이 선언과 메모리 할당을 분리해서 수행할 수도 있고 아니면 선언과 메모리 할당을 동시에 할 수도 있다.


int num[][] = new int[3][4];;
double val[][] = new double[2][3];
char mch[][] = new char[100][1000];


만약 선언과 동시에 배열을 특정한 값들로 초기화를 하는 경우라면 new 연산자를 사용할 필요 없이 다음과 같이 중괄호를 이용할 수 있다.


double val[][] = {
   {1.1, 2.2, 3.3},
   {4.4, 5.5, 6.6}
};


이 경우 주어진 초기값에 의해서 배열의 크기는 자동으로 정해지게 된다.

 배열의 요소를 참조하는 방법은 일차원 배열과 유사하게 변수명 뒤에 대괄호로 인덱스를 지정하는데 이 경우 대괄호쌍이 두 개가 온다.


val[0][0] = 10.1; // 요소값을 지정하는 경우
double da = val[1][2]; //요소값을 읽어내는 경우


이차원 배열의 경우 length 필드는 최상위 차원의 크기를 갖는다. 하위 차원의 크기를 구하고 싶다면 다음과 같이 하면 된다.


System.out.println( val.length ); // 2가 출력된다.
System.out.println( val[0].length ); // 3이 출력된다.
System.out.println( val[1].length ); // 3이 출력된다.


 자바에서 배열은 참조형(reference type)이라는 점도 숙지하고 있어야 한다. 따라서 다른 함수에서 배열을 그대로 받아서 조작하는 경우 원 배열도 영향을 받게 된다.



Posted by 살레시오
,

 자바 제네릭(generic) 프로그래밍에 대해서 실습하던 중에 제네닉 타입의 단순 배열을 생성하는데 미묘하게 안 되는게 있기도 해서 구글링을 해 보았더니 배열을 쓰지말고 웬만하면 List<>를 사용하는게 여러 모로 편하다고 하는 의견들이 많았다. 성능차도 별로 없다고 해서 직접 간단한 프로그램으로 실행 시간을 측정 해보기로 하였다..


 초기에 크기는 배열과 리스트 모두 정해졌다고 가정하고 단순 읽고 쓰는 속도만 비교하였다.


package listtestj01;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class ListTestj01 {
   public static    long iter = 1000000L;
   public static    int id;
   public static    double db, dSum;
   public static long le, ls;

   public static Double[] dArr;
   public static List<Double> lst;

   public static void main(String[] args) {
       dArr = new Double[100];
       for(int k=0;k<100;k++) dArr[k]=new Double(1.0);
       
       lst = new ArrayList<>();
       for(int k=0;k<100;k++) lst.add(new Double(1.0));

       doIt();
       doIt();
       doIt();
   }
   
   public static void doIt() {
       double dSum1 =0, dSum2=0;
       long id;
       for(int n=0;n<10;n++) {
           
           ls = System.nanoTime();
           for(int k=0;k<iter;k++)
               for(int x=0;x<100;x++) {
                   db=dArr[x];
                   dArr[x]=db;
               }
           le = System.nanoTime();
           dSum1 += (le-ls)/1e9;

           ls = System.nanoTime();
           for(int k=0;k<iter;k++)
               for(int x=0;x<100;x++) {
                   db = lst.get(x);
                   lst.set(x, db);
               }
           le = System.nanoTime();
           dSum2 += (le-ls)/1e9;
        }
       System.out.println("Double Arr: "+dSum1/10+ "sec.");
       System.out.println("List<Doub>: "+dSum2/10+ "sec.");
   }
}


이 예에서 붉은 색으로 마킹된 부분을 보면 단순히 배열 요소에서 하나를 읽고 다시 하나를 쓰고를 1억번 반복하고 이것을 다시 열 번 반복해서 평균시간을 구해서 비교하는 것이다. 내 노트북(윈764비트)에서 다음과 같은 결과를 얻었다.



세 번 반복해서 재 보아도 모두 단순 배열쪽이 두 배 이상 속도가 빨랐다. 리스트가 느리더라도 그 차이가 많이 안 나길 기대했는데 이것으로 적어도 대규모 연산이 있는 곳에서는 단순 배열이 속도 면에서 훨씬 더 낫다는 (당연한) 결과를 얻었다.




Posted by 살레시오
,

 자바의 자료형은 크게 기본형(primitive type)과 참조형(referene type)으로 나뉜다. 그리고 기본형은 다시 정수형, 실수형, 문자형, 논리형 네 가지로 분류할 수 있다. 이것들을 다음 표에 정리하였다.


[표 1] 자바의 기본 자료형(primitive type)의 종류

분류

이름

바이트 수

비고

정수형

byte

1

-127 ~ +128

short

2

-32,768 ~ + 32,767

int

4

-2,147,483,648 ~ +2,147,483,647

long

8

-9,223,372,036,854,775,808~

+9,223,372,036,854,775,807

실수형

float

4

단정도 실수형 (유효 자리는 7 정도임)

double

8

배정도 실수형 (유효 자리는 15정도)

문자형

char

2

유니코드 문자열

논리형

boolean

1

true, false


 정수형은 정수를 저장하는 자료형으로서 byte, short, int, long 네 가지가 있으며 각각에 저장할 수 있는 정수의 범위가 다르다 ([표 1] 참조) 한 가지 알아둘 것은 C/C++ 과 다르게 자바의 정수형에는 unsigned 형이 없고 부호 있는 정수형만 있다는 것이다. (자료 구조의 단순함을 유지하기 위해서 이렇게 설계했다고 한다.) 그리고 C/C++의 long long int 가 자바의 long형에 해당된다. 숫자 상수끝에 L/l 접미어가 붙으면 long형으로 저장된다.


 실수형은 실수(소숫점이나 e/E를 포함하는 수)를 저장하는 자료형으로서 float와 double 형이 있다. (이것은 C/C++과 동일하다.) 숫자 상수 끝에 f/F 접미어가 붙으면 float형으로 저장된다.


 컴퓨터에서는 모든 문자에 번호를 할당하고 문자를 정수로 바꿔서 저장한다. 어떤 문자에 어떤 번호를 할당하는 가는 여러 방법이 있으며 자바는 유니코드(unicode)라는 세계 표준 규격을 따른다. 유니코드는 국제적으로 사용되는 모든 문자를 0~65,535 범위(2 바이트)의 정수에 할당한 것이라고 이해하면 된다. 자바의 char형은 유니코드 한 문자를 표현할 수 있는 자료형으로서 2 byte 크기이다. 문자상수는 작은 따옴표를 사용하여 표시한다. 예를 들면 ‘a’, ‘가’, ‘3’ 등이다. (C/C++에서는 char형이 1byte이다. 혼동하면 안된다.)


 논리형은 true(참)과 false(거짓) 단 두 개의 값만을 가지는 자료형이다. 조건 검사에서 사용되는 논리식의 결과값을 저장하는 용도로 사용된다.




Posted by 살레시오
,

 이전 포스트에서 C++의 double형 연산과 long long int 형 연산 속도를 측정한 적이 있는데 똑같은 일을 JAVA에서 수행하고 시간을 측정해 보았다. (JAVA는 long형이 64비트 정수형이고 c++의 long long int 형에 대응한다.)


package javaapplication5;
public class JavaApplication5 {
   public static void main(String[] args) {
       long iter = 100000000; //1억번
       
       System.out.println("Start");
       long ls, le;
       double da=12.3, db=45.6;
       ls = System.nanoTime();
       for(long k=0;k<iter;k++) da *= db;
       le = System.nanoTime();
       double tm1 = (le-ls)/1e9;
       System.out.println("elapsed time 1 = "+tm1);
       
       long la=2, lb=2;
       ls = System.nanoTime();
       for(long k=0;k<iter;k++) la *= lb;
       le = System.nanoTime();
       double tm2 = (le-ls)/1e9;
       System.out.println("elapsed time 2 = "+tm2);
       
       System.out.println(tm1/tm2 + " times faster.");
   }   
}


수행 결과는 의외였다.



JAVA로 실행한 결과가 훨씬 더 수행시간이 짧다. 당연히 JAVA가 수행시간이 더 걸릴 줄 알았는데 아니었다. 아래가 g++ 로 컴파일하여 수행시간 결과다. 똑 같은 일은 c++ 은 14.591초, 자바는 0.357초 걸렸다.



윈도에서는 g++ 성능이 낮고 최적화를 전혀 하지 않았음을 감안하더라도 성능 차이가 이렇게 날 줄 몰랐다. 자바도 중간어를 JIT 컴파일해서 실행하므로 c++과의 실행 속도 차이가 그다지 크지 않다고 알고는 있었는데 직접 해보니 사실이었다. 한 가지 자바에서는 정수형과 실수형의 연산 속도 차이가 c++에서만큼 크지 않다는 것도 알 수 있었다.


 그렇다면 c++을 고집할 필요가 없는 것 아닌가 싶다. JAVA를 이용하는 것이 훨씬 더 편하고 쉽다. 더군다나 CUDA4J 같은 GPU를 사용할 수 있는 라이브러리도 있으니 성능 향상이 필요할 때는 이것을 사용하면 되지 않을까.


 실수 연산과 정수 연산의 시간 차이를 알아보기 위해서 자바로 실험을 조금 더 해 보았다.


package javaapplication5;
import static java.lang.Math.exp;
public class JavaApplication5 {
   public static void main(String[] args) {
       long iter = 100000000;
       
       System.out.println("Start");
       long ls, le;
       double da=12.3, db=45.6, dc=0, dd=0;
       ls = System.nanoTime();
       for(long k=0;k<iter;k++) {
           dd = da*db;
           dc = exp(dd);
           da += 1e-8;
       }
       le = System.nanoTime();
       //System.out.println(da + ", " + dc);
       double tm1 = (le-ls)/1e9;
       System.out.println("elapsed time 1 = "+tm1);
       
       long la=2, lb=2, lc = 0, ld=0;
       long[] larr = new long[2000];
       
       ls = System.nanoTime();
       for(long k=0;k<iter;k++) {
           long ll = k%2000;
           ld = la*lb;
           lc = larr[(int)ll];
           la++;
       }
       le = System.nanoTime();
       double tm2 = (le-ls)/1e9;
       System.out.println("elapsed time 2 = "+tm2);
       
       System.out.println(tm1/tm2 + " times faster.");
   }
}


이 연산에서는 30배 정도 속도에서 차이가 난다.


Posted by 살레시오
,

 러플(RUR-PLE, RUR - Python Learning Environment)은 파이썬을 이용한 교용용 프로그래밍 언어 환경이다. 사용자는 명령을 통해 화면에 있는 로봇을 움직이며 프로그램잉의 개념에 대해 학습을 할 수 있다.



러플의 특징은 다음과 같다. 프로그래밍을 처음 접하는 학생들에게 추상적인 수치를 다루는 내용보다는 간단한 명령의 조합을 통해 눈에 보이는 로봇을 조작함으로써 프로그래밍을 보다 쉽게 이해할 수 있도록 한다. 사용 문법은 초보자도 쉽게 익힐 수 있을 정도로 간단하지만 강력한 기능을 지원하고 다양한 분야에 이용되는 파이썬 언어를 학습할 수 있다. 혼자서도 학습할 수 있는 튜토리얼이 많다. 파이썬을 별도로 설치하지 않아도 기본적으로 파이썬 쉘과 에디터를 제공한다.



그리고 다양한 운영체제에서 실행할 수 있는 배포판을 제공한다.


 개인적으로 스크래치와 함께 프로그래밍의 개념을 학습할 수 있는 좋은 도구라고 생각된다.



Posted by 살레시오
,

 파이썬 3.4 이상에서 표준화된 Enum객체를 지원한다. 자세한 설명은 여기에 있다. 간략한 사용법을 알아보도록 하자.


 일단 Enum 클래스를 임포트해야 한다.


>>> from enum import Enum


첫 번째로 다음과 같이 클래스를 Enum을 상속해서 생성할 수 있다.


>>> class Color(Enum):
...     red = 1
...     green = 2
...     blue = 3


이제 Color.red 또는 Color.green 과 같이 사용할 수 있다. 첫 번째 값은 보통 1부터 시작한다. (0으로 시작하면 그 필드는 False가 된다.)


 다른 방법으로 다음과 같이 더 간단히 생성할 수 있다.


>>> Color = Enum('Color', 'red green blue')


유의할 점은 인스턴스 이름과  Enum생성자의 첫 인자가 (위에서 밑줄 쳐진 두 부분) 같아야 한다. 이제 이전과 마찬가지로 Color.red 또는 Color.green 과 같이 사용할 수 있다.


enum 필드는 name과 value를 가진다. 예를 들어 Color.blue 의 name 은 'blue' value 는 3 이다.


>>> Color.blue.name
'blue'

>>> Color.blue.value
3

>>> type(Color.blue)
<enum 'Color'>



Posted by 살레시오
,

 오토데스크사의 인벤터를 사용하다 보니 이것과 비슷한 워크플로우로 작업을 할 수 있는 오픈 소스나 무료 프로그램이 있을까 해서 찾아보았는데 다음과 같은 것들이 눈에 띈다.

 

123d Design 은 인벤터 개발사인 autodesk사가 만든 것인데 프로버전은 구매를 해야 하지만 기 본적으로 무료로 사용할 수 있고 인벤터에 익숙하다면 곧바로 사용할 수 있을 정도로 구성이나 메뉴가 유사하다. 간단한 기계부품을 설계하는데 손색이 없다. 독립적인 프로그램을 설치해서 사용할 수도 있고 웹버젼도 있다는 것이 특징이다.


[그림 1] autodesk 사의 123d design


 freeCAD는 아직 버전이 0.15 이지만 싱당히 강력해 보이는 3d캐드이다. 오픈소스로 개발되고 있으며 가강 강력한 인벤터의 alternative가 아닐까 개인적으로 생각된다. 향후 발전이 상당히 기대된다.


[그림 2] freecad 오픈소스 무료 3d 캐드 프로그램이다.

 

 designspark mechanical은 rs 사에서 제공하는 무료 기계설계 3d캐드 프로그램이다. 현재 (2014년 10월) 버전은 1.0이지만 기능은 빈약한 것 같다.

[그림 3]  designspark mechanical


 이 중에서 가장 인벤터와 비슷하게 사용할 수 있는 것을 꼽으라면 freecad 이다. 인벤터에서의 설계 순서(2d 스케치 -> 돌출 -> 2d 스케치 -> 돌출…)와 비슷하게 기계 부품을 설계해 나갈 수 있다.




Posted by 살레시오
,

 학부생들에게는 (공대생이라 할 지라도) 수학 계산에 쓰이는 프로그램이 낯설 것이다. 여기서 '수학 계산에 쓰이는 프로그램'이라는 것은 윈도우를 깔면 기본으로 제공되는 계산기 프로그램을 말하는 것이 아니라 수학 문제를 해결하는데 사용되는 전문적인 프로그램을 말하는 것이다.


 사실 공대에 들어와서 <일반 수학>이나 <공학 수학>같은 과목들을 배울 때에는 손으로 풀거나 공학용 계산기 같은 것으로 함수 입력해서 그래프를 그리고 하는 방식이 아직까지는 익숙한 풍경이다. 학부생들이 전문적인 컴퓨터 프로그램을 이용한다는 것은 그리 일반적이지는 않은 것 같다. '곱셈이나 나눗셈' 하면 '계산기'가 보통은 떠오르지만 '방정식'을 푸는데 컴퓨터로 그 식들을 입력하고 엔터키를 치면 그 해를 간단히 구할 수 있다는 것을 아는 학부생들이 얼마나 될까.


 이러한 수학 과목에서 매스메티카(mathematica)나 매트랩(matlab)을 실습에 도입한 교재들이 간간히 있기는 하다. 하지만 이들 패키지는 고가의 상용 제품들이므로 학부생들이 자유롭게 실습에 이용하기에는 제약이 따른다. 하지만 훌륭한 대안이 있는데 바로 Maxima와 Sage라는 프리웨어들이다.

[그림 1] Maxima의 외형

 이 그림의 첫번째 명령에서 보면 입력방정식이 x2+ax+b=0 으로 a와 b라는 기호를 어떤 수치값을 갖는 변수가 아니라 문자상수로 취급하여 그 해를 보여줌을 알 수 있다. 이렇게 문자 상수를 숫자처럼 다루는 것을 기호식 해석(symbolic analysis)라 하고 mathematica, maple, maxima, sage와 같은 프로그램이 사용된다. 반면, 변수 이외의 모든 기호는 어떤 수치값을 지정하여 문제를 푸는 것을 수치 해석(numerical analysis)라고 하고 일반 계산기 (프로그램), MATLAB, SciLab, Octave, FreeMat 등의 프로그램이 사용된다.


[그림 2] Sage의 외형


 개인적인 관심은 <공학 수학>의 교과 과정에 Maxima나 Sage 같은 프로그램의 사용법을 접목시킬 수 있는가이다. 공과 대학의 수학 과목들이 학생들이 주어진 공학적 문제를 수학적으로 모델링하고 그것을 해결하는 능력을 배양하는 데에 목적이 있지만 이제는 컴퓨터를 이용한 문제 해결 능력도 같은 비중으로 다루어져야 한다고 생각하기 때문이다. 즉, 기존에는 수학에서 컴퓨터 이용 능력이 보조적인 역할로 다루어졌지만 이제는 동등하거나 혹은 더 비중있게 다루어져야 하지 않을까 하는 생각이 든다.



Posted by 살레시오
,