java 정수 리터럴

wooni·2023년 6월 20일

Java

목록 보기
4/6

리터럴 문법을 사용하여 데이터 출력하기

정수리터럴

  • 10진수 리터럴

    • 코드에서 일반적으로 정수값을 표현할때 사용
    • 아래의 수는 모두 숫자 100을 기준으로 변환한다.
    • ex) 100
  • 8진수 리터럴

    • 코드작성할때 잘 사용하지 않음
    • 0으로 시작함
    • ex) 0144
  • 2진수 리터럴

    • 메모리 상태를 직설적으로 보여주고 싶을때 사용
    • 0b or 0B로 시작한다.
      • 0b1100100 or 0B1100100
    • 숫자앞에 0이 있어도 된다.
      • 0b01100100 or 0B1100100
  • 16진수 리터럴

    • 2진수를 간결하게 표현하기 위해 사용
    • 0x 또는 0X로 시작한다.
      • 0x64 or 0X64
    • 숫자앞에 0이 있어도 된다.
      • 0x064 or 0X064
  • 정수를 읽기 쉽도록 밑줄(underscore; _)을 숫자 사이에 삽입할 수 있다.

public class example { 
  public static void main(String[] args) {
     //10진수 문자 삽입
     System.out.println(1278_3406);
     System.out.println(12_783_406);
     //8진수 문자 삽입
     System.out.println(07_7);
     //2진수 문자삽입
     System.out.println(0b110_0100);
     System.out.println(0b1_1_0_0_1_0_0);
     //16진수
     System.out.println(0xff_aa);


  }
}
  • 숫자 맨 앞 또는 맨 뒤에 삽입할 수없다.

정수 리터럴 - 메모리 크기에 따른 표기법

  • 정수를 저장할 메모리의 크기를 지정할 수 있다.

  • 메모리의 크기에 따라 표현할 수 있는 정수의 크기가 다르다.

  • 4바이트 정수

    • 접미사를 붙이지 않고 그냥 숫자를 표현하면 4바이트 크기의 메모리에 저장되는 정수를 표현
    • -2147483648~2147483647 4바이트 얌수 음수 최대 최소값
    • 메모리 크기를 초기화 하면 컴파일 오류가 발생
  • 8바이트 정수

    • 4바이트 메모리를 벗어나는 정수 값을 표현할때 사용한다.
    • 숫자 뒤에 L 또는 l을 붙인다 (long)
    • 보통 대문자를 붙인다. 소문자는 혼돈의 여지가 있음
  • 정리

    • 4바이트 정수 리터럴 = 100
    • 8바이트 정수 리터렬 = 100L

정수 리터럴 - 메모리에 저장하는 방법

  • 컴퓨터에서는 값을 저장할 때 전기 신호(예: RAM) 또는 자기 신호(예: HDD)로 저장한다.
  • 값은 비트로 표현되고, 각 비트는 전기가 있거나 없는 두 상태로 표현한다.
  • 비트의 두 가지 상태를 표현할 때 2진수의 1과 0을 사용한다.
  • 따라서 값을 메모리에 저장하려면 2진수로 표현할 수 있어야 한다.

정수를 2진수로 표현하는 방법

  • 부호-크기/절대값(Sign-Magnitude)
    • 부동 소수점에서 가수부(significand or mantissa)를 저장할 때 사용한다.
    • 맨 왼쪽 1비트를 부호 비트로 사용한다. 양수는 0, 음수는 1 이다.
    • 나머지 비트는 절대값(magnitude)으로 저장한다.
    • 8비트 = 1비트(부호) + 7비트(절대값)
      • 예) +24 => |+24| = 24 ---> 0001 1000
      • 예) -24 => |-24| = 24 ---> 1001 1000
    • 수의 범위(8비트 기준): -127 ~ + 127
    0111 1111 (127)
    0111 1110 (126)
    0111 1101 (125)
      ...
    0000 0001 (1)
    0000 0000 (+0)
    1000 0000 (-0)
    1000 0001 (-1)
      ...
    1111 1101 (-125)
    1111 1110 (-126)
    1111 1111 (-127)
  • 단점
    • 두 개의 0(+0, -0)이 존재한다.
    • 양수와 음수를 더했을 때 옳지 않은 값이 나온다.
    • 예) 4비트일 경우, 1 + -1 = ?
      • 0001(+1) + 1001(-1) = 1010 (-2) <-- 계산 결과가 옳지 않다.
  • 빼기를 처리하는 컴퓨팅 회로를 별도로 설계해야 하므로 하드웨어가 복잡해진다.
  • 장점
    • 사람이 이해하기 쉽다!

부동소수점 리터럴

  • 실수 값을 부동소수점 방식으로 저장하려면 1과 0으로 변환해야 한다.
  • 자바는 부동소수점을 저장할 때 전기전자기술자협회(IEEE)에서 개발한 IEEE 754 명세에 따라 2진수로 변환한다.

Exponential 기호 사용하기

  • e 기호를 사용하면 소수점의 위치를 조정할 수 있다.
  • 소수점의 위치를 움직인다고 해서 "부동소수점(floating point)"이라 부른다.
  • 표기법
    • 숫자e지수(10e5) 또는 숫자E지수(12E22)
System.out.println(0.0314e2); // 0.0314 * 10의2승 = 3.14
System.out.println(0.314e1); // 0.314 * 10의1승 = 3.14
System.out.println(31.4e-1); // 31.4 * 10의-1승 = 3.14
System.out.println(314e-2); // 314 * 10의-2승 = 3.14

부동소수점 리터럴 - 메모리 크기에 따른 표기법

  • float : 4바이트 크기의 부동소수점
    • 숫자 맨 뒤에 f 또는 F를 붙인다
  • double : 8바이트 크기의 부동소수점
    • 숫자 맨 뒤에 d 또는 D를 붙인다.
    • 생략해도 된다.

부동소수점 리터럴 - 유효자릿수

  • 정수처럼 메모리 크기(4바이트 또는 8바이트)에 따라 표현할 수 있는 부동소수점의 범위가 다르다.

  • 단 IEEE 754 명세에 따라 2진수로 변환되기 때문에
    정확하게 '소수점 이상 얼마까지 소수점 이하 얼마까지' 식으로 정의할 수 없다.

  • 대신 '유효자릿수'라는 방식으로 대략적으로 값의 범위를 표현한다.

  • 부동소수점을 저장할 때 정확하게 저장되지 않는 예

    • System.out.println(7 * 0.1); //결과: 0.7000000000000001
    • 이유
      • IEEE-754 규격에 따라 부동소수점을 2진수로 바꾸다보면 정확하게 2진수로 딱 떨어지지 않는 경우가 있다.
      • CPU, OS, 컴파일러, JVM의 문제가 아니다.
      • IEEE-754의 방법에 내재되어 있는 문제다.
    • 해결책
      • 시스템에서 필요한 만큼 소수점 이하 자리수를 적절히 짤라 사용하면된다.

결론!

  • 32비트(float) 메모리에 부동소수점을 저장할 때는 유효자릿수 7자리까지는 거의 가능하다.
  • 64비트(double) 메모리에 부동소수점을 저장할 때는 유효자릿수 15자리까지는 거의 가능하다.
  • 그래서 32비트 float을 단정도(single-precision)라 부르고,
    64비트는 두 배 정밀하게 값을 저장한다고 해서 배정도(double-precision)이라 부른다.

메모리 비트와 2진수

  • 메모리의 각 비트는 전기의 on/off 상태를 나타낸다.
  • 비트의 on 상태를 1, off 상태를 0으로 표현한다.
  • 그래서 메모리의 비트 상태를 표현할 때는 2진수로 나타낸다.

메모리에 값을 저장하기

  • 메모리는 비트로 되어 있기 때문에 어떤 유형의 값이든 2진수로 변환할 수 있다면 메모리에 저장할 수 있다.
  • 예) 빛을 저장하기
    • 카메라 렌즈로 들어온 빛을 메모리에 저장하려면 2진수로 변환해야 한다.
    • 이런 역할을 하는 것이 이미지 센서이다.
  • 예) 소리를 저장하기
    • 소리도 마찬가지이다. 메모리에 저장하려면 2진수로 변환해야 한다.
    • 마이크로 들어온 음파를 ADC를 통해 디지털 신호, 즉 2진수로 변환한다.

부동소수점이 메모리에 저장되는 원리

  • 부동소수점도 메모리에 저장하려면 2진수로 표현할 수 있어야 한다.
  • 부동소수점을 2진수로 변환하는 것을 "정규화(nomalized)"라 부른다.
  • 이런 정규화 규칙을 정의한 문서가 "IEEE-754"이다.
  • 부동소수점을 2진수로 바꿀 때, 가수부와 지수부로 분리하여 변환한다.
  • 가수부는 'Sign-Magnitude 방식'으로 변환하고, 지수부는 'Excess-K 방식'으로 변환한다.

IEEE-754

  • 부동소수점을 32비트와 64비트로 표현하는 방법에 대해 정의하고 있다.
  • 32비트로 표현하는 방법을 "single-precision(정밀도 1; 단정도)"이라 한다.
  • 64비트로 표현하는 방법은 32비트에 대비해 두 배 가량 더 정밀하게 표현할 수 있다고 해서 "double-precision(정밀도가 두 배; 배정도)"이라 한다.

부동소수점을 2진수로 표현하는 방법

  • 자바에서 부동소수점의 정규화는 "IEEE 754-1985" 명세에 따른다.
  • 메모리 크기와 비트의 구성
=> 32비트 float 타입(32-bit single-precision; 단정도)
  [부호비트(1)][지수부(8)][가수부(23)]
=> 64비트 double 타입(64-bit double-precision; 배정도)
  [부호비트(1)][지수부(11)][가수부(52)]
  • 부호비트(sign bit)
    음수는 1, 양수는 0.
  • 지수(exponent)
    127 bias를 사용한다. 즉 2의 지수 값에 127을 더한 결과 값을 사용한다.
  • 가수(fraction/mantissa)
    sign-magnitude 방식으로 저장한다.
    1.xxxx 값에서 소수점 왼쪽에 있는 1을 제외한 나머지 수를 사용한다.
    가수부에 남는 비트가 있다면 0으로 채운다.

실수 값을 정규화하는 방법 = 실수 값을 32비트 2진수로 만드는 방법

1) 소수점 앞의 정수 값을 2진수로 변환한다.
  12(10진수)
  = 1100(2진수)  
2) 소수점 뒤의 값을 2진수로 변환한다.
- 변환 규칙
- 소수점을 2로 곱하여 나온 결과에서 정수 부분만을 차례대로 표기한다.
- 소수 부분이 0이거나 반복되면 계산을 멈춘다.
- 예: 0.375(10진수)
  0.375 * 2 = 0.75  --> 0
  0.75 * 2  = 1.5   --> 1
  0.5 * 2   = 1.0   --> 1
  => 0.011(2진수)

3) 2진수 바꾼 최종 결과
  12.375(10진수)
  = 12(10진수) + 0.375(10진수)
  = 1100(2진수) + 0.011(2진수)
  = 1100.011(2진수)
  = 1*2^3 + 1*2^2 + 0*2^1 + 0*2^0 + 0*2^-1 + 1*2^-2 + 1*2^-3
  = 1*8 + 1*4 + 0*2 + 0*1 + 0*0.5 + 1*0.25 + 1*0.125

4) 정규화 
- 소수점의 위치를 조정하여 가수부와 지수부를 분리한다.
- IEEE 754 명세는 다음과 같은 형식으로 가수부와 지수부를 나눈다.
  1.x1x2x3x4...x23(2진수) * 2^e
  => 소수점 왼쪽에 1만 남도록 소수점을 이동한다.
  => 소수점 왼쪽은 무조건 1이기 때문에 저장하지 않고 버린다.
  => 따라서 소수점 오른쪽 수만 가수부에 놓는다.
     즉 x1, x2 등은 가수부 1번 비트부터 23번 비트까지를 의미한다.
  => 23번 비트까지 채우지 못하면 나머지 비트는 0으로 채운다.
- 예)
  1100.011(2진수)
  = 1.100011(2진수) * 2^3
  가수부 => 100011(2진수)
  지수부 => 3 + 127(bias) = 130(10진수) = 10000010(2진수)

5) 32비트로 표현하기
  [0][10000010][10001100000000000000000]
  => 0100_0001_0100_0110_0000_0000_0000_0000
  => 0x41460000

주의!
- 유효 자릿수의 부동소수점이라도 정규화할 때 2진수로 딱 떨어지지 않은 경우가 있다.
- 예) 2.127
2 => 0010
0.127 => 
0.127 * 2 = 0.254 --> 0
0.254 * 2 = 0.508 --> 0
0.508 * 2 = 1.016 --> 1
0.016 * 2 = 0.032 --> 0
0.032 * 2 = 0.064 --> 0
0.064 * 2 = 0.128 --> 0
0.128 * 2 = 0.256 --> 0
0.256 * 2 = 0.512 --> 0
0.512 * 2 = 1.024 --> 1
0.024 * 2 = 0.048 --> 0
....
이처럼 2진수로 완벽히 표현할 수 없는 수가 있다.
0.00000....1 의 오차가 있다.
그래서 부동소수점은 정수와 다르게 정확하게 2진수로 변환할 수 없는 경우가 있다.
즉 메모리에 정확하게 저장되지 않을 수 있다.

profile
Backend

0개의 댓글