JAVA LV 2-2

산술 연산자

Posted by Gihoon on March 13, 2023

사칙 연산자 + - * /

1
2
3
4
5
6
7
8
9
10
11
12
13
14
        int a = 10;
        int b = 4;
​
        System.out.printf("%d + %d = %d\n",  a, b, a + b);
        System.out.printf("%d - %d = %d\n",  a, b, a - b);
        System.out.printf("%d * %d = %d\n",  a, b, a * b);
        System.out.printf("%d / %d = %d\n",  a, b, a / b);
        System.out.printf("%d / %f = %f\n",  a, (float)b, a / (float)b);
실행결과:
10 + 4 = 14
10 - 4 = 6
10 * 4 = 40
10 / 4 = 2
10 / 4.000000 = 2.500000

​ 여기서 눈 여겨볼것은 10을 4로 나눈 결과가 2.5.가 아닌 2라는 점이다. int 타입의 값은 소수점 이하는 저장하지 못하므로 정수만 남고 소수점 이하는 버려진다. 이때 반올림은 발생하지 않는다.
그래서 올바른 연산결과를 위해서는 한쪽을 실수형으로 형변환 해야한다. 그리고 피연산자가 정수형인 경우 나누는 수를 0을 사용할 수 없다. 부동 소수점값인 0.0f , 0.0d 로 나누는 것은 가능하지만 그 결과는 무한대이다. ​

1
2
3
4
5
           byte a = 10; 
            byte b = 20; 
            byte c = a + b; 
​
            System.out.println(c); 

​ 위의 결과는 에러가 발생한다. ‘a+b’의 값은 byte형이 아닌 int형이므로 ‘byte c = (byte)(a * b);로 형변환을 해주어야 한다. ​

1
2
3
4
5
        byte a = 10;
        byte b = 30;
        byte c = (byte)(a * b);
​
        System.out.println(c);

​ 위의 결과는 44가 출력된다. 원래 결과는 300이어야 하지만, 형변환에서 배운 것처럼 300은 byte형의 범위를 넘기 때문에 데이터 손실이 발생하여 44가 byte형 변수 c에 저장된다. 따라서 값손실을 방지하려면 큰 자료형을 사용해주어야 한다. ​

1
2
3
4
5
6
7
    public static void main(String args[]) { 
        int a = 1000000;    // 1,000,000  
        int b = 2000000;    // 2,000,000  
​
        long c = a * b;     // a * b = 2,000,000,000,000 ?
​
        System.out.println(c);

​ 위의 결과는 c의 자료형이 long타입이기 때문에 올바른 값이 출력될 것 같지만, 전혀 다른 값이 출력된다.
그 이유는 int 타입과 int 타입의 연산결과는 int 타입이기 때문에 long 타입으로 형변환 되어도 값은 변하지 않는다. 따라서 a 또는 b의 타입을 long으로 형변환 해주어야한다. ​

1
2
3
4
5
6
7
8
9
10
        int a = 1000000;
​
        int result1 = a * a / a;   // 1000000 * 1000000 / 1000000
        int result2 = a / a * a;   // 1000000 / 1000000 * 1000000
​
        System.out.printf("%d * %d / %d = %d\n", a, a, a, result1);
        System.out.printf("%d / %d * %d = %d\n", a, a, a, result2);
실행 결과 : 
1000000 * 1000000 / 1000000 = -727
1000000 / 1000000 * 1000000 = 1000000

​ 1,000,000 에 1,000,000을 먼저 곱한 후에 나눈 것과 나눈 후에 곱하는것의 연산결과가 다르다.
먼저 곱하는 경우에는 int의 범위를 넘어서기 때문에 오버플로우가 발생한다. ​

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
        char c = 'a';
        for(int i=0; i<26; i++) {          // {} 안에 문장을 26번 반복한다.
            System.out.print(c++); // 'a'부터 26개의 문자를 출력한다.
        }
​
        System.out.println(); // 줄바꿈을 한다.
​
        c = 'A';
        for(int i=0; i<26; i++) {          // {} 안에 문장을 26번 반복한다. 
            System.out.print(c++); // 'A'부터 26개의 문자를 출력한다.
        }
​
        System.out.println();
​
        c='0';
        for(int i=0; i<10; i++) {          // {} 안에 문장을 10번 반복한다.
            System.out.print(c++); //'0'부터 10개의 문자를 출력한다.
        }
        System.out.println();
실행결과:
abcdefghijklmnopqrstuvwxyz
ABCDEFGHIJKLMNOPQRSTUVWXYZ
0123456789

​ 위 사실을 이용하여 대문자를 소문자로 소문자를 대문자로 변환하는 프로그램을 작성할 수 있다. ​

1
2
3
4
5
6
            char lowerCase = 'a'; 
            char upperCase = (char)(lowerCase - 32); 
​
            System.out.println(upperCase); 
실행결과
A

​ 대문자 A가 소문자 a보다 코드값이 32가 적으므로 소문자 a의 코드값에서 32를 빼면된다. ​

1
2
3
4
5
6
7
    public static void main(String[] args) { 
        float pi = 3.141592f; 
        float shortPi = (int)(pi * 1000) / 1000f; 
​
        System.out.println(shortPi); 
실행결과:
3.141

​ (int)(pi * 1000) 이 수식에서 제일 먼저 수행되는 것은 괄호안의 수식이다. pi가 float이고 1000이 정수형이니까
연산의 결과는 float인 3141.592f rk ehlsek.
(int)(3142.592f) 그 다음으로 단항연산자인 형변환 연산자의 형변환이 수행된다. 3141.592f를 형변환 하면 3141을 얻는다
이떄 소수점 이하는 반올림 없이 사라진다.
3141 / 1000f; int가 float로 변환된 다음, 연산이 수행된다.
결과는 3.141f 가된다.
그렇다면 버림이 아닌 반올림이 되도록 하려면 어떻게 할까? ​

1
2
3
4
5
6
        double pi = 3.141592; 
        double shortPi = (int)(pi * 1000 + 0.5) / 1000.0;
​
        System.out.println(shortPi);
실행결과:
3.142

​ 이 예제는 소수점 넷째자리에서 반올림 하는 방법을 보여준다. 이전 예제와 다른점은 반올림을 위해 0.5를 더해준다는 것이다.
Math.round()을 사용하면 간단히 반올림 할 수 있다. 다음예제를 보자. ​

1
2
3
4
5
6
        double pi = 3.141592; 
        double shortPi = Math.round(pi * 1000) / 1000.0;
​
        System.out.println(shortPi);
실행결과:
3.142

​ Math.round(pi * 1000) / 1000.0;
-> Math.round(3.141592 * 1000) / 1000.0;
-> Math.round(3141.592) / 1000.0;
-> Math.round(3142) / 1000.0;
-> 3.142 ​

나머지 연산자 %

​ 나머지 연산자는 왼쪽의 피연산자를 오른쪽 피연산자로 나누고 난 나머지 값을 결과로 반환하는 연산자이다. 나누는 수로 0을 사용할 수 없다. 주로 나머지 연산자는 짝수, 홀수 또는 배수검사 등에 주로 사용된다. ​

1
2
3
4
5
6
7
8
        int x = 10;
        int y = 8;
​
        System.out.printf("%d을 %d로 나누면 , \n", x, y); 
        System.out.printf("몫 %d이고, 나머지는 %d입니다.\n", x / y, x % y); 
실행결과
10을 8로 나누면,
몫은 1이고, 나머지는 1입니다.

​ 나머지 연산자는 나누는 수로 음수도 음수도 허용한다. 그러나 부호는 무시되므로 결과는 음수의 절대값으로 나눈 나머지와 결과가 같다. ​

비교 연산자

​ 비교 연산자는 이항 연산자이므로 비교하는 피연산자의 타입이 다를 경우에는 범위가 큰 쪽으로 자동 형변환하여 타입을 일치시킨다.
대소비교 연산자 < > <= >=
값의 크기를 비교하는 연산자이다. 참이면 true를, 거짓이면 false를 결과로 반환한다. 기본형에는 boolean을 제외한 자료형에 사용가능하지만 참조형에는 사용할 수 없다. ​ 등가 비교 연산자 == !=
두 피연산자의 값이 같은지 또는 다른지를 빅쇼하는 연산자이다. 참조형 포함 모든 자료형에 사용할 수 있다. 기본형의 경우 변수에 저장되어 있는 값이 같은지 알수 있고, 참조형의 경우 객체의 주소값을 저장하기 때문에 두 개의 피연산자가 같은 객체를 가리키고 있는지를 알수있다. 이때 기본형과 참조형은 형변환이 불가함으로 둘을 비교할 수 없다.
*== : 두 값이 같으면 true 아니면 false ,!= : 두 값이 다르면 true, 아니면 false *

1
2
3
4
5
6
7
8
9
10
11
12
13
        System.out.printf("10 == 10.0f  \t %b\n", 10==10.0f);
        System.out.printf("'0'== 0      \t %b\n", '0'== 0);
        System.out.printf("'\\0'== 0    \t %b\n", '\0'== 0);
        System.out.printf("'A'== 65     \t %b\n", 'A'== 65);
        System.out.printf("'A' > 'B'    \t %b\n", 'A' > 'B');
        System.out.printf("'A'+1 != 'B' \t %b\n", 'A'+1 != 'B');
실행결과:
10 == 10.0f       true
'0'== 0           false
'\0'== 0         true
'A'== 65          true
'A' > 'B'         false
'A'+1 != 'B'      false

​ 비교 연산자도 이항 연산자 이므로 연산하기 전에 형변환을 통해 두 피연산자의 타입을 같게 맞춘 다음 다음 피연산자를 비교한다.
따라서 10 == 10.0f 에서 10.0f는 float 타입이므로, 10 을 float로 형변환 한다음 비교한다. 따라서 두 값이 10.0f로 같으므로 true를 얻게 된다. ​

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
​
        float  f  = 0.1f;
    double d  = 0.1;
    double d2 = (double)f;
​
        System.out.printf("10.0==10.0f  %b\n", 10.0==10.0f);
        System.out.printf("0.1==0.1f    %b\n",  0.1==0.1f);
        System.out.printf("f =%19.17f\n", f);
        System.out.printf("d =%19.17f\n", d);
        System.out.printf("d2=%19.17f\n", d2);
        System.out.printf("d==f   %b\n", d==f);
        System.out.printf("d==d2  %b\n", d==d2);
        System.out.printf("d2==f  %b\n", d2==f);
        System.out.printf("(float)d==f  %b\n", (float)d==f);
실행결과:
10.0==10.0f  true
0.1==0.1f    false
f =0.10000000149011612
d =0.10000000000000000
d2=0.10000000149011612
d==f   false
d==d2  false
d2==f  true
(float)d==f  true

# 태그입력