부호와 부호화 문서의 검증 코드다. if __name__ == "__main__": 아래가 자체 테스트다.

"""부호와 부호화 문서의 값 확인.

문서: 04.부호와 부호화
주장:
  1. '가'의 유니코드 번호는 44032 = U+AC00 = 1010 1100 0000 0000(2).
  2. UTF-8 변환 표: U+0000~007F 1바이트, ~07FF 2바이트, ~FFFF 3바이트, ~10FFFF 4바이트.
     '가' -> 1110 1010 / 10 110000 / 10 000000 = EA B0 80.
  3. UTF-16은 '가'를 2바이트, UTF-32는 4바이트로 적는다.
  4. 부호 비율 R = log|C| / (n log|Sigma|): 반복 부호 {000, 111}은 1/3, 4비트에 패리티 1비트는 4/5,
     해밍 (7,4)는 4/7, 길이 n의 모든 2진 열은 1.
  5. 부호화는 1:1이어야 복호화할 수 있다.
실행: python3 04_code-encoding_verify.py
"""
import math
from fractions import Fraction
from itertools import product


def utf8_manual(cp):
    if cp <= 0x7F:
        return [cp]
    if cp <= 0x7FF:
        return [0b11000000 | cp >> 6, 0b10000000 | cp & 0x3F]
    if cp <= 0xFFFF:
        return [0b11100000 | cp >> 12, 0b10000000 | (cp >> 6) & 0x3F, 0b10000000 | cp & 0x3F]
    return [0b11110000 | cp >> 18, 0b10000000 | (cp >> 12) & 0x3F,
            0b10000000 | (cp >> 6) & 0x3F, 0b10000000 | cp & 0x3F]


def rate(code, q):
    n = len(next(iter(code)))
    return math.log(len(code)) / (n * math.log(q))


if __name__ == "__main__":
    assert ord("가") == 44032 == 0xAC00 and format(44032, "016b") == "1010110000000000"
    for cp in list(range(0, 0xD800, 7)) + list(range(0xE000, 0x110000, 101)) + [0x7F, 0x80, 0x7FF, 0x800, 0xFFFF, 0x10000, 0x10FFFF]:
        assert bytes(utf8_manual(cp)) == chr(cp).encode("utf-8")
    assert "가".encode("utf-8").hex().upper() == "EAB080"
    assert [format(b, "08b") for b in "가".encode("utf-8")] == ["11101010", "10110000", "10000000"]
    assert len("A".encode("utf-8")) == 1 and len("é".encode("utf-8")) == 2 and len("😀".encode("utf-8")) == 4
    assert len("가".encode("utf-16-be")) == 2 and len("가".encode("utf-32-be")) == 4
    assert ord("A") == 65 and format(65, "07b") == "1000001"
    # "가A"는 UTF-8로 4바이트
    assert len("가A".encode("utf-8")) == 4

    rep = {"000", "111"}
    assert abs(rate(rep, 2) - 1 / 3) < 1e-12
    par = {"".join(m) + str(sum(map(int, m)) % 2) for m in product("01", repeat=4)}
    assert len(par) == 16 and abs(rate(par, 2) - 4 / 5) < 1e-12
    assert Fraction(4, 7) == Fraction(int(math.log2(16)), 7)
    full = {"".join(m) for m in product("01", repeat=5)}
    assert abs(rate(full, 2) - 1) < 1e-12
    # 카드: 길이 5, 부호어 8개인 2진 부호 -> (5, 8) 부호, 비율 3/5
    assert abs(math.log2(8) / 5 - 0.6) < 1e-12
    # 1:1이 아니면 복호화가 갈린다
    bad = {"a": "0", "b": "0"}
    assert len(set(bad.values())) < len(bad)
    print("ALL CHECKS PASSED")