진법 변환기

숫자를 2진, 8진, 10진, 16진 및 2부터 36까지 임의 진법으로 상호 변환. 고정 폭 2의 보수와 비트 그리드 포함.

비트 폭
2진수
8진수
10진수
16진수
진법
비트 — 클릭해 뒤집기

폭 8비트, 그중 8개가 켜짐

이 도구가 하는 일

같은 수를 여러 진법으로 쓸 수 있고, 프로그래머는 그중 넷 사이를 끊임없이 오갑니다: 하드웨어가 담는 것이라 2진수, 2진수의 읽을 수 있는 약기라 16진수, 사람이 그렇게 생각하니 10진수, 그리고 파일 권한과 몇몇 오래된 시스템이 아직 쓰니 8진수입니다. 여기 어느 칸에 값을 입력해도 나머지가 따라오고, 더해서 2부터 36까지 임의 진법으로 설정할 수 있는 칸도 하나 딸려 옵니다.

이것을 학교 계산기와 가르는 것은 폭 선택과 비트 그리드입니다. 8, 16, 32, 64비트를 고르면 음수가 빼기 기호가 아니라 진짜 기계 표현을 얻고, 모든 비트가 클릭할 수 있는 것이 됩니다.

진법이란 실제로 무엇인가

진법이란 다 써서 올림해야 하기까지 숫자가 몇 개 있느냐입니다. 10진수에는 열 개가 있어 9 다음이 10입니다. 2진수에는 두 개가 있어 1 다음이 10입니다. 각 자리의 위치는 진법의 거듭제곱이고, 그게 전부입니다:

1011           # 이 수를 2진수로
1 x 8 = 8      # 비트 3
0 x 4 = 0      # 비트 2
1 x 2 = 2      # 비트 1
1 x 1 = 1      # 비트 0
8+0+2+1 = 11   # 합계를 10진수로

열을 넘는 진법에는 열 개보다 많은 숫자 기호가 필요해 글자를 빌립니다: 16진수는 0-9 다음 a-f로 가고 a는 10, f는 15입니다. 그것이 진법 36까지 이어지며, 거기서는 모든 숫자와 모든 글자를 씁니다 — 맨 알파벳으로 쓸 수 있는 가장 큰 진법이자, 이 도구가 거기서 멈추는 이유입니다.

왜 16진수이고 다른 무언가가 아닌가

16진수는 하나의 특정한 이유로 인기입니다: 16은 2의 4제곱이라 정확히 16진수 한 자리가 정확히 4비트를 덮습니다. 그 덕에 16진수와 2진수의 변환이 계산 없는 찾아보기가 됩니다 — 각 16진수 자리가 주변 자리와 무관하게 저만의 4비트로 펼쳐집니다.

d    e    a    d
1101 1110 1010 1101   # 각 16진수 자리가 저마다의 니블

8진수는 한 자리 3비트로 같은 방식으로 돕니다. 8이 2의 3제곱이기 때문입니다 — 그래서 Unix 권한이 8진수입니다: 사용자 그룹마다 세 권한 비트가 정확히 한 자리에 들어맞습니다. 10진수는 2진수와 그런 관계가 없어, 둘 사이의 변환에는 찾아보기가 아니라 진짜 나눗셈이 필요합니다.

여기 2진수 칸이 넷씩, 16진수 칸이 둘씩 묶인 것도 그래서입니다: 그 묶음이 중요한 경계에 맞으므로 세지 않고도 니블이나 바이트를 화면에서 읽어 낼 수 있습니다.

음수와 2의 보수

음수는 그 자체로는 2진 형태가 없습니다. 레지스터에 빼기 기호는 없고 — 비트뿐입니다 — 그래서 부호는 비트 자체에 부호화되어야 하고, 그러려면 비트가 몇 개인지 정해야 합니다. 폭 선택이 있는 이유이자, 바꾸면 답이 바뀌는 이유입니다.

모든 현대 기계가 쓰는 방식은 2의 보수입니다: 음수를 나타내려면 그 양수 형태를 취해 모든 비트를 뒤집고 1을 더합니다. 그 결과 맨 위 비트가 "음수"를 뜻하게 되고, 부호를 위한 특별한 경우 없이 보통의 덧셈이 계속 통합니다.

0000 0101   # 5
1111 1010   # 모든 비트 뒤집기
1111 1011   # 1 더하기: 바이트로 -5, 16진수로 fb

레지스터를 넓히면 같은 수가 다른 패턴을 얻습니다: -5는 8비트로 fb, 16비트로 fffb, 32비트로 fffffffb입니다. 값은 바뀌지 않았습니다. 그것을 나르는 비트의 수가 바뀌었습니다. 이 도구에서 폭을 바꾸면 바로 그것이 보입니다.

0xFF가 255이면서 -1이기도 한 이유

비트 ff는 그것이 부호 있는지를 말하지 않습니다. 1111 1111을 담은 바이트는 그것을 읽는 코드가 부호 없는 타입을 선언했으면 255로, 부호 있는 것을 선언했으면 -1로 읽힙니다. 바이트 자체에는 둘을 가르는 것이 아무것도 없습니다 — 타입은 그런 정보를 지니지 않은 비트에 대해 프로그램이 하는 주장입니다.

그것이 진짜 버그 한 무리의 근원입니다: 음수로 나오는 체크섬, 파일에서 읽어 0보다 작게 비교되는 바이트, 부호 유무가 구현 정의라 ARM에서 x86과 다르게 동작하는 C의 char입니다. 부호 있는 읽기와 부호 없는 읽기가 다를 때마다 이 도구는 둘 다 보여 줍니다. 그 어긋남이야말로 대개 당신이 찾던 것이기 때문입니다.

비트 그리드

현재 값의 모든 비트가 위치 번호와 함께 표시되고, 하나를 클릭하면 뒤집힙니다. 진법이 곧바로 갱신되어, 몇몇 물음을 손으로 하기보다 훨씬 쉽게 답할 수 있게 합니다:

  • 이 플래그 값에서 어느 비트가 켜졌나 — 하나씩 클릭하며 위치를 읽으세요.
  • 비트 4와 7의 마스크는 무엇인가 — 그 둘을 켜고 16진수를 읽으세요.
  • 맨 위 비트를 켜면 부호 있는 값에 무슨 일이 생기나 — 눈에 보이게 음수가 됩니다.
  • 이 값이 2의 거듭제곱인가 — 2의 거듭제곱은 정확히 한 비트만 켜져 있습니다.

비트 0이 최하위 비트이고 오른쪽에 있으며, 이는 보편적 관례이자 오른쪽에서 왼쪽으로 쓰는 페이지에서도 그리드가 왼쪽에서 오른쪽으로 남는 이유입니다. 행은 여덟 비트 폭이라 바이트 경계가 한눈에 보입니다.

큰 수도 정확하게 남는다

JavaScript 숫자는 배정밀도라 정수를 정확히 담는 것은 2^53 — 약 9천조 — 까지뿐입니다. 64비트 값은 그것을 넘을 수 있고, 보통 숫자로 만든 변환기는 그것을 조용히 반올림해 그럴듯해 보이지만 마지막 자릿수가 틀린 16진수 문자열을 냅니다.

여기서는 모든 것이 대신 임의 정밀도 정수를 씁니다. 그래서 온전한 64비트 값이 정확히 변환됩니다. 임의 정밀도 폭 모드는 더 나아가 한계를 아예 없앱니다 — 암호 값과 큰 식별자에 유용합니다 — 다만 고정 폭이 없으면 2의 보수도 없으므로, 그 모드에서 음수는 어느 진법에서든 그저 빼기 기호를 지닙니다.

자주 묻는 질문

-5가 2진수로 -101이 아니라 fb로 표시되는 이유는 무엇인가요?
레지스터에 빼기 기호가 없기 때문입니다. 폭을 고르면 음수는 2의 보수로 표시되고, 이는 기계가 실제로 저장하는 것입니다: 바이트로 -5는 1111 1011, 즉 fb입니다. 부호 있는 수학적 형태를 원하면 폭을 임의 정밀도로 바꾸세요.
0xFF는 255인가요, -1인가요?
둘 다입니다 — 비트는 동일하고 선언된 타입만이 정합니다. 부호 있는 8비트 값은 ff를 -1로, 부호 없는 것은 255로 읽습니다. 두 읽기가 다를 때마다 이 도구는 그것들을 나란히 보여 줍니다.
10진수 대신 16진수가 그토록 많이 쓰이는 이유는 무엇인가요?
16진수 한 자리가 정확히 4비트라, 16진수와 2진수가 계산 없는 찾아보기로 변환되고 자리가 바이트 경계에 맞기 때문입니다. 10진수는 2진수와 그런 관계가 없어, 10진수 값은 어느 비트가 켜졌는지 아무것도 말해 주지 않습니다.
여기서 가장 높은 진법은 무엇이고 왜 36인가요?
36입니다. 숫자 10개에 글자 26개 — 맨 라틴 알파벳이 주는 모든 기호 — 이기 때문입니다. 더 높이 가려면 어떤 추가 문자를 쓸지에 대한 합의가 필요한데, 합의된 하나가 없습니다.
0x나 공백이 든 값을 붙여넣을 수 있나요?
네. 0x, 0b, 0o 접두사는 맞는 진법에서 받아들여지고, 공백과 밑줄은 무시되므로, 코드나 데이터시트에서 그대로 붙여넣어도 먼저 정리할 필요가 없습니다.
64비트 값이 정확히 변환되나요?
네. 모든 연산이 임의 정밀도 정수를 쓰므로, 2^53 — 보통 JavaScript 숫자가 반올림하기 시작하는 곳 — 을 넘은 값도 정확히 남습니다.
제가 입력한 것이 서버로 전송되나요?
아니요. 브라우저 안의 연산입니다. 아무것도 업로드되거나 기록되지 않고, 네트워크 연결 없이 동작합니다.