Skip to content

2의 보수 계산기 — 부호 있는 정수 인코딩 변환

부호 있는 정수를 넣으면 부호-절대값, 1의 보수, 2의 보수, 오프셋 바이너리를 4~64비트로 한 번에 계산합니다. 비트열이나 16진수로 역방향 조회도 지원합니다.

트래킹 없음 브라우저 실행 무료
모든 계산은 브라우저 안에서 이루어집니다. 입력한 내용은 업로드되지 않습니다.
비트 폭

10진수에서 기계 표현으로

부호 있는 정수를 입력하세요. 네 가지 표현이 한꺼번에 계산되므로, 내 시스템이 어느 것을 쓰는지 미리 알고 있을 필요가 없습니다.

예시로 확인
인코딩 비트열 16진수
부호-절대값 1000 0101 85
1의 보수 1111 1010 FA
2의 보수 1111 1011 FB
오프셋 바이너리 0111 1011 7B

비트 패턴에서 값으로

메모리 덤프나 레지스터에서 바이트 하나를 찾았는데 어떻게 읽어야 할지 모르겠다면, 붙여 넣어 보세요. 각 해석에서 그것이 무엇을 뜻하는지 한 번에 나열됩니다. 어느 쪽이 맞는지는 그것을 내놓은 시스템에 달려 있으므로 전부 보여 줍니다.

읽는 방식
부호 없음 251
부호-절대값 -123
1의 보수 -4
2의 보수 -5
오프셋 바이너리 123
8비트 대조표

위 도구가 쓰는 것과 같은 엔진으로 계산하므로 두 값이 어긋날 수 없습니다.

10진수 부호-절대값 1의 보수 2의 보수 오프셋 바이너리 16진수
127 0111 1111 0111 1111 0111 1111 1111 1111 7F
100 0110 0100 0110 0100 0110 0100 1110 0100 64
10 0000 1010 0000 1010 0000 1010 1000 1010 0A
5 0000 0101 0000 0101 0000 0101 1000 0101 05
1 0000 0001 0000 0001 0000 0001 1000 0001 01
0 0000 0000 0000 0000 0000 0000 1000 0000 00
-1 1000 0001 1111 1110 1111 1111 0111 1111 FF
-5 1000 0101 1111 1010 1111 1011 0111 1011 FB
-10 1000 1010 1111 0101 1111 0110 0111 0110 F6
-100 1110 0100 1001 1011 1001 1100 0001 1100 9C
-127 1111 1111 1000 0000 1000 0001 0000 0001 81
-128 1000 0000 0000 0000 80
비트 폭별 값 범위
비트 폭 2의 보수 / 오프셋 바이너리 부호-절대값 / 1의 보수
4 -8 … 7 -7 … 7
8 -128 … 127 -127 … 127
16 -32768 … 32767 -32767 … 32767
32 -2147483648 … 2147483647 -2147483647 … 2147483647
64 -9223372036854775808 … 9223372036854775807 -9223372036854775807 … 9223372036854775807
다섯 가지 비트 폭 전부에 대해 각 인코딩을 테스트 스위트에서 단언합니다. 4비트 전 구간, 두 가지 0 패턴, 각 폭의 최솟값이 포함됩니다. 64비트 결과는 JavaScript 자체의 BigInt.asIntN과 BigInt.asUintN으로 교차 검증했습니다. — Go Tools 팀 · Sep 9, 2026

Go Tools 엔지니어링 팀이 구축하고 검증했습니다.

빠른 답변

8비트 2의 보수로 −5는?

11111011 11111011, 16진수로는 0xFB입니다.

부호 있는 바이트의 범위는?

-128 … 127 2의 보수에서는 −128부터 127까지, 부호-절대값과 1의 보수에서는 −127부터 127까지입니다.

2의 보수 패턴을 다시 수로 되돌리려면?

부호 없는 값 − 2^n 최상위 비트가 0이면 부호 없는 수로 읽고, 1이면 부호 없는 읽기에서 2^n을 뺍니다.

0xFF는 −1인가요, 255인가요?

−1 또는 255 부호 있는 바이트로는 −1, 부호 없는 바이트로는 255입니다. 비트만으로는 정해지지 않습니다.

2의 보수란?

2의 보수가 답하는 것은 수학 문제가 아니라 하드웨어 문제입니다. 이미 만들어 둔 가산기를 그대로 계속 쓰려면 음수를 어떻게 저장해야 하는가. 답은 −x2^n − x의 패턴으로 나타내는 것이었습니다. 그러면 덧셈이 2^n을 법으로 자연스럽게 돌아 나가 부호에 대한 특수 처리 없이 옳은 답에 내려앉고, 뺄셈을 위한 별도 회로가 필요 없어집니다.

여기서 두 가지 결과가 따라 나오며 둘 다 실제 버그로 나타납니다. 첫째, 범위가 비대칭입니다. 8비트가 덮는 구간은 −128부터 127까지이지 −128부터 128까지가 아닙니다. 패턴 총량을 나눠 가져야 하는데 양쪽을 맞춰 줄 음의 0이 없기 때문입니다. 둘째, 부호는 떼어 낼 수 있는 깃발이 아닙니다. 11111011의 최상위 비트는 1이지만 값은 −123이 아니라 −5입니다. 음수를 읽는다는 것은 비트 하나를 보는 일이 아니라 워드 전체를 해석하는 일입니다.

부호-절대값과 1의 보수는 경쟁에서 밀려난 두 설계입니다. 그래도 알아 둘 값어치가 있는 이유는 IEEE 754 부동소수점이 부호-절대값 배치를 물려받았기 때문이고, 셋을 나란히 놓고 비교해 봐야 비로소 2의 보수가 임의의 선택이 아니라 필연으로 보이기 때문입니다.

// -5 as an 8-bit byte, three ways to arrive at the same pattern
0b00000101        // 5
~0b00000101       // 11111010  ones' complement of 5
~0b00000101 + 1   // 11111011  two's complement = -5

// In JavaScript the width matters: bitwise operators are 32-bit,
// so anything wider has to go through BigInt.
BigInt.asIntN(8, 0xFBn)                 // -5n
BigInt.asUintN(8, -5n)                  // 251n
BigInt.asIntN(64, 0xFFFFFFFFFFFFFFFBn)  // -5n

// C23 made two's complement mandatory for signed integers.
// Before that, the other two encodings were legal but unused.

이 계산기가 하는 일

네 가지 인코딩을 한 번에

부호-절대값, 1의 보수, 2의 보수, 오프셋 바이너리를 함께 계산합니다. 오프셋 바이너리는 대부분의 계산기가 빼먹는 항목이지만, ADC 데이터시트가 지금도 계속 쓰고 있는 것이 바로 이것입니다.

비트 패턴에서 역방향 조회

손에 있는 실제 비트열이나 16진수를 붙여 넣으면 부호 없는 읽기까지 다섯 가지가 모두 나옵니다. 덤프와 장치가 보고하는 수가 어긋날 때 필요한 것이 이 방향입니다.

64비트에서도 정확

모든 값을 BigInt로 다루므로 0xFFFFFFFFFFFFFF9C는 32비트 절단의 산물이 아니라 −100으로 풀립니다.

표현할 수 없으면 없다고 적기

비트 폭 8에서 −128에는 부호-절대값도 1의 보수 형태도 없습니다. 표는 그렇게 적습니다. 그 수를 뜻하지 않는 패턴을 찍어 주지 않습니다.

음의 0을 눈에 보이게

0을 입력하면 부호-절대값과 1의 보수에서 0이 갖는 두 번째 비트 패턴이 나타납니다. 2의 보수가 이긴 이유를 보여 주는 가장 명료한 한 가지입니다.

JavaScript 없이도 읽히는 참조표

8비트 대조표와 비트 폭별 범위는 위쪽 입력란을 움직이는 것과 같은 엔진으로 빌드 시점에 그려집니다. 그래서 둘이 어긋날 수 없습니다.

다른 확인 방법과의 비교

언어가 제공하는 변환 함수

런타임 API

BigInt.asIntN, Python의 int.from_bytes(..., signed=True), C의 고정 폭 타입은 지금 쓰고 있는 코드에 대해 권위 있는 답을 줍니다. 코드 안에서는 그것들을 쓰고, 값은 눈앞에 있는데 인터프리터를 열어 두지 않았을 때 이 페이지를 쓰세요.

디버거의 메모리 뷰

IDE 기능

프로그램이 선언한 타입으로 값을 보여 주는데, 그것이야말로 비트 패턴에 빠져 있는 바로 그 정보입니다. 다만 선언된 타입 없이 회선을 타고 도착한 바이트에는 도움이 되지 않습니다. 이 페이지가 맡는 경우가 바로 그것입니다.

진법 변환기

이 사이트

진법 사이를 변환하지만 음수가 아닌 값만 다룹니다. 저쪽에서는 음수를 명시적으로 거부하는데, 진법 자체는 부호를 어떻게 저장할지에 대해 아무 견해도 갖지 않기 때문입니다. 부호 있는 표현은 이 페이지의 몫이고, 절댓값의 진법 변환은 저쪽의 몫입니다.

IEEE 754 변환기

이 사이트

부동소수점 쪽의 짝이 되는 도구입니다. 2의 보수가 아니라 부호-절대값 배치를 유지하고 지수부는 2^(e−1)−1만큼 치우쳐 있으므로, 두 페이지는 같은 메모리 한 워드를 두고 서로 다른 질문에 답합니다.

계산 예시

−5를 1바이트에 담기

-5, 비트 폭 8
부호-절대값     1000 0101
1의 보수        1111 1010
2의 보수        1111 1011  (0xFB)
오프셋 바이너리  0111 1011

세 인코딩은 부호 비트에서만 일치하고 나머지는 모두 어긋납니다. C의 int8_t가 실제로 담고 있는 것은 2의 보수 행뿐입니다.

같은 바이트 0xFB를 읽는 다섯 가지 방법

0xFB, 비트 폭 8
부호 없음       251
부호-절대값     -123
1의 보수        -4
2의 보수        -5
오프셋 바이너리  123

−128에는 부호-절대값 표현이 없다

-128, 비트 폭 8
부호-절대값     이 폭에서는 표현 불가
1의 보수        이 폭에서는 표현 불가
2의 보수        1000 0000  (0x80)
오프셋 바이너리  0000 0000

부호-절대값과 1의 보수는 각각 비트 패턴 하나를 음의 0에 써 버리므로 범위가 −127에서 127까지이고 −128에는 닿지 못합니다. 여기서 바이트를 찍어 주는 도구는 틀린 것입니다.

64비트 레지스터 값

0xFFFFFFFFFFFFFF9C, 비트 폭 64
2의 보수   -100
부호 없음  18446744073709551516

32비트를 넘어가면 BigInt로 처리할 수밖에 없습니다. JavaScript의 |, <<, >>>는 조용히 32비트로 잘라 냅니다. 일부 온라인 계산기가 여기서 오류 대신 틀린 답을 내놓는 이유입니다.

2의 보수 계산기 사용법

  1. 1

    비트 폭 고르기

    4, 8, 16, 32, 64 중 하나. 이것은 표시 취향이 아닙니다. 같은 비트라도 폭이 다르면 다른 수를 뜻하므로, 잘못 고르면 답 자체가 달라집니다.

  2. 2

    부호 있는 10진수 입력하기

    마이너스 부호까지 포함해 정수를 입력하세요. 네 가지 인코딩이 입력에 맞춰 갱신되고, 각각의 16진수 표기도 함께 나옵니다.

  3. 3

    또는 비트에서 거꾸로 되짚기

    2진 문자열이나 0x로 시작하는 값을 역방향 조회 칸에 붙여 넣으면, 그 패턴이 각 해석에서 어떤 수인지 부호 없는 읽기까지 포함해 확인할 수 있습니다.

  4. 4

    안내가 뜨면 읽기

    사람들이 걸려 넘어지는 두 지점을 페이지가 표시합니다. 최솟값에는 부호-절대값과 1의 보수 형태가 없다는 것, 그리고 그 두 인코딩에서는 0에 두 번째 비트 패턴이 있다는 것입니다.

틀린 답이 나오는 실수

+1을 잊는 것

비트를 뒤집기만 하면 1의 보수입니다. 거기서 멈추면 2의 보수와 1만큼 어긋나는데, 결과가 여전히 그럴듯한 음수로 보이기 때문에 놓치기 쉽습니다.

✗ 오류
5   = 00000101
~5  = 11111010   <- ones' complement, not -5
✓ 정상
5        = 00000101
~5       = 11111010
~5 + 1   = 11111011   <- -5 in two's complement

64비트 값에 32비트 비트 연산자를 쓰는 것

JavaScript는 비트 연산자의 피연산자를 32비트로 잘라 냅니다. 위쪽 절반이 오류 없이 사라지므로 결과는 없는 게 아니라 틀린 것이 됩니다.

✗ 오류
0xFFFFFFFFFFFFFFFB        // 18446744073709552000  -- the literal is already rounded
~0xFFFFFFFFFFFFFFFB + 1   // 0  -- silently wrong, expected -5
✓ 정상
BigInt.asIntN(64, 0xFFFFFFFFFFFFFFFBn)   // -5n

음수를 0으로 확장하는 것

0을 채워 폭을 넓히는 방식은 수가 양수일 때만 값을 지켜 줍니다. 음수라면 늘어난 비트 전체에 부호 비트를 복제해야 합니다.

✗ 오류
int8  0xFB  (-5)
int16 0x00FB  (251)   <- zero-extended
✓ 정상
int8  0xFB  (-5)
int16 0xFFFB  (-5)    <- sign-extended

최솟값에 부호-절대값 형태를 부여하는 것

8비트에서 −128에는 부호-절대값 표현도 1의 보수 표현도 없습니다. 두 인코딩 모두 음의 0에 패턴 하나를 쓰기 때문입니다. 여기에 10000000을 찍는 것은 2의 보수의 답을, 그 수를 표현할 수 없는 인코딩과 혼동하는 일입니다.

✗ 오류
-128 sign-magnitude: 10000000   <- that pattern means -0
✓ 정상
-128 sign-magnitude: no representation at width 8
-128 two's complement: 10000000

실제로 필요해지는 순간

센서 레지스터 읽기
온도 레지스터가 0xFF9C를 돌려줍니다. 부호가 없다고 보면 65436인데, 이건 온도가 아닙니다. 비트 폭 16에서 2의 보수 행은 −100을 가리키고, 0.1 °C 스케일 계수를 곱하면 센서가 말하는 값은 −10.0 °C입니다.
타입 정보가 없는 프로토콜 디버깅
Modbus, CAN을 비롯한 대부분의 바이너리 텔레메트리는 부호 정보가 붙지 않은 원시 워드를 실어 나릅니다. 클라이언트와 장치가 값을 두고 어긋날 때 같은 워드의 두 읽기를 나란히 확인하면 어느 쪽 가정이 틀렸는지 대개 드러납니다.
컴퓨터 구조 과제
부호-절대값, 1의 보수, 2의 보수, 오프셋 바이너리는 입문 강의의 표준 네 가지입니다. 같은 비트 폭에서 나란히 놓으면 차이는 외우는 것이 아니라 보이는 것이 됩니다.
정수 오버플로 추적
카운터가 2147483647에서 −2147483648로 튀었을 때 둘을 32비트 패턴으로 보면 올림이 부호 비트로 들어갔다는 사실이 보입니다. 값이 헛것이 된 게 아니라 인코딩이 정한 규칙대로 정확히 감긴 것입니다.
직렬화 코드 작성
직접 쓴 인코더를 믿기 전에 각 비트 폭마다 음수 하나씩을 이 페이지와 대조해 보세요. 부호 처리는 틀리게 쓰기 쉽고, 게다가 진짜 음수가 도착하기 전까지는 출력이 구조적으로 멀쩡해 보입니다.

네 가지 인코딩의 구성 방식

부호-절대값
최상위 비트가 부호이고 나머지 n−1비트가 절댓값을 평범한 부호 없는 수로 나타냅니다. 범위는 −(2^(n−1)−1)부터 2^(n−1)−1까지로 대칭이며 0이 둘입니다. IEEE 754 부동소수점이 쓰는 배치가 바로 이것입니다.
1의 보수
음수 값은 절댓값의 비트 반전, 즉 2^n − 1 − x입니다. 범위도 두 개의 0도 부호-절대값과 같습니다. 덧셈에는 끝자리 되돌림(end-around carry)이 필요한데, 바로 그 번거로움을 2의 보수가 없앴습니다. 영어 표기에서 아포스트로피 위치가 다른 것은 오타가 아닙니다. ones' complement는 전부 1인 워드를 기준으로 삼고, two's complement는 2의 거듭제곱 하나를 기준으로 삼습니다.
2의 보수
음수 값 −x2^n − x로 저장됩니다. 범위는 −2^(n−1)부터 2^(n−1)−1까지로 의도적으로 비대칭이며 0이 하나입니다. 덧셈, 뺄셈, 그리고 하위 워드의 곱셈까지 모두 부호를 가리지 않으며, 이것이 승리한 이유의 전부입니다.
오프셋 바이너리
value + 2^(n−1)을 저장하므로 −2^(n−1)이 전부 0이 되고, 패턴의 정렬 순서가 그것이 나타내는 값의 순서와 같아집니다. 2의 보수 패턴에서 최상위 비트를 뒤집은 것과 같습니다. 이름에는 주의하세요. IEEE 754 지수부는 2^(e−1)−1로 치우쳐 있어 여기서 쓰는 오프셋보다 1만큼 작습니다.
계산에 BigInt를 쓰는 이유
JavaScript는 &, |, ~와 시프트의 피연산자를 32비트 정수로 변환한 뒤 연산하고 다시 되돌립니다. 그래서 64비트 값은 아무 오류도 없이 위쪽 절반을 잃습니다. 이 페이지의 모든 변환은 임의 정밀도 정수 위에서 이루어지며, 64비트 양 끝값이 정확하게 나오는 이유이기도 합니다.

부호 있는 값을 제대로 다루기

무엇보다 먼저 비트 폭을 확정하기
필드가 몇 비트인지 말하기 전까지 비트 패턴에는 값이 없습니다. 데이터시트와 디버거가 어긋나는 사례는 대개 한쪽은 16비트를, 다른 쪽은 32비트를 가정한 경우로 귀결됩니다.
최솟값은 특수 사례로 다루기
어느 비트 폭에서도 부호를 뒤집으면 넘칩니다. 2의 보수 부호 있는 바이트에서 −(−128)은 여전히 −128입니다. 절댓값을 구하는 코드에는 이 입력에 대한 방침이 있어야 하고, 테스트에도 반드시 들어가야 합니다.
부호 유무를 데이터에서 추측하지 않기
비트를 아무리 들여다봐도 그 필드가 부호 있는지는 알 수 없습니다. 데이터시트, 스키마, 구조체 정의에서 가져오세요. 추측은 운영 환경에 첫 음수가 도착할 때까지만 통합니다.
폭을 넓힐 때는 부호 확장하기
8비트 0xFB를 16비트 필드에 0x00FB로 옮기면 −5가 251이 됩니다. 부호 있는 값을 넓힌다는 것은 부호 비트를 복제한다는 뜻이고, 결과는 0xFFFB여야 합니다.
언어가 제공하는 변환을 우선하기
JavaScript의 BigInt.asIntN, Python의 int.from_bytes(..., signed=True), C의 고정 폭 타입은 의도를 분명히 밝히고 경계도 처리해 줍니다. 손으로 쓴 ~x + 1이야말로 비트 폭 버그가 나오는 곳입니다.

자주 묻는 질문

2의 보수란 무엇인가요, 한 문장으로 말하면?
음수 −x2^n − x의 비트 패턴으로 저장하는 규약입니다. 덧셈과 뺄셈이 같은 회로로 처리되고, 수직선 위의 0이 정확히 하나가 됩니다.
2의 보수를 손으로 구하는 절차는?
절댓값을 2진수로 쓰고, 모든 비트를 뒤집은 다음, 1을 더합니다. 8비트에서 5라면 000001011111101011111011. 뒤집기까지만 한 결과가 1의 보수이며, 그래서 두 값은 언제나 1만큼 떨어져 있습니다.
부호 있는 바이트에 −128은 들어가는데 +128은 왜 안 되나요?
2의 보수의 범위는 의도적으로 비대칭입니다. n비트로 −2^(n−1)부터 2^(n−1)−1까지를 덮습니다. 부호-절대값이나 1의 보수처럼 음의 0에 패턴 하나를 낭비하지 않기 때문에, 남는 한 자리가 음수 쪽에 붙습니다.
11111011은 −5인가요, 251인가요?
둘 다이며, 비트만 봐서는 알 수 없습니다. 답은 그 값을 만들어 낸 시스템이 선언한 타입에 달려 있습니다. 그래서 이 페이지의 역방향 조회는 하나를 골라 주는 대신 모든 해석을 동시에 보여 줍니다. 손에 있는 int8_tuint8_t에 맞는 행을 고르세요.
오프셋 바이너리는 무엇이고 어디서 만나게 되나요?
오프셋 바이너리(excess-K, 바이어스 표현)는 value + 2^(n−1)을 저장합니다. 최솟값이 전부 0이 되고, 원시 패턴을 부호 없는 정수로 정렬한 순서가 부호 있는 값의 순서와 일치합니다. ADC와 DAC 출력, 오디오 샘플 형식에서 볼 수 있습니다. 다만 IEEE 754의 지수부 바이어스는 2^(e−1)−1로 1만큼 작으니 숫자를 그대로 옮겨 쓰지 마세요.
센서는 −100이라는데 Modbus 레지스터는 왜 65436으로 읽히나요?
Modbus는 타입 정보가 없는 16비트 워드를 실어 나르므로, 부호가 없다고 가정한 클라이언트는 65436을 표시하지만 장치가 뜻한 값은 2의 보수 −100입니다. 65436을 16진수 0xFF9C로 비트 폭 16에서 여기에 붙여 넣으면 2의 보수 행이 의도된 값을 보여 줍니다.
부호-절대값과 1의 보수는 지금도 쓰이나요?
정수에서는 사실상 쓰이지 않습니다. 현행 CPU는 거의 전부 2의 보수를 쓰고, C23에서 마침내 필수가 되었습니다. 그래도 알아 둘 값어치가 있는 이유는 IEEE 754 부동소수점이 부호-절대값 배치를 그대로 유지하고 있고, 컴퓨터 구조 시험 문제에 여전히 나오기 때문입니다.
64비트 값에서 틀린 답을 내는 계산기가 있는 이유는?
JavaScript의 비트 연산자는 피연산자를 먼저 32비트 정수로 변환하므로, ~x + 1로 구현한 페이지는 64비트 값의 위쪽 절반을 조용히 잃고 그럴듯하지만 틀린 결과를 내놓습니다. 이 도구는 전 구간을 BigInt로 처리하며, 그래서 여기 64비트 행은 디버거가 보여 주는 값과 일치합니다.
음의 0이란 무엇이고 왜 문제가 되나요?
부호-절대값에서는 0000000010000000이 모두 0을 뜻하고, 1의 보수에서는 0000000011111111입니다. 따라서 같아야 할 두 값이 비트 단위 비교에서는 다르게 나올 수 있습니다. 2의 보수의 0은 하나뿐이며, 이 덕분에 하드웨어의 특수 사례 한 무더기가 사라졌습니다.
입력한 내용이 서버로 전송되나요?
아닙니다. 페이지는 변환 엔진을 브라우저로 내려보내 그 자리에서 실행합니다. 레지스터 덤프나 펌웨어 값은 밖으로 내보낼 수 없는 시스템에서 나온 경우가 많으니, 여기서 믿어 달라고 부탁할 것도 없습니다. 네트워크 탭을 열어 보면 요청이 한 건도 나가지 않는다는 사실을 확인할 수 있습니다.