증감 연산자 ++와 --는 한 개의 피연산자를 갖는 단항 연산자로서 피연산자를 1씩 증가 혹은 감소시키는 것이다. (증감연산자는 C/C++에서의 용법과 동일하다.) 반복문에서 많이 사용되며 피연산자로서 정수형과 실수형 모두 사용할 수 있으나 주로 정수형 변수에 사용된다.


int ia = 10;

ia++; //  ia = ia + 1 과 같다.


double da = 1.0;

da++; // da = da + 1과 같다.


이와 같이 증감 연산자는 수식을 간결하게 만들어주고 실행속도 면에서 좀 더 효율적이다. 이 연산자는 매우 자주 쓰이는 연산자이지만 잘못 사용한 경우에는 발견하기 힘든 오류을 발생시킬 수 있으므로 주의해서 사용해야 한다.


[표 1] 증감 연산자의 종류와 용법

형식

의미

++x

x를 먼저 1증가시킨 후 그 값을 사용

--x

x를 먼저 1감소시킨 후 그 값을 사용

x++

x값을 먼저 사용한 후 1 증가

x--

x값을 먼저 사용한 후 1 감소


위 표에서와 같이 증감연산자는 변수 앞에도 붙을 수 있고 뒤에 올수도 있다.  ++x 나 x++ 는 프로그램에서 다른 조건식이나 수식에 연결되지 않고 단일문으로 쓰일 경우에는 같은 결과를 얻지만 수식의 일부분으로 사용할 경우에는 그 의미가 달라질 수 있다. 다음 예를 보자. (package와 class이름은 각자 다를 수 있다.)


package tut02;
public class Tut02 {
   public static void main(String[] args) {
       int ia, ib;
       ia = ib = 1;
       ia++;
       ib--;
       System.out.println("ia:"+ia+",ib:"+ib);
   }
}


이 예에서 출력되는 ia와 ib값은 각각 2와 0이다. ia++, ib--은 각각 다음과 같다.


ia = ia + 1;
ib = ib - 1;


다음 예에서와 같이 증감연산자가 다른 연산자와 사용될 때에는 주의해야 한다.


package tut02;
public class Tut02 {
   public static void main(String[] args) {
       int  ia = 10, ib = 10, ix, iy;
       ia++;
       ++ib;
       System.out.println("ia:"+ia+", ib:"+ib);

       ix = --ia;
       iy = ib--;
       System.out.println("ia:"+ia+", ib:"+ib);
       System.out.println("ix:"+ix+", iy:"+iy);
   }
}


ia:11, ib:11
ia:10, ib:10
ix:10, iy:11


이 예제에서 ia에 저장되는 값과 ib에 저장되는 값은 각각 10과 11이다. ix=--ia 에서는 ix에 대입되기 전에 먼저 ia값이 1 감소하고 그 후에 그 값이 ix에 대입된다. iy=ib-- 에서는 iy에 ib값이 먼저 대입되고 ib값이 1 감소한다. 증감연산자가 앞에 붙느냐 혹은 뒤에 붙느냐에 따라 동작의 순서가 달라진다는 점에 유의해야 한다.

 관례적으로 증감연산자를 쓰지 말아야 할 경우가 있다.

  1. 하나의 변수가 수식 내에서 두 번 이상 사용될 경우에는 증감연산자를 사용하지 않는다. 예: y = x*2 + x++

  2. 한 변수가 어떤 함수의 인자로 두 번 이상 사용될 경우에는 이 변수에 증감 연산자 ++, --를 사용하지 않는다. 예: func(x*2, x++)

그 외에도 프로그램 작성자가 혼동의 여지가 있을 것 같다면 명확하게 작성하도록 유의해야 한다.



Posted by 살레시오

 산술 연산자는 덧셈, 뺄셈 등 산술 연산을 수행하는 연산자들이고 부호 연산자는 부호를 지정하는 것들이다. 산술 연산자는 피연산자가 두 개이므로 이항 연산자이고 부호 연산자는 피연산자가 하나이므로 단항 연산자에 해당된다. 산술 연산자는 다음과 같은 것들이 있다.


[표 1] 산술 연산자

기호

기능

용례

+

덧셈/부호

12+13, a+b, 12.3+45.6+c, +12, +d
-

뺄셈/부호

12-13, a-b, 12.3-45.6-c, -12, -d
*

곱셈

12*13, a*b, 12.3*45.6*c
/

나눗셈

12/13, a/b, 12.3/45.6/c
%

나머지

12%13, a%b


예를 들면 다음과 같다.


int ia = 11, ib = 22, ic, id, ie;
ic = 1a + ib;
id = ia – ib;
ie = ia * ib;
double da = 1.1, db=2.2;
da = ie*ie;
db = da/ia;


부호 연산자는 어떤 값의 부호를 지정하거나 바꾸는데 쓰인다. +, -기호는 부호 연산자로도 사용되며, 부호 연산자는 한 개의 피연산자를 요구하는 단항 연산자이다.  예를 들면 다음과 같다.


+1234   -1234   -temp   +a   -b


따라서 다음과 같은 표현식에서 첫 번째 ‘-’는 부호연산자이고 두번째 ‘-’는 산술연산자이다.


ia = -ib - ic;


 연산의 결과를 변수에 저장할 때는 결과 값이 그 변수의 허용 범위에 들어가는지 여부를 잘 판단해야 한다.


int ia = 2000000;
int ib = ia*10;
byte bya = 129; // 오류
short sa = 700000;//오류


나머지(%)연산의 예를 들면 다음과 같다.


10%5 // 0
3%2 // 1
8%3 // 2
3%5 // 3


한 가지 주의할 점은 %연산자의 피연산자는 정수형과 실수형 모두 사용 가능하다. (C/C++에서는 정수형만 사용가능하지만 자바는 그렇지 않다.)


double da=5.2, db=4.1;
System.out.println(da%db); // 1.1이 출력됨


 다음 예제는 다양한 숫자의 2로 나눈 나머지를 출력해 주는 프로그램이다.


package tut02;
public class Tut02 {
   public static void main(String[] args) {
       byte bya = 13;
       int ia = 23456;
       float fa = 78.567f;
       System.out.println(bya%2);
       System.out.println(ia%2);
       System.out.println(fa%2);
   }
}


1
0
0.56700134


 다음 예제는 두 수의 덧셈, 뺄셈, 곱셈, 나눗셈의 결과를 표시해 주는 프로그램이다.


package tut02;
public class Tut02 {
   public static void main(String[] args) {
       int ia = 23456, ib=789;
       int ir = ia + ib;
       System.out.println("ia + ib = "+ir);
       ir = ia - ib;
       System.out.println("ia - ib = "+ir);
       ir = ia * ib;
       System.out.println("ia * ib = "+ir);
       System.out.println("ia / ib = "+(ia/ib));
   }
}


ia + ib = 24245
ia - ib = 22667
ia * ib = 18506784
ia / ib = 29


 자바는 컴파일하는 시점에서 변수에 어떤 상수를 입력할 때 범위를 체크하여 허용 범위를 넘어선다면 에러를 발생시킨다. 또한 산술연산을 할 때 다음과 같이 자동 형 변환이 일어난다.


  • 두 피연산자 중 하나라도 double 형이면 다른 하나도 double 형으로 변환하고 결과도 double형이다.

  • 그렇지 않고 두 피연산자 중 하나라도 float 형이면 다른 하나도 float 형으로 변환하고 결과도 float형이다.

  • 그렇지 않고 두 피연산자 중 하나라도 long 형이면 다른 하나도 long 형으로 변환하고 결과도 long형이다.

  • 그렇지 않다면 두 피연산자를 모두 int 형으로 변환하고 결과도 int 형이다.


자바에서 산술연산에 대해서는 이 네 가지의 규칙을 따른다. (c/c++의 경우보다 훨씬 더 간결하다.) 특히 마지막 규칙 때문에 예를 들어서 두 개의 byte형이나  short 형의 연산의 결과는 int형이 된다. 따라서 다음과 같은 간단한 연산도 에러를 발생한다.


short sa = 10, sb=20;
short sc = -sa;
short sd = sa+sb; //에러


범위를 벗어나는 것도 아닌데 왜 에러가 발생하는지 처음에는 의아할 수 있다. -sa와  sa+sb의 연산 결과는 int 형이고 이것을 short 형에 대입하려고 하기 때문이다. (C/C++ 프로그래머는 처음에 혼동하기 쉽다.) 자바에서는 크기가 작은 자료형으로의 형변환(lossy conversion)은 무조건 명시적으로 해 주어야 한다. 따라서 다음과 같이 명시적으로 형변환을 해주어야 한다.


short sa = 10, sb=20;

short sc = (short)(-sa);

short sd = (short)(sa+sb);


이것은 byte형에 대해서도 마찬가지이다.




Posted by 살레시오

 자바에서 같은 바이트 수를 가지는 long 형과 double 형의 계산 속도 차이가 거의 나지 않는다는 것을 며칠 삽질한 결과 알아냈다. 정수형 연산이 훨씬 빠를거라고 지레 짐작했던 것이 보기 좋게 빗나간 것이다. 왜 그런지는 아직도 잘 모르겠다.


 실험 방법은 long형으로 고정 소숫점 숫자 연산을 간단하게 구현하고,  예를 들어 처음 여섯 자리를 소수 자리로 간주한다면 (즉 1,000,000이 1.0임)


  • 덧셈,뺄셈은 그대로 수행한다.

  • 두 수의 곱셈은 각각을 1000으로 먼저 나누고 곱셈

  • 두 수의 나눗셈은 나눈 결과에 1000000을 곱한다.


이렇게 연산을 하게끔 구성해 놓고 거의 동일한 연산을 수행해 보았더니 오히려 double형을 사용한 것이 더 빠르다는 결과가 나왔다.


 이제는 C++로 코딩해도 똑같은 결과가 나올까 궁금하다.





Posted by 살레시오

 자바에서는 문자열(string)을 처리할 수 있는 String 클래스를 제공한다. 클래스에 대해서는 아직 설명하지 않았지만 문자열은 간단하게라도 알고 넘어가야 한다. 자바에서 문자열은 기본형이 아니라 참조형이고 큰따옴표를 이용하여 표현한다. 그리고 문자열 변수를 선언/초기화하는 것은 String은 클래스이지만 기본형의 변수를 선언하고 초기화하는 방법과 동일하다.


String name; //문자열 선언
name = “홍길동”; // 문자열 초기화

String title = “선생님”;//선언과 동시에 초기화


다음과 같이 화면에 출력할 수도 있다.


System.out.println(name); // name 문자열의 내용이 화면에 출력된다.


두 개의 문자열을 서로 연결하는 데 ‘+’연산자를 이용할 수도 있다.


String fullName = name + title; // 두 문자열 연걸
String sayHi = “안녕하세요. “ + name;
String sayHello = “안녕하세요. “ + name + title; //세 개 이상도 연결 가능


다음과 같이 System.out.println() 함수에 문자열 연결식을 직접 입력할 수도 있다.


System.out.println(“안녕하세요. “+name+”씨.”);


이렇게 하면 불필요한 문자열 변수를 생성하지 않고 직접 연결된 문자열을 화면에 출력할 수 있다.


 어떤 기본형 변수의 값을 출력할 때에도 System.out.println()함수를 사용할 수 있다.


double da = 11.2;
System.out.println(da);


함수 System.out.println() 는 문자열을 인자로 주어야 하는데 이경우 변수값 da는 내부적으로 문자열로 자동으로 변환되어서 System.out.println()에 그 문자열을 넘겨준다. 따라서 다음과 같이 연결하는 것도 가능하다.


double da = 11.2;
System.out.println(“da 값은 “ + da + “입니다.”);


이 경우 연결이 일어나기 전에 da값은 문자열로 변환되어 세 개의 문자열을 연결한 새로운 문자열이 System.out.println()에 인자로 넘어가는 것이다.




Posted by 살레시오

 자바 프로젝트를 netbean 에서 윈도 실행 파일로 빌드하는 방법은 매우 간단한데 다음과 같이 프로젝트의 속성창에서 설정해주면 된다. (프로젝트명에서 오른 클릭을 하면 '속성'메뉴가 나온다.)

이 메뉴가 체크되었다면 프로젝트명에서 오른 클릭을 하면 'Pakage As..' 메뉴가 새로 생긴 것을 확인할 수 있을 것이다. 하위 메뉴의 'Image Only' 항을 선택하면 윈도우exe파일을 생성할 수 있다. 생성된 이미지는 프로젝트폴더/dist/bundle 폴더 안에 생성된다.


 만약 이것으로부터 msi 인스톨러를 생성하려면 Wix 와 같은 외부툴을 설치하여 사용해야 한다.


 그런데 javafx2 응용프로그램을 image build 를 해서 윈도우 exe 를 생성했을 경우 아이콘이 제대로 심어지지 않는다는 문제가 있다. (아직도 해결이 안 된 것 깉다.) 일단 프로그램 내부에서 사용되는 아이콘 이미지는 다음과 같이 설정해 주면 된다.

@Override

   public void start(Stage stage) throws Exception {

       primaryStage = stage;

       

       Parent root = FXMLLoader.load(getClass().getResource("FXMLDoc.fxml"));

       Scene scene = new Scene(root);

       stage.setScene(scene);

       stage.show();

       stage.getIcons().add(new Image("file:_resources\\icon_256.png"));

   }

하지만 deploy 된 실행 파일에는 아이콘이 제대로 표시되지 않으며 단축아이콘을 바탕화면으로 빼도 역시나 아이콘이 잘 못 표기된다. 여러가지 해결책이 검색되었지만 윈도7에서는 잘 해결되지 않았다.


 그 런데 'Bat to Exe Converter' 라는 프로그램을 이용하여 문제를 한 다리 건너서 해결하는 수가 있었다. 원래의 exe파일을 실행하는 배치파일을 다시 실행파일로 생성한 후 이것에 아이콘을 지정해 주면 문제가 해결되었다. 만약 원래의 실행파일이 ArudinoHarp.exe라고 한다면 다음과 같은 launcher.bat 화일을 생성한다.

    @echo off

    start ArduinoHarp.exe

이것을  'Bat to Exe Converter'  프로그램을 이용하여 아이콘을 지정해 준 후 실행파일로 바꾸는 것이다. 사용자는 이렇게 생성된 launcher.exe 파일을 실행시키거나 바탕화면에 단축아이콘을 지정해 줄 수 있다. 아이콘 이미지의 해상도는 64x64 이상이어야 제대로 표시된다.



Posted by 살레시오

 자바(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 살레시오

 자바의 자료형은 크게 기본형(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 살레시오