진법 변환기
숫자를 2진, 8진, 10진, 16진 및 2부터 36까지 임의 진법으로 상호 변환. 고정 폭 2의 보수와 비트 그리드 포함.
폭 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 숫자가 반올림하기 시작하는 곳 — 을 넘은 값도 정확히 남습니다.
- 제가 입력한 것이 서버로 전송되나요?
- 아니요. 브라우저 안의 연산입니다. 아무것도 업로드되거나 기록되지 않고, 네트워크 연결 없이 동작합니다.