Java에서 정수는 내부적으로 비트 수준으로 어떻게 표현됩니까?
Java가 내부적으로 정수를 저장하는 방법을 이해하려고합니다. 나는 모든 자바 원시 정수가 서명된다는 것을 알고 있습니다 (짧은 것을 제외하고?). 즉, 해당 숫자에 대해 한 바이트에서 사용할 수있는 비트가 하나 적습니다.
내 질문은 모든 정수 (양수 및 음수)가 2의 보수로 저장됩니까 아니면 2의 보수에 음수 만 있습니까?
사양에 x bit two's complement number
. 그러나 나는 종종 혼란스러워합니다.
예를 들면 :
int x = 15; // Stored as binary as is? 00000000 00000000 00000000 00001111?
int y = -22; // Stored as two complemented value? 11111111 11111111 11111111 11101010
편집하다
확실하게, x = 15
In binary as is: `00000000 00000000 00000000 00001111'
Two's complement: `11111111 11111111 11111111 11110001`
따라서 답이 all
숫자 라면 2의 보수로 저장됩니다.
int x = 15; // 11111111 11111111 11111111 11110001
int y = -22 // 11111111 11111111 11111111 11101010
여기서 다시 혼동되는 것은 둘 다 음수라는 기호입니다. 내가 잘못 읽거나 오해하고있는 것일까 요?
편집 내 질문이 헷갈리는 지 잘 모르겠습니다. 질문을 분리해야합니다.
내 질문은 정확하게 : 양수 binary as is
는 저장되고 음수는 저장 two's complement
됩니까?
일부는 모두 2의 보수로 저장되고 하나의 대답은 음수 만 2의 보수로 저장된다고 말합니다.
Java 기본 데이터 유형을 요약하여 시작하겠습니다.
byte : Byte 데이터 유형은 부호있는 8 비트 2의 보수 정수 입니다.
Short : Short 데이터 유형은 16 비트 부호있는 2의 보수 정수 입니다.
int : Int 데이터 유형은 32 비트 부호있는 2의 보수 정수 입니다.
long : Long 데이터 유형은 64 비트 부호있는 2의 보수 정수 입니다.
float : Float 데이터 유형은 단 정밀도 32 비트 IEEE 754 부동 소수점 입니다.
double : double 데이터 유형은 배정 밀도 64 비트 IEEE 754 부동 소수점 입니다.
boolean : boolean 데이터 유형은 1 비트 정보를 나타냅니다 .
char : char 데이터 유형은 단일 16 비트 유니 코드 문자 입니다.
2의 보수
"좋은 예는 256 = 255 + 1이고 (255 − x)가 x의 1의 보수라는 점에 주목함으로써 2의 보수와의 관계가 실현된다는 위키 에서 나온 것입니다.
0000 0111 = 7 2의 보수는 1111 1001 = -7
작동 방식은 MSB (최상위 비트)가 음의 값을 수신하므로 위의 경우
-7 = 1001 = -8 + 0+ 0+ 1
양의 정수는 일반적으로 간단한 이진수로 저장됩니다 (1은 1, 10은 2, 11은 3 등).
음의 정수는 절대 값의 2의 보수로 저장됩니다. 이 표기법을 사용할 때 양수의 2의 보수는 음수입니다.
이 답변에 대해 몇 점을 받았으므로 더 많은 정보를 추가하기로 결정했습니다.
더 자세한 답변 :
무엇보다도 양수와 음수를 이진수로 표현하는 네 가지 주요 접근 방식이 있습니다.
- 부호있는 크기
- 하나의 보완
- 2의 보완
- 편견
1. 부호있는 크기
부호를 나타내는 데 가장 중요한 비트를 사용하고, 나머지 비트는 절대 값을 나타내는 데 사용됩니다. 여기서 0 나타내며 양수 및 1 나타내고 네가티브 번호 , 예를 들어 :
1011 = -3
0011 = +3
이 표현은 더 간단합니다. 그러나 십진수를 추가하는 것과 같은 방식으로 이진수를 추가 할 수 없으므로 하드웨어 수준에서 구현하기가 더 어렵습니다. 또한이 접근 방식은 0, 100 ... 0 및 0 .... 0을 나타내는 두 개의 이진 패턴을 사용합니다.
2. 하나의 보완
이 표현에서 우리는 주어진 숫자의 모든 비트를 반전하여 보완을 찾습니다. 예를 들면 :
010 = 2, so -2 = 101 (inverting all bits).
이 표현의 문제는 0 (00..0 및 11..1)을 나타내는 두 개의 비트 패턴이 여전히 존재한다는 것입니다.
3. 2의 보수
숫자의 음수를 찾기 위해이 표현에서는 모든 비트를 반전 한 다음 1 비트를 더합니다. 1 비트를 더하면 0을 나타내는 두 개의 비트 패턴이있는 문제가 해결됩니다.이 표현에서는 하나 (00 ... 0) 만 있습니다.
예를 들어, 4 비트를 사용하여 4 (십진수)의 이진 음수 표현을 찾고 싶습니다. 먼저 4를 바이너리로 변환합니다.
4 = 0100
그런 다음 모든 비트를 반전합니다.
0100 -> 1011
마지막으로 1 비트를 추가합니다.
1011 + 1 = 1100.
따라서 4 비트로 2의 보수 이진 표현을 사용하는 경우 1100은 십진수로 -4와 같습니다.
보완을 찾는 더 빠른 방법은 첫 번째 비트를 값 1로 고정하고 나머지 비트를 반전하는 것입니다. 위의 예에서는 다음과 같습니다.
0100 -> 1100
^^
||-(fixing this value)
|--(inverting this one)
2의 보수 표현은 0에 대한 표현이 하나 뿐인 것 외에도 십진수에서와 같은 방식으로 두 개의 이진 값을 더합니다. 부호가 다른 짝수입니다. 그럼에도 불구하고 오버플로 사례를 확인해야합니다.
4. 바이어스
이 표현은 부동 소수점에 대한 IEEE 754 표준의 지수를 나타내는 데 사용됩니다. 모든 비트가 0 인 이진 값이 가장 작은 값을 나타내는 이점이 있습니다. 그리고 모든 비트가 1 인 이진 값은 가장 큰 값을 나타냅니다. 이름에서 알 수 있듯이 값은 바이어스 (보통 2 ^ (n-1) 또는 2 ^ (n-1) -1)가있는 n 비트를 사용하여 이진수로 인코딩됩니다 (양수 또는 음수).
따라서 8 비트를 사용하는 경우 10 진수 값 1은 2 ^ (n-1) 바이어스를 사용하여 이진수로 표시됩니다.
+1 + bias = +1 + 2^(8-1) = 1 + 128 = 129
converting to binary
1000 0001
Java 정수는 32 비트이며 항상 서명됩니다. 즉, MSB (최상위 비트)가 부호 비트로 작동합니다. 로 표시되는 정수는 int
비트의 가중치 합계 일뿐입니다. 가중치는 다음과 같이 지정됩니다.
Bit# Weight
31 -2^31
30 2^30
29 2^29
... ...
2 2^2
1 2^1
0 2^0
MSB의 가중치는 음수 (실제로 가능한 가장 큰 음수)이므로이 비트가 켜져 있으면 정수 (가중 합계)가 음수가됩니다.
4 비트 숫자로 시뮬레이션 해 보겠습니다.
Binary Weighted sum Integer value
0000 0 + 0 + 0 + 0 0
0001 0 + 0 + 0 + 2^0 1
0010 0 + 0 + 2^1 + 0 2
0011 0 + 0 + 2^1 + 2^0 3
0100 0 + 2^2 + 0 + 0 4
0101 0 + 2^2 + 0 + 2^0 5
0110 0 + 2^2 + 2^1 + 0 6
0111 0 + 2^2 + 2^1 + 2^0 7 -> the most positive value
1000 -2^3 + 0 + 0 + 0 -8 -> the most negative value
1001 -2^3 + 0 + 0 + 2^0 -7
1010 -2^3 + 0 + 2^1 + 0 -6
1011 -2^3 + 0 + 2^1 + 2^0 -5
1100 -2^3 + 2^2 + 0 + 0 -4
1101 -2^3 + 2^2 + 0 + 2^0 -3
1110 -2^3 + 2^2 + 2^1 + 0 -2
1111 -2^3 + 2^2 + 2^1 + 2^0 -1
따라서 2의 보수는 음의 정수를 나타내는 배타적 인 체계가 아닙니다. 오히려 정수의 이진 표현이 항상 동일하다고 말할 수 있습니다. 단지 최상위 비트의 가중치를 부정합니다. 그리고 그 비트는 정수의 부호를 결정합니다.
In C, there is a keyword unsigned
(not available in java), which can be used for declaring unsigned int x;
. In the unsigned integers, the weight of the MSB is positive (2^31
) rather than being negative. In that case the range of an unsigned int
is 0
to 2^32 - 1
, while an int
has range -2^31
to 2^31 - 1
.
From another point of view, if you consider the two's complement of x
as ~x + 1
(NOT x plus one), here's the explanation:
For any x
, ~x
is just the bitwise inverse of x
, so wherever x
has a 1
-bit, ~x
will have a 0
-bit there (and vice versa). So, if you add these up, there will be no carry in the addition and the sum will be just an integer every bit of which is 1
.
For 32-bit integers:
x + ~x = 1111 1111 1111 1111 1111 1111 1111 1111
x + ~x + 1 = 1111 1111 1111 1111 1111 1111 1111 1111 + 1
= 1 0000 0000 0000 0000 0000 0000 0000 0000
The leftmost 1
-bit will simply be discarded, because it doesn't fit in 32-bits (integer overflow). So,
x + ~x + 1 = 0
-x = ~x + 1
So you can see that the negative x
can be represented by ~x + 1
, which we call the two's complement of x
.
I have ran the following program to know it
public class Negative {
public static void main(String[] args) {
int i =10;
int j = -10;
System.out.println(Integer.toBinaryString(i));
System.out.println(Integer.toBinaryString(j));
}
}
Output is
1010
11111111111111111111111111110110
From the output it seems that it has been using two's complement.
Oracle provides some documentation regarding Java Datatypes that you may find interesting. Specifically:
int: The int data type is a 32-bit signed two's complement integer. It has a minimum value of -2,147,483,648 and a maximum value of 2,147,483,647 (inclusive).
Btw, short is also stored as two's complement.
According to this document, all integers are signed and stored in two's complement format for java. Not certain of its reliability..
The most significant bit (32nd) indicates that the number is positive or negative. If it is 0, it means the number is positive and it is stored in its actual binary representation. but if it is 1, it means the number is negative and is stored in its two's complement representation. So when we give weight -2^32 to the 32nd bit while restoring the integer value from its binary representation, We get the actual answer.
Thank you, dreamcrash for the answer https://stackoverflow.com/a/13422442/1065835; on the wiki page they give an example which helped me understand how to find out the binary representation of the negative counterpart of a positive number.
For example, using 1 byte (= 2 nibbles = 8 bits), the decimal number 5 is represented by
0000 01012 The most significant bit is 0, so the pattern represents a non-negative value. To convert to −5 in two's-complement notation, the bits are inverted; 0 becomes 1, and 1 becomes 0:
1111 1010 At this point, the numeral is the ones' complement of the decimal value −5. To obtain the two's complement, 1 is added to the result, giving:
1111 1011 The result is a signed binary number representing the decimal value −5 in two's-complement form. The most significant bit is 1, so the value represented is negative.
Positive numbers are stored/retrived as it is.
e.g) For +ve number 10; byte representation will be like 0-000 0010
(0 - MSB will represent that it is +ve).
So while retrieving based on MSB; it says it is +ve,
so the value will be taken as it is.
But negative numbers will be stored after 2's complement (other than MSB bit), and MSB bit will be set to 1.
e.g) when storing -10 then
0-000 0010 -> (1's complement) -> 0-111 1101
-> (2's complement) 0-111 1101 + 1 -> 0-111 1110
Now MSB will be set to one, since it is negative no -> 1-111 1110
when retrieving, it found that MSB is set to 1. So it is negative no. And 2's complement will be performed other than MSB.
1-111 1110 --> 1-000 0001 + 1 --> 1-000 0010
Since MSB representing this is negative 10 --> hence -10 will be retrived.
Casting
Also note that when you are casting int/short to byte, only last byte will be considered along with last byte MSB,
Take example "-130" short, it might be stored like below
(MSB)1-(2's complement of)130(1000 0010) --> 1-111 1111 0111 1110
Now byte casting took last byte which is 0111 1110. (0-MSB) Since MSB says it is +ve value, so it will be taken as it is. Which is 126. (+ve).
Take another example "130" short, it might be stored like below
0-000 000 1000 0010 (MSB = 0)
Now byte casting took last byte which is 1000 0010 . (1=MSB) Since MSB says it is -ve value, 2's complement will be performed and negative number will be returned. So in this case -126 will be returned.
1-000 0010 -> (1's complement) -> 1-111 1101
-> (2's complement) 1-111 1101 + 1 -> 1-111 1110 -> (-)111 1110
= -126
Diff between (int)(char)(byte) -1 AND (int)(short)(byte) -1
(byte)-1 -> 0-000 0001 (2's Comp) -> 0-111 1111 (add sign) -> 1-111 1111
(char)(byte)-1 -> 1-111 1111 1111 1111 (sign bit is carry forwarded on left)
similarly
(short)(byte)-1-> 1-111 1111 1111 1111 (sign bit is carry forwarded on left)
But
(int)(char)(byte)-1 -> 0-0000000 00000000 11111111 11111111 = 65535
since char is unsigned; MSB won't be carry forwarded.
AND
(int)(Short)(byte)-1 -> 1-1111111 11111111 11111111 11111111 = -1
since short is signed; MSB is be carry forwarded.
References
Why is two's complement used to represent negative numbers?
positive numbers are stored directly as binary. 2's compliment is required for negative numbers.
for example:
15 : 00000000 00000000 00000000 00001111
-15: 11111111 11111111 11111111 11110001
here is the difference in signed bit.
For positive integer 2'complement value is same with MSB bit 0 (like +14 2'complement is 01110)
.
For only negative integer only we are calculating 2'complement value (-14= 10001+1 = 10010)
.
So final answer is both the values(+ve and -ve)
are stored in 2'complement form only.
'Program Tip' 카테고리의 다른 글
LINQ Lambda 식에서 GroupBy, Count 및 Sum 사용 (0) | 2020.10.18 |
---|---|
sqlite에서 int를 실수로 변환 (0) | 2020.10.18 |
Intellij (Android Studio) 멤버 변수 접두사 (0) | 2020.10.18 |
앱이 시작될 때 Firebase 상태 업데이트 로깅을 중지하는 방법 (0) | 2020.10.18 |
연결 해제 이벤트를 처리하는 Socket.IO (0) | 2020.10.18 |