情報の表現

目次

概要

ビット・文字・数・画像・音をつなげて理解する

情報の表現は、コンピュータサイエンスの入口です。文字も画像も音も、最終的には0と1の列として扱われます。なぜそれで多様な情報を扱えるのかを、直感と構造の両方から見ていきます。

要点

情報の表現とは、現実の対象をビット列へ写す規約です。表現と意味を切り分けて考えると、文字コード、浮動小数点、圧縮、ファイル形式が一気につながります。

この章で重視すること

  • 単に用語を覚えるのではなく、なぜその表現が必要かを理解する
  • 「意味」と「表現」の違いをはっきり区別する
  • 文字化け、丸め誤差、圧縮の劣化のような実務上の事故へつなげて考える
  • 2025~2026年の最新動向(ベクトル表現、量子情報、AIによる圧縮)も視野に入れる

情報表現の全体像

コンピュータは、最初から「文字」「音」「写真」を知っているわけではありません。ある対象をどういう規約でビット列へ写すかを決め、その規約に沿って保存・転送・解釈しているだけです。

flowchart LR A[現実の対象] --> B[符号化の規約] B --> C[ビット列] C --> D[保存 転送] D --> E[復号して意味に戻す]

ここで大事なのは、ビット列そのものは最初から意味を持たない という点です。意味は、どの規約で読むかによって決まります。

情報表現を学ぶときの見取り図

flowchart TD A[現実の対象] --> B[離散化] B --> C[符号化] C --> D[保存 転送] D --> E[復号] E --> F[人間や別プログラムが解釈]

ビットとバイト

ビット は0または1のどちらかを表す最小単位です。 バイト は通常8ビットをひとまとめにした単位です。

直感的には、

  • ビット = スイッチ1個
  • バイト = スイッチ8個の小箱

です。

ASCII文字の多くは1バイトで表せますが、UTF-8の日本語は複数バイトになることが多いです。ここからも、「1文字 = 1バイト」とは限らないことがわかります。

なぜ2値なのか

ここで一度立ち止まって、「なぜ0と1なのか」を見ておくと、あとがかなり楽になります。

物理世界の信号は本来連続的で、電圧もノイズもゆらぎます。にもかかわらず計算機が安定して動けるのは、細かなゆらぎを無視して「しきい値より上なら1、下なら0」と丸めて扱うからです。2値は情報量の都合だけでなく、壊れにくく判定しやすい という工学上の事情とも結びついています。

つまり、

  • ビットは数学的な記号
  • 2値化は工学的な安定化

の両面を持っています。

ビット・バイト・KiB・MiBの違い

実務では容量の単位が意外と混乱しやすいです。

  • byte (B): 8ビット
  • KB, MB, GB: 10進系(1000倍)で使われることが多い
  • KiB, MiB, GiB: 2進系(1024倍)の単位

たとえばメモリとストレージでは慣習がずれることがあります。数字だけを見ていると「なぜ表示容量が少ないのか」で混乱するので、単位系が1000なのか1024なのか を意識する癖が大切です。

情報量の単位

  • 1 ニブル = 4ビット(16進1桁)
  • 1 バイト = 8ビット
  • 1 ワード = CPUによる(通常32 ~ 64ビット)
  • 1 セクタ = ディスク固有(通常512 B ~ 4096 B)

2進数と整数表現

進数変換と直感

10進数では10ごとに桁が上がりますが、2進数では2ごとに桁が上がります。

例:

  • 13 = 1101_2 = 1×8 + 1×4 + 0×2 + 1×1
  • 42 = 101010_2 = 1×32 + 0×16 + 1×8 + 0×4 + 1×2 + 0×1
  • 255 = 11111111_2 = 2^8 - 1

2進数が使われるのは、回路が「高い / 低い」「流れる / 流れない」のような二値を扱いやすいからです。

8進数と16進数

コンピュータ内部では2進が主ですが、実務では8進と16進がよく出ます。

8進数(Octal)

  • 2進3桁 = 8進1桁
  • 123_8 = 001 010 011_2 = 43_10
  • Unixのファイル権限(755 など)で使われる

16進数(Hexadecimal)

  • 2進4桁 = 16進1桁
  • FF16FF_16 = 11111111_2 = 255_10
  • メモリダンプ、色コード、ハッシュ値で常用
  • 記号:0-9, A-F(大文字 / 小文字区別なし)
flowchart LR A[10進数42] --> B[2進変換] B --> C[101010 2] C --> D[8進表示] D --> E[52 8] C --> F[16進表示] F --> G[2A 16]

符号なし整数と符号付き整数

符号なし整数はそのままビットへ展開できますが、負数をどう表すかが問題になります。現在のほとんどの計算機では 2の補数表現 が使われます。

符号表現の方法

1. 符号絶対値方式(Sign-Magnitude)

  • 最上位ビットを符号(0=正、1=負)
  • 例:4ビット で 1011_2 = -(011_2) = -3
  • 問題:ゼロが2通りある(0000, 1000)

2. 1の補数(One’s Complement)

  • 負数は全ビット反転
  • 例:4ビット で 1100_2 = -(0011_2) = -3
  • 問題:やはりゼロが2通り、加算が複雑

3. 2の補数(Two’s Complement) ← 現在の主流

  • 負数は全ビット反転 + 1
  • 例:4ビット で 1101_2 = -(0011_2) = -3
  • 利点:ゼロが一意、加算回路が単純
flowchart TD A[4ビット整数 +3 = 0011] B[符号絶対値1011 = -3] C[1の補数1100 = -3] D[2の補数1101 = -3] A --> B A --> C A --> D

2の補数が好まれる理由

2の補数が好まれる理由:

  • 正数と負数を同じ加算回路で扱いやすい
  • 0の表現が一意
  • オーバーフロー時の振る舞いが機械的に決まる
  • ビット操作が直感的

例:4ビット で 3 + (-3) を計算

  0011  (+3)
+ 1101  (-3, 2の補数)
------
10000  (キャリーを無視して0000)

範囲はビット数で決まる

n ビットで表せる値の個数は 2^n 通りです。そこから、

  • 符号なし n ビット: 0 から 2^n - 1
  • 2の補数 n ビット: -2^(n-1) から 2^(n-1)-1

が導かれます。

例:8ビット(1バイト)

  • 符号なし:0 ~ 255
  • 2の補数:-128 ~ 127

ここで重要なのは、ビット列は有限 だということです。つまり整数型には必ず上限と下限があり、その範囲を超えるとオーバーフローやアンダーフローの話が出てきます。

BCD(Binary Coded Decimal)

BCD は、10進数の各桁を4ビット で表した方式です。

例:123_10 をBCDで表す

1      2      3
0001   0010   0011

メリット:

  • 10進数との相互変換が簡単
  • 金融計算で内部表示に使われることもある

デメリット:

  • 領域が無駄(4ビット で0~15が表現できるのに0~9しか使わない)
  • 演算が複雑

実務では、BCDは古いメインフレームやレガシーシステム、某些金融端末で見られます。

オーバーフロー、アンダーフロー、飽和算(Saturation)

オーバーフロー

初心者のうちは「値が大きすぎると壊れる」という説明で終わりがちですが、もう少し丁寧に言うと、オーバーフローは

  • 数学の整数は無限に広い
  • コンピュータの整数型は有限の箱である

というズレが表面化したものです。

例:8ビット 符号なし で 200 + 100

  11001000  (200)
+ 01100100  (100)
----------
 100101100  (9ビット必要だが、8ビットしかない)
-> 00101100  (44, 元の値300ではない)

ラップアラウンド(Wrap-around)

加算の結果がビット数を超えると、余りだけが残ります。これをラップアラウンドと呼びます。

flowchart LR A[8ビット符号なし0-255] B[256 mod 256 = 0] C[257 mod 256 = 1] D[オーバーフロー時の値] A --> D B --> D C --> D

飽和算(Saturation Arithmetic)

ラップアラウンドの代わりに、「最大値で止める」という方法もあります。これを飽和算と呼びます。

例:8ビット 符号なし で 200 + 100(飽和)

結果:255  (オーバーフロー時は最大値で止める)

使われる場面:

  • グラフィックス(ピクセル値が255を超えない)
  • DSP(デジタル信号処理)
  • SIMD演算(AVX, NEONなど)

任意精度整数とBigInteger

普通の整数型は有限ですが、任意の精度を持つ整数も扱えます。

言語別の実装:

  • Python:int は自動的に任意精度
  • Java:java.math.BigInteger
  • JavaScript:BigInt(100n のような記号)
  • C++:Boost.Multiprecisionライブラリ
# Pythonの任意精度整数
big = 123456789012345678901234567890
print(big + 1)  # 完全に正確に計算される

内部表現: 通常、可変長の「チャンク」(32~64ビット) の配列で実装されます。


浮動小数点数

実数は無限の精度を持つことがあるため、コンピュータでは近似で表します。代表が IEEE 754 です。

IEEE 754の構造

binary32(float)とbinary64(double)

binary64(double)は、

  • 符号ビット : 1ビット
  • 指数 : 11ビット
  • 仮数 : 52ビット

に分けて数を表します。

符号: 0 = 正, 1 = 負
指数: バイアスされた指数(bias = 1023)
仮数: 隠れた1ビットを含めて計53ビット有効
flowchart LR A[実数] --> B[符号] A --> C[指数] A --> D[仮数] B --> E[binary64のビット列] C --> E D --> E

IEEE 754の詳細

指数とバイアス

指数は「バイアス表現」で保存されます。

  • binary32のbias : 127
  • binary64のbias : 1023

例:binary64で指数が 2^{10} の場合

実際の指数:10
ビットに保存:10 + 1023 = 1033

正規数(normal)と非正規数(subnormal)

正規数

  • 仮数の最上位ビットが1(隠れている)
  • 指数が全て0でも1でもない

非正規数(subnormal / denormalized)

  • 指数が全て0
  • 仮数の最上位ビットが0
  • アンダーフローの範囲を拡張
  • 例:binary64で 2^{-1074} まで表現可能

特殊値

符号     指数      仮数      値
0全て1全て0      +Infinity
1全て1全て0      -Infinity
x全て1    0以外NaN (Not a Number)

なぜ 0.1 + 0.2 != 0.3 が起こるのか

0.10.2 は2進の有限桁でぴったり表せません。そこで近い値に丸められます。その結果、

  • 0.10.1000000000000000055511151231...
  • 0.20.2000000000000000111022302463...
  • 0.30.2999999999999999888977697537...

が人間の思う「ちょうどその値」とは少しずつずれます。

>>> 0.1 + 0.2
0.30000000000000004
>>> 0.1 + 0.2 == 0.3
False

10進では正確だが、2進では無限小数。コンピュータが2進で有限桁で近似するため、このずれが生じます。

丸め誤差(Rounding Error)

浮動小数点の丸め方はIEEE 754で定義されています。

丸めモード:

  1. Round to Nearest, Ties to Even(RNE)← 默认
  2. Round towards Positive Infinity(+∞方向)
  3. Round towards Negative Infinity(-∞方向)
  4. Round towards Zero(0方向)

デフォルト(RNE)は「最も近い偶数へ」という方式で、統計的にバイアスが少ないです。

桁落ち(Catastrophic Cancellation)

近い値同士を引くと、有効桁が大きく減ります。

例:x=1.0000000001x = 1.0000000001, y=1.0y = 1.0 のとき

x - y = 0.0000000001 (有効桁が12になってしまう)

対策:

# 悪い:桁落ちの危険
result = (1 + small) - 1  # smallが失われる

# 良い:数学的に等価だが桁落ちが少ない
result = small  # 直接計算

例外処理(Exception Handling)

IEEE 754では5つの例外が定義されています:

  1. Invalid Operation : 0/0、sqrt(-1) など
  2. Division by Zero : 1/0 → ±Infinity
  3. Overflow : 結果が大きすぎる
  4. Underflow : 結果が小さすぎて0に丸まる
  5. Inexact : 丸めが発生した

多くの環境で、これらは例外を発生させるか、特殊値(NaN、Inf)を返すか、フラグを設定します。

浮動小数点は科学計算の敵ではない

浮動小数点の話になると、しばしば「危険だから使うな」という雑な理解になりがちです。でも実際には、浮動小数点は科学計算、機械学習、画像処理、シミュレーションの土台です。

本質は、

  • 浮動小数点が悪いのではない
  • 近似表現であることを忘れるのが危ない

ということです。

たとえば比較でも、

  • x==yx == y をそのまま使うと危ないことがある
  • 許容誤差を決めて比較するほうが自然なことがある

という判断が必要です。

# 危険
if result == 0.3:
    pass

# 安全
epsilon = 1e-10
if abs(result - 0.3) < epsilon:
    pass

金融計算にdecimalを使う理由

金融計算や厳密な小数計算で decimal 系が使われるのは、浮動小数点が近似だからです。

from decimal import Decimal

# 浮動小数点:不正確
print(float(0.1) + float(0.2))  # 0.30000000000000004

# Decimal:正確
print(Decimal('0.1') + Decimal('0.2'))  # 0.3

Decimalは10進の規則で小数を扱えるため、0.1 のような値を十進表記のまま正確に表しやすく、金融計算や会計処理に向いています。


エンディアン

マルチバイト整数をメモリにどう並べるかには複数の方法があります。

ビッグエンディアンとリトルエンディアン

ビッグエンディアン(Big Endian)

  • 上位バイトが先(先頭のアドレス)
  • ネットワークバイトオーダー
  • Motorola 68000、PowerPC、ARM(メインフレーム)

リトルエンディアン(Little Endian)

  • 下位バイトが先(先頭のアドレス)
  • Intel x86、x86-64、ARM(モバイル)

例:0x12345678を4バイトに保存

メモリ ビッグエンディアン リトルエンディアン
addr+0 0x12 0x78
addr+1 0x34 0x56
addr+2 0x56 0x34
addr+3 0x78 0x12
flowchart TD A[整数0x12345678] B[ビッグエンディアン] C[リトルエンディアン] D[12 34 56 78] E[78 56 34 12] A --> B A --> C B --> D C --> E

ミドルエンディアン

歴史的には「ミドルエンディアン」(ワード単位でビッグ、バイト単位でリトル)も存在しましたが、現在はほぼ使われません。

なぜエンディアンが問題になるのか

この違いは、ネットワークプロトコル、バイナリ互換性、ファイル形式を理解するうえで重要です。

実務上の問題:

  • ネットワーク通信 : 受信側が異なるエンディアンで読むと数値が反転
  • バイナリファイル : ファイル形式で指定されたエンディアンと異なると解釈失敗
  • 言語間の連携 : CとJava、Pythonなど言語が異なると自動変換が入る

何が混乱のもとになるのか

エンディアンは「数の意味」が変わる話ではなく、メモリ上の並び順 の話です。ここを取り違えると、

  • 16進ダンプを読む
  • ネットワークパケットを解析する
  • バイナリファイルを実装する

ときに混乱します。

とくに、ネットワークでは歴史的にビッグエンディアンが「ネットワークバイトオーダ」として使われることが多く、CPU内部の都合とは別にプロトコルの約束が存在します。

変換関数

多くの言語で、エンディアン変換関数が提供されています。

// C/POSIX
#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong);  // host -> network
uint32_t ntohl(uint32_t netlong);   // network -> host
# Python 3.10+
int.from_bytes(b'\x12\x34', byteorder='big')
int.to_bytes(0x1234, 2, byteorder='little')

文字コード

文字は、そのまま保存できません。そこで「この文字にはこの番号を割り当てる」という体系が必要になります。

  • ASCII: 英数字中心の古典的集合
  • Unicode: 世界中の文字を統一的に扱う体系
  • UTF-8: Unicodeを実際のバイト列へ落とす方式

文字コードの歴史

BCDとEBCDIC

コンピュータ黎明期には、10進を4ビット で表すBCD(前述)や、その拡張版EBCDICが使われていました。EBCDICはIBMメインフレームで長く使用されていますが、現代ではほぼ使われません。

ASCII(American Standard Code for Information Interchange)

1960年代に標準化された7ビット 文字コード

0-31:制御文字(改行、タブなど)
32-126:印字可能文字(空白、記号、数字、英字)
127:DEL

例:

  • A = 0x41 = 65
  • 0 = 0x30 = 48
  • スペース = 0x20 = 32

拡張ASCII では8ビット を使い、128~255に字形を追加していますが、地域によって異なり、互換性に問題がありました。

JIS X 0208とShift_JIS

日本で使われていた複数バイト方式。

Shift_JIS は、ASCII互換を保ちながら日本語を表現:

  • 0x00~0x7F:ASCII(1バイト)
  • 0x81~0x9F, 0xE0~0xEF:日本語の第1バイト(2バイト)

EUC-JP(Extended Unix Code - Japanese)

Unix環境で使われた別の日本語符号化。

  • 0x00~0x7F:ASCII(1バイト)
  • 0x8E:半角カタカナ切り替え
  • 0xA1~0xFE:日本語(2バイト)

ISO 8859シリーズ

各地域の文字を1バイト で表す体系(ただし拡張なし)。

  • ISO 8859-1(Latin-1):西ヨーロッパ言語
  • ISO 8859-5:キリル文字
  • ISO 8859-7:ギリシャ文字

問題 : 複数の地域文字を同時に使えない。

UnicodeとUCS

1990年代に、世界中の文字を統一的に番号づける体系が開発されました。

  • UCS (Universal Character Set) : ISO/IEC 10646
  • Unicode : Consortiumによる同じような標準

現在、両者はほぼ同期しており、実質的に同じです。

UnicodeとUTF-8の違い

  • Unicode = 文字の体系(何の文字か)
  • UTF-8 = 保存形式(バイト列への変換方法)

です。

さらに、文字字形 も別です。Unicodeは「何の文字か」を扱い、フォントは「どう描くか」を扱います。

flowchart LR A[文字という意味] --> B[Unicode code point] B --> C[UTF-8] C --> D[バイト列] D --> E[フォントと描画] E --> F[画面上の字形]

Unicodeの構造

Code Point : 0から0x10FFFF(約110万文字)の番号。

0x0000 - 0x007F : Basic Latin (ASCII)
0x0080 - 0x00FF : Latin-1 Supplement
0x0100 - 0x017F : Latin Extended-A
...
0x3040 - 0x309F : Hiragana (ひらがな)
0x30A0 - 0x30FF : Katakana (カタカナ)
0x4E00 - 0x9FFF : CJK Unified Ideographs (漢字)
0xF900 - 0xFAFF : CJK Compatibility Ideographs
...
0x1F300 - 0x1F5FF : Miscellaneous Symbols and Pictographs (絵文字など)

UTF-8のエンコーディング

UTF-8 は可変長符号化:

U+0000 to U+007F    :  1 byte  0xxxxxxx
U+0080 to U+07FF    :  2 bytes 110xxxxx 10xxxxxx
U+0800 to U+FFFF    :  3 bytes 1110xxxx 10xxxxxx 10xxxxxx
U+10000 to U+10FFFF :  4 bytes 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

例:

'A' (U+0041)        : 0x41                 (1バイト)
'あ' (U+3042)       : 0xE3 0x81 0x82      (3バイト)
'😀' (U+1F600)      : 0xF0 0x9F 0x98 0x80 (4バイト)

特徴:

  • ASCIIと後方互換(0x00~0x7Fは同じ)
  • 連続性:バイト列を見て「何バイト目から始まるか」が判定可能
  • 無駄が少なく、テキストが多いときはLF的効率

UTF-16とUTF-32

UTF-16 : 2または4バイト

U+0000 to U+FFFF : 2 bytes
U+10000以上     : 4 bytes(サロゲートペア)
  • 多くの言語が2バイト で表現できる(効率的)
  • Java, C#, JavaScript内部で使用

UTF-32 : 常に4バイト

すべてのcode point : 4 bytes
  • 単純だが容量が大きい
  • インデックスアクセスが簡単

Unicodeの正規化

Unicodeでは、見た目や意味がほぼ同じでも内部表現が複数ありえます。

例:「é」(e + 急音符)は2つの方法で表現できます。

合成形式(precomposed)  : U+00E9 (1つのcode point)
分解形式(decomposed)   : U+0065 U+0301 (e + 急音符)

正規化形式:

  • NFC (Canonical Decomposition, followed by Canonical Composition)
  • NFD (Canonical Decomposition)
  • NFKC / NFKD (Compatibility + Canonical)

比較や検索の前に、両方を同じ形式に正規化する必要があります。

import unicodedata

s1 = "café"      # 合成形式
s2 = "cafe\u0301"  # 分解形式

print(s1 == s2)  # False!

# 正規化してから比較
print(unicodedata.normalize('NFC', s1) ==
      unicodedata.normalize('NFC', s2))  # True

結合文字と合字

結合文字(Combining Character) 単独では表示されず、前の文字に合成される。

例:a$ + combining dot above = $ȧ

合字(Ligature) 複数の文字が1つの字形で表現される。

例:f + ifi(活字では合字)

Unicodeでは、合字は通常コードポイントを持ちません(flf + l のまま)。ただし、フォントが合字対応なら自動的に連字表示します。

絵文字の複雑性

絵文字(U+1F300~)は見た目ほど単純ではありません。

ZWJシーケンス(Zero Width Joiner)

ZWJ(U+200D)を使い、複数の絵文字を組み合わせます。

例:👨‍👩‍👧‍👦(家族)

👨 + ZWJ + 👩 + ZWJ + 👧 + ZWJ + 👦

この列は一見1つの絵文字ですが、内部では複数のコードポイント。

スキントーン修飾子(Skin Tone Modifier)

絵文字の肌色を変更:

U+1F44B + U+1F3FB = 👋🏻(肌色light)

5段階のスキントーン修飾子があります。

絵文字の変異セレクタ

絵文字は複数の表現形式を持つことがあります。

U+2764 ❤ (emoji variant)
U+2764 U+FE0F ❤️ (text variantはU+FE0E)

実務での事故例

  • UTF-8前提のシステムに別の文字コードのデータが入って文字化けする
  • 表示上は同じに見える文字列が内部では別なので検索に引っかからない
  • 文字数制限を bytes で見てしまい、多言語入力で不公平が出る
  • 絵文字や合成文字でカーソル移動や削除位置がずれる
  • ZWJ絵文字を len() で数えると正しい「見た目の文字数」にならない

画像と音の表現

画像の基本

ラスタグラフィックスとベクタグラフィックス

ラスタグラフィックス(Raster)

  • ピクセルの格子で表現
  • JPG, PNG, BMP, TIFF, WebP, AVIF
  • 写真や複雑な画像に向く
  • 拡大するとジャギーが出る

ベクタグラフィックス(Vector)

  • 数学的な図形(線、曲線、多角形)で表現
  • SVG, PDF, EPS, AI
  • ロゴやアイコン、図表に向く
  • 解像度に依存しない
  • ただし複雑な画像には向かない
flowchart TD A[画像] --> B[ラスタ] A --> C[ベクタ] B --> D[ピクセル格子] C --> E[数学的図形]

RGBと色深度

各ピクセルは色を持ちます。RGB が最も一般的:

R(赤): 0-255
G(緑): 0-255
B(青): 0-255

合計256 × 256 × 256 = 1677万色。

色深度 によって異なります:

  • 8-bit色 : 1バイト、256色(パレット方式)
  • 16-bit色 : 2バイト(RGB565: R5G6B5)
  • 24-bit色 : 3バイト、RGBフルカラー
  • 32-bit色 : 4バイト、RGB + Alpha(透明度)

RGBAとAlphaチャンネル

Alpha は透明度 (0 = 完全透明、255 = 完全不透明)。

透明度を考慮した合成:

出力色 = 上層色 × Alpha / 255 + 下層色 × (1 - Alpha / 255)

PNGWebPはAlphaをネイティブサポート。JPEGは非対応(透明度なし)。

HSLとCMYK

別の色表現方式:

HSL (Hue, Saturation, Lightness)

  • H(色相): 0-360°
  • S(彩度): 0-100%
  • L(明度): 0-100%
  • Webデザイン・画像編集で直感的

CMYK (Cyan, Magenta, Yellow, Black)

  • 印刷用の色モデル
  • RGBからCMYKへの変換は非可逆(色ずれの可能性)

YUVとYCbCr

YUV : 人間の視覚特性を考慮した表現。

  • Y:輝度(人間の目に最も重要)
  • U, V:色差

人間の目は色の詳細より明るさに敏感なため、UとVは低い解像度にできます(色差削減)。

JPEG, MPEG, H.264などで使用。

画像の解像度とサンプリング

画像はピクセルの集まりです。各ピクセルが色の値を持ちます。

  • RGB: 赤・緑・青
  • 解像度: どれだけ細かく分けるか(例:1920×1080)
  • 色深度: 1ピクセルあたり何段階の色を持つか

画像は「現実の景色そのもの」を持っているわけではありません。持っているのは、格子状に区切ったサンプルの集まりです。

つまり画像処理は、

  • 空間をどれだけ細かく区切るか
  • 各点をどれだけ細かい段階で表すか

の2軸で決まります。

ここから、

  • 解像度を上げると細部は増えるが容量も増える
  • 色深度を上げると滑らかになるが容量も増える

というトレードオフが見えてきます。

容量計算例:

1920 × 1080 × 3 bytes (RGB) = 6,220,800 bytes ≈ 5.9 MB

圧縮しないと、高解像度画像は巨大になります。

画像フォーマット詳説

PNG(Portable Network Graphics)

特徴:

  • 可逆圧縮
  • アルファチャンネル対応
  • インターレース対応(プログレッシブ読み込み可)
  • メタデータ対応

圧縮方式:

  • Deflate(LZ77 + Huffman)
  • フィルタリング:行ごとにバイト値を変換して圧縮性向上

用途:

  • 図表、アイコン、UI
  • 写真はJPEGのが効率的

JPEG(Joint Photographic Experts Group)

特徴:

  • 非可逆圧縮
  • アルファチャンネルなし
  • 品質因子で圧縮率調整可(1-100)
  • EXIFメタデータ対応

圧縮メカニズム:

  1. RGB → YCbCr変換
  2. 8×8ピクセルブロックに分割
  3. 各ブロックをDCT(離散余弦変換)
  4. 量子化(色差を粗くする)
  5. ハフマン符号化

人間の知覚を利用:

  • 色差(CbCr)は粗くしても目立たない
  • 低周波成分は重要、高周波は削除可能

圧縮率vs品質:

  • 品質95 : ほぼロスレス(ファイルサイズ大)
  • 品質80 : 高品質(バランス型)
  • 品質60 : 一般的(Web向け)
  • 品質30 : 低品質(圧縮率重視)

WebP

特徴:

  • Googleが開発
  • JPEGより約25% 小さい
  • PNGより約26% 小さい
  • アルファチャンネル対応
  • ロスレス・ロッシー両対応
  • アニメーション対応(APNG代替)

技術:

  • VP8ビデオコーデック由来
  • 予測符号化、エントロピー符号化

AVIF(AV1 Image File Format)

特徴:

  • 次世代フォーマット(2020年代)
  • H.265/HEVCより高圧縮
  • 広色域、HDR対応
  • アルファチャンネル対応

課題:

  • エンコード速度が遅い
  • デコード対応ブラウザがまだ少ない

音声表現

音は時間ごとの振幅のサンプル列として扱われます。

  • サンプリング周波数: 時間方向の細かさ
  • ビット深度: 1点ごとの精度

ここでの直感は、連続的なものを離散的に刻んで表している、という点です。

PCM(Pulse Code Modulation)

アナログ音声をデジタル化する標準方式:

  1. サンプリング : 一定間隔(例44.1 kHz)でアナログ値を測定
  2. 量子化 : 測定値を有限の値に丸める(例16-bit = 65536段階)
  3. 符号化 : 数値のバイト列化

標準設定:

  • CD:44.1 kHz, 16-bit, ステレオ(2チャンネル)
  • 容量:44100 × 2 bytes × 2チャンネル × 秒数 ≈ 176 KB/s

サンプリング定理(Nyquist Theorem)

音を表すには、ただ細かく取ればよいわけではありません。

Nyquist周波数 = サンプリング周波数 / 2

例:44.1 kHzでサンプリング → 22.05 kHz以下の音声成分まで正確に復元可能

人間の可聴域が20 Hz~20 kHzなので、44.1 kHzで十分です(実際には20 kHz超の成分は含まれない)。

音声コーデック

無圧縮/可逆圧縮:

  • PCM : 非圧縮(44.1 kHz × 16-bit × 2ch ≈ 176 KB/s)
  • FLAC (Free Lossless Audio Codec) : 約50% 圧縮率
  • ALAC (Apple Lossless) : FLAC並の効率

非可逆圧縮:

  • MP3 (MPEG-1 Audio Layer III)

    • Psychoacoustic model:人間に聞こえない音を削除
    • ビットレート:128~320 kbps(品質による)
    • ブロックノイズ、プリエコーが課題
  • AAC (Advanced Audio Coding)

    • MP3後継、より高効率
    • iTunes, YouTubeで使用
  • Opus

    • 最新、低レート(6 kbps)~高品質対応
    • 遅延小さい(リアルタイムアプリ向け)
    • VoIP, ゲーム通話で採用増加

動画のコーデック

動画は連続する静止画(フレーム)で構成されます。フレームレートは通常24~60 fps。

フレームサイズ:1920×1080
フレームレート:30 fps
色深度:24-bit RGB
非圧縮容量:1920 × 1080 × 3 × 30  180 MB/s

圧縮なしでは保存不可能。

Iフレーム、Pフレーム、Bフレーム

多くの動画コーデック(H.264, H.265, VP9, AV1)は3種類のフレームを使い分けます。

Iフレーム(Intra)

  • 独立して復号可能(フル情報含む)
  • ファイルサイズが大きい
  • 約0.5秒ごとに挿入(キーフレーム)

Pフレーム(Predicted)

  • 前のフレームからの差分のみ
  • ファイルサイズが小さい
  • 前フレームに依存

Bフレーム(Bidirectional)

  • 前後のフレームから予測
  • 最も圧縮性が高い
  • ただし遅延増加
flowchart LR A[Iフレーム] -->|フル| B[I1] B -->|予測| C[P1] C -->|前後予測| D[B1] C -->|前後予測| E[B2] C -->|予測| F[P2]

H.264(MPEG-4 AVC)

特徴:

  • 標準化:2003年
  • 広く採用(YouTube, Netflix, Blu-ray)
  • ビットレート:500 kbps~数Mbps(品質による)
  • エンコード速度:比較的速い

H.265(HEVC - High Efficiency Video Coding)

特徴:

  • H.264より約50% 効率的
  • 4K, 8K対応
  • エンコード速度:遅い
  • 採用:YouTube(試験的)、Netflix(一部)

VP9とAV1

VP9(Google)

  • H.265に匹敵する効率
  • ロイヤルティー不要
  • YouTubeで使用

AV1(Alliance for Open Media)

  • 最新(2018年)
  • さらに高効率
  • ただしエンコード非常に遅い
  • 課題:対応デコーダが少ない

圧縮

データをそのまま持つと大きいので、圧縮が使われます。

  • 可逆圧縮: 完全に元へ戻せる
  • 非可逆圧縮: 一部を捨てて小さくする

例:

  • PNG, ZIP = 可逆
  • JPEG, MP3 = 非可逆

圧縮は魔法ではなく、偏りの利用

圧縮を深く理解するコツは、「どんなデータでも縮むわけではない」と知ることです。

圧縮は、データの中にある

  • 繰り返し
  • 偏り
  • 予測しやすさ

を利用して短く表現します。

だから、

  • もともと規則性が強いログや文章は縮みやすい
  • すでに圧縮済みのJPEGやZIPはさらに縮みにくい

という差が出ます。

可逆と非可逆は目的が違う

可逆圧縮は、「完全に戻ること」が必要な場面で使います。

  • プログラム
  • 文書
  • ソースコード
  • データベースのバックアップ

非可逆圧縮は、「多少違っても知覚上ほぼ同じならよい」場面に向きます。

  • 写真
  • 音楽
  • 動画

ここを区別せずに「圧縮率だけ」で選ぶと事故になります。

可逆圧縮アルゴリズム詳説

ハフマン符号化

原理: 頻度の高いシンボルには短いビット列を割り当て、低い頻度のシンボルには長い列を割り当てます。

例: テキスト「ABRACADABRA」

シンボル: A B R C D
頻度:    5 2 2 1 1

ハフマンツリー構築:

  1. 各シンボルを葉として開始
  2. 最も頻度の低い2つを結合
  3. 繰り返す

結果:

A: 0     (1 bit)
B: 10    (2 bits)
R: 110   (3 bits)
C: 1110  (4 bits)
D: 1111  (4 bits)

元のテキスト(1シンボル = 1byte = 8bit):

11 bytes × 8 bits = 88 bits

ハフマン符号:

0 10 110 0 1110 0 1111 0 10 110 0
= 1 + 2 + 3 + 1 + 4 + 1 + 4 + 1 + 2 + 3 + 1 = 23 bits

圧縮率:23/88 ≈ 26%

LZ77とLZ78

LZ77(滑動窓方式): 過去のテキストをバッファ(窓)として保持し、繰り返しを参照。

元:ABRACADABRACADABRA
圧縮:A B R A C A D <参照: 7文字前から6文字>

ZIP, gzip, PNGフィルタで使用。

LZ78(辞書方式): シーケンスを辞書に追加していく。

GIF圧縮で使用。

Deflate

PNG, ZIP, gzipの標準方式:

  1. LZ77 で繰り返しを除去
  2. ハフマン符号化 で短くする

両方を組み合わせることで効率向上。

Zstandard(zstd)とBrotli

最新の可逆圧縮:

Zstandard(Facebook)

  • 圧縮率:ZIPより10~20% 良い
  • 速度:非常に速い
  • ブロック単位で並列化可能

Brotli(Google)

  • 圧縮率:Deflateより15~20% 良い
  • 速度:遅い(エンコード)
  • Web配信最適化
  • Chrome, FirefoxでBrotli onの場合、自動選択

データ形式とシリアライズ

実務では「中身のビット列」だけでなく、どう読むかの手がかり も一緒に運ぶ必要があります。

たとえばファイル形式には、

  • ヘッダ
  • 長さ情報
  • エンコーディング情報
  • 圧縮方式
  • バージョン

などが含まれます。

これらは「本体ではないけれど、解釈に必須な情報」です。画像が開けるか、音声が正しく再生できるか、互換性を保てるかは、この周辺設計に大きく左右されます。

JSON, XML, YAML

JSON(JavaScript Object Notation)

  • 人間が読みやすい
  • 構造が簡潔
  • Web APIのデファクト標準
  • テキストなのでサイズが大きい

XML(Extensible Markup Language)

  • スキーマで構造を定義可能
  • SOAPなど業務システムで使用
  • 冗長(開始・終了タグ両方)

YAML(YAML Ain’t Markup Language)

  • インデント で構造表現(JSONより可読性高)
  • 設定ファイル向け(Ansible, Docker Compose)
  • Python同様にホワイトスペース重要

Protocol BuffersとMessagePack

Protocol Buffers(protobuf)(Google)

  • バイナリ形式(効率的)
  • スキーマ定義(.proto ファイル)
  • 複数言語対応
  • gRPCで使用

MessagePack

  • バイナリ形式(コンパクト)
  • JSON同等の表現力
  • 高速エンコード / デコード

CBORとAvro

CBOR(Concise Binary Object Representation)

  • RFC 8949標準
  • JSONとバイナリの中間
  • IoT, センサーネットワーク向け

Avro(Apache)

  • スキーマ必須
  • BigData(Hadoop, Spark)向け
  • 効率的なバイナリ

シリアライズとデシリアライズ

プログラム内部の構造を、そのまま別の環境へ持ち出せるわけではありません。そこで、

  • メモリ上の構造
  • 送受信や保存に向いた表現

を変換する必要があります。これがシリアライズです。

代表例:

  • JSON
  • Protocol Buffers
  • MessagePack
  • CSV

ここでの注意点は、人間に読みやすい形式機械に効率のよい形式 が一致するとは限らないことです。


エラー訂正とハッシュ

チェックサムと誤り検出

情報は保存や転送の途中で壊れることがあります。そこで、内容そのものとは別に、壊れていないかを確かめるための要約値を持つことがあります。

パリティビット

最もシンプルな誤り検出:各バイトに1ビット追加。

0bitパリティ(偶数パリティ):ビットの合計が偶数になるよう1ビット付加
1bitパリティ(奇数パリティ):ビットの合計が奇数になるよう1ビット付加

例:バイト 10101011 に偶数パリティ

ビット合計 = 1+0+1+0+1+0+1+1 = 5(奇数)
パリティビット = 1を追加
-> 101010111

問題: 2ビット以上の誤りを検出できない。

CRC(Cyclic Redundancy Check)

多項式除算を使う高速な誤り検出。

元データを多項式として扱い、生成多項式で割った余りをCRCとして付加

種類:

  • CRC-32 : イーサネット、ZIPに使用
  • CRC-16 : 通信プロトコル
  • CRC-8 : 簡易チェック

特性: バースト誤り(連続誤り)に強い。

ハッシュ関数

元データから固定長の「指紋」を生成。完全には復号不可(一方向)。

目的別:

  • 整合性確認 : CRC, MD5, SHA
  • 改ざん検出 : HMAC, SHA-256
  • 認証 : bcrypt, scrypt, Argon2

ハミング符号

単一ビット誤りを自動訂正できる符号。

データ d ビットに対し、パリティ p ビットを付加:

p >= log2(d + p + 1)

例:4ビット データなら3ビット パリティが必要。

受信側:

  1. 各パリティをチェック
  2. エラー位置を特定(0なら誤りなし)
  3. 誤り訂正

用途:DRAM(1ビット誤り自動訂正)

Reed-Solomon符号

複数ビット誤りを訂正可能(QRコード、バーコード)。

元データ:kシンボル
冗長部:n - kシンボル
訂正可能誤り:(n - k) / 2シンボル

QRコードはRS(255, 223) で16シンボル誤り訂正。


ハッシュ関数詳説

MD5とSHA-1(廃止推奨)

MD5

  • 出力:128ビット
  • 衝突脆弱性が発見(2004年)
  • 廃止推奨

SHA-1

  • 出力:160ビット
  • 衝突攻撃が実証(2017年)
  • 2020年代は使用避ける

SHA-256とSHA-3

SHA-256(SHA-2系列)

  • 出力:256ビット
  • 2035年まで安全と見做される
  • NIST推奨
  • ブロックチェーン(Bitcoin)で使用

SHA-3(Keccak)

  • 2015年標準化
  • 256ビット, 512ビット など
  • SHA-2とは独立した設計
  • 急速に採用中

BLAKE3

特徴:

  • 最新(2020年)
  • SHA-3より高速
  • 並列化対応
  • ツリーハッシュモード

暗号化の入口

対称鍵暗号(Symmetric Encryption)

同じ鍵で暗号化・復号化。

AES(Advanced Encryption Standard)

鍵長:128, 192, 256ビット
ブロック長:128ビット
モード:ECB, CBC, CTR, GCMなど

AES-256-GCM(認証付き暗号)が現在推奨。

ChaCha20-Poly1305

鍵長:256ビット
ストリーム暗号 + 認証タグ
TLS 1.3で推奨

非対称鍵暗号(Public Key Encryption)

公開鍵で暗号化、秘密鍵で復号化。

RSA

鍵長:2048, 4096ビット
計算量:大きい整数の因数分解の困難性
用途:デジタル署名、鍵交換

楕円曲線暗号(ECC)

鍵長:256, 384ビット(RSAより短い)
計算量:離散対数の困難性
用途:TLS 1.3(ECDHE)、Bitcoin

ハイブリッド暗号

実務では両方を組み合わせます:

  1. RSA / ECDH で共有鍵を交換(安全だが遅い)
  2. AES / ChaCha20 で本体を暗号化(高速)

TLSプロトコルがまさにこれ。


ベクトル表現と埋め込み

ベクトル表現埋め込み(embedding) は、単語やテキスト、画像を数値ベクトルで表現する手法です。

Word2VecからLLMの埋め込みへ

Word2Vec

2013年にMikolovらが提案。

  • Skip-gram : 単語から周辺語を予測
  • CBOW : 周辺語から単語を予測

結果は300次元ベクトル。

"king" - "man" + "woman""queen"

BERTとTransformer埋め込み

Transformer時代には、コンテキストを考慮した埋め込みが可能。

"bank" の埋め込みが「川の土手」と「金融機関」で異なる

大規模言語モデル(LLM)の埋め込み

GPT-3, GPT-4, Gemini, Claudeなどは、隠れ層の活性化を「埋め込み」として抽出できます。

埋め込み次元:768  4096次元
用途:セマンティック検索、クラスタリング、異常検知

Vector Database

埋め込みの保存・検索に特化したデータベース:

  • Pinecone
  • Weaviate
  • Qdrant
  • Milvus

大規模言語モデルのRAG(Retrieval Augmented Generation)で急速に採用増。


量子情報入門

古典的なビットは0または1ですが、量子ビット(qubit) は重ね合わせ状態を持ちます。

Qubitと重ね合わせ

古典ビット:0または1
Qubit:|0⟩ と |1⟩ の重ね合わせ = α|0⟩ + β|1⟩
       (|α|² + |β|² = 1)

測定時には0か1のどちらかに「崩壊」します。

もつれ(Entanglement)

複数のqubitが「もつれ」状態:

|Ψ⟩ = (1/√2)(|00⟩ + |11⟩)

一方を測定すると、他方の状態も決まる(距離に関わらず)。

量子コンピュータの可能性と課題

可能性:

  • 因数分解(Shorアルゴリズム)
  • 探索(Groverアルゴリズム)
  • 最適化、化学シミュレーション

課題:

  • Decoherence(環境との相互作用で状態が壊れる)
  • エラー率が高い
  • スケーラビリティ

2024年時点で、量子コンピュータはNISQ(Noisy Intermediate Scale Quantum)段階。実用的な量子優位性はまだ限定的。


現在の動向

Neural Compression(AIによる圧縮)

従来:Huffman, LZ77, Deflateなどの決定的アルゴリズム 新動向:ニューラルネットワークで学習した圧縮

CompressAI (Facebook Research)
Joint Autoregressive and Hierarchical Priors
  • JPEGPNGより効率的
  • ただし計算量が多い

量子耐性暗号(Post-Quantum Cryptography)

NISTは2024年に最初の3つの標準を公開し、追加候補の評価も継続しています。

Latticeベース:

CRYSTALS-Kyber(鍵交換)
CRYSTALS-Dilithium(署名)

非Lattice:

SPHINCS+ (tree-based, stateless)

TLSなどへの統合や移行計画の整備が進んでいます。

拡張表示(Extended Reality)と表現

XR(AR, VR, MR)では、

  • ジオメトリ圧縮
  • テクスチャ圧縮(ASTC)
  • リアルタイム再構成

などが重要に。


よくある落とし穴

  • 1文字 = 1バイト と思い込む
  • 浮動小数点を厳密な実数と思い込む
  • UnicodeとUTF-8を同じものだと思う
  • 可逆圧縮と非可逆圧縮を同列に考える
  • 同じビット列なら意味も同じだと思う
  • エンディアンを誤解し、バイナリ互換性の問題を無視する
  • ハッシュ関数で衝突する可能性を無視する
  • 量子コンピュータをすべて変えると勘違いする

発展ルート

深掘りの方向

  • 文字コードを深める : Unicode正規化、合成文字、絵文字、RTL言語
  • 数値表現を深める : IEEE 754の丸め、NaN、例外、任意精度演算
  • メディア表現を深める : JPEG, PNG, MP3, AAC, H.264の内部処理
  • 通信へ進む : パケット、プロトコル、バイトオーダー
  • 暗号化へ進む : 対称鍵、公開鍵、ハイブリッド方式、デジタル署名
  • ベクトル表現へ進む : 埋め込み、セマンティック検索、RAG
  • 量子情報へ進む : アルゴリズム、実装、NISQ応用

次にどこへつながるか

  • 文字コード → Web、DB、ログ基盤
  • 浮動小数点 → 数値計算、統計、機械学習
  • 圧縮 → ネットワーク、メディア、ストレージ
  • シリアライズ → API、分散システム、メッセージング
  • ハッシュ・暗号化 → セキュリティ、ブロックチェーン
  • ベクトル表現 → LLMRAG、検索エンジン
  • 量子情報 → 量子コンピューティング、将来の暗号

何に使うか

  • 文字化けの原因を理解する
  • 金額計算で浮動小数点を避ける理由を理解する
  • 画像や音声のサイズと品質のトレードオフを考える
  • ファイル形式や通信フォーマットを読む土台にする
  • ネットワークプロトコルのバイナリを解析できる
  • 圧縮アルゴリズムの特性を使い分ける
  • セキュリティ脅威を理解する(とりわけハッシュ・暗号化)

何に似ているか

情報表現は、「現実世界を別の言語へ翻訳する辞書」に似ています。ただし、その辞書は曖昧さを極力排し、機械が必ず同じように読める必要があります。


たとえるなら

  • Unicodeは文字の台帳
  • UTF-8はその台帳の内容を箱詰めする方法
  • 浮動小数点は実数の精密な写真ではなく、限られた桁数で描いたスケッチ
  • 圧縮は引っ越しの荷物を詰め直す工夫
  • ハッシュは荷札のID番号
  • 暗号は鍵のかかった箱

小さな題材

  • 同じ文字列をUTF-8とUTF-16で保存してサイズを比べる
  • 0.1 + 0.2 を複数言語で試す
  • PNGJPEGを見比べて圧縮の違いを観察する
  • 同じテキストファイルをgzip, brotli, zstdで圧縮して率を比較
  • CRC-32を手動で計算してみる
  • 簡単な絵文字をUTF-8でダンプしてみる

実務での見方

仕様書を読むとき

情報表現の知識があると、仕様書の

といった語が、ただの細部ではなく「壊れやすい境界」だと見えるようになります。

障害調査で効く場面

  • 文字化け
  • 数値丸めの不一致
  • ファイルが開けない
  • APIの相互運用失敗
  • 圧縮展開エラー
  • ネットワークダンプが読めない

のような不具合は、業務ロジック以前に表現層で起きていることがあります。


実務チェックリスト

  • 文字数制限はbytesではなく必要な単位で見ているか
  • エンコーディングは入出力で統一されているか
  • 金額や厳密小数へ浮動小数点を安易に使っていないか
  • 圧縮方式は用途に合っているか
  • ファイル形式のバージョンやメタデータを確認しているか
  • エンディアン仮定の不一致がないか
  • ハッシュ関数はMD5やSHA-1ではなくSHA-256以上か
  • 量子耐性暗号への移行計画はあるか

補足

第2章 情報の表現

ヒント

「コンピュータは0と1しか扱えない」とよく言われますが、なぜそれで画像も文字も動画も扱えるのか? が本章のテーマです。鍵は「符号化(encoding)」という考え方です。

要点

文字、数値、画像、音はすべてビット列に変換されて扱われます。本章では「表現方法が違うだけで、土台は同じ」という感覚をつくります。

この章が実務で役立つ場面

  • 文字化けやエンコード不整合の調査
  • 浮動小数点誤差による不具合の理解
  • 画像や音声のサイズ・品質・圧縮率の判断

2.1すべてはビットで表す

コンピュータの中では、文字も画像も音も整数も、最終的には0と1の列として扱われます。

【図2】情報の符号化プロセス

flowchart LR A["文字・数・画像・音"] --> B["符号化"] B --> C["ビット列"] C --> D["メモリやストレージに格納"]

2.2 2進数

10進数では10ごとに桁が上がりますが、2進数では2ごとに桁が上がります。

例:

  • 13 (10進) = 1101 (2進)
  • 42 (10進) = 101010 (2進)

2進数が使われるのは、回路が「高い / 低い」「電流が流れる / 流れない」のような二値を扱いやすいからです。

2.3整数と負数

整数は単純にビットへ展開できますが、負数をどう表すかが問題になります。現代のほとんどのコンピュータでは 2の補数表現 が使われます。

2の補数表現の利点:

  • 加算回路をそのまま使いやすい
  • 0の表現が一意
  • 正数と負数を同じ演算器で扱いやすい

具体例:8bit整数

10進 符号なし 2の補数
0 00000000 00000000
1 00000001 00000001
127 01111111 01111111(最大正)
128 10000000 10000000(-128、最小負)
255 11111111 11111111(-1)

-n の求め方:n のビットを全反転して +1。例えば +5=00000101+5 = 00000101 → 反転 11111010+111111011 = -5

オーバーフロー 符号付き演算の結果が表現範囲を超えると、C/C++ ではUndefined Behavior、Javaでは定義済みのwraparoundになる。Rustでは通常の整数演算と wrapping_* 系を分けて考える。INTMAX+1INT_MAX + 1INTMININT_MIN のような値になる現象は、固定ビット幅で桁あふれが起きるためである。

2.3.1浮動小数点数(IEEE 754)

実数は無限の精度を持てないので、IEEE 754標準 で近似する。最もよく使われるのは binary32(単精度、float)と binary64(倍精度、double)。

binary64の構造(64ビット):

| 1bit符号 | 11bit指数 | 52bit仮数 |

値 = (-1)^符号 × (1.仮数)₂ × 2^(指数-1023)

【図29】浮動小数点の落とし穴:

flowchart LR A["0.1 + 0.2"] --> B["binary64に変換"] B --> C["どちらも正確には表せない"] C --> D["0.30000000000000004"] D --> E["== 0.3はfalse"]

金融・科学計算では BigDecimal(Java)、decimal(Python)、Decimal128(MongoDB)を使って精度問題を回避することが多い。

2.3.2エンディアン(バイト順序)

マルチバイト整数をメモリにどう並べるかには2通りある:

  • ビッグエンディアン:上位バイトが先(0x1234567812 34 56 78)
  • リトルエンディアン:下位バイトが先(0x1234567878 56 34 12)

x86/x86-64、ARM(多くは)はリトルエンディアン。ネットワークプロトコル(TCP/IPヘッダ)はビッグエンディアン(network byte order)。移植性のため htonl/ntohl 関数で変換する。

2.4文字コード

文字はそのまま保存できないので、番号を割り当てて表します。

  • ASCII: 英数字中心の古典的な文字集合
  • Unicode: 世界中の文字を扱うための体系
  • UTF-8: Unicodeを実際にバイト列へ落とす代表的な方式

ここで大事なのは、

  • Unicode = 文字の体系
  • UTF-8 = 保存や通信のための符号化方式

という区別です。

もう少し丁寧にいうと、Unicodeは「文字そのものに番号を与える標準」で、UTF-8 / UTF-16 / UTF-32はその番号を実際のビット列やバイト列へ写すための方式です。つまり、

  • Unicodeは辞書
  • UTF-8などは保存形式

という関係です。

さらに重要なのは、文字見た目 は別だという点です。たとえば A という文字と、その文字を画面にどう描くかは別問題です。標準が扱うのは「どの文字か」という意味であり、フォントが扱うのは「どう描くか」という見た目です。

【図3】文字から画面表示までの流れ:

flowchart LR A["文字という意味"] --> B["Unicode code point"] B --> C["UTF-8 / UTF-16 / UTF-32"] C --> D["バイト列"] D --> E["フォントと描画エンジン"] E --> F["画面上の字形"]

この区別がわかると、

  • なぜ同じ文字でもフォントで見た目が違うのか
  • なぜ「1文字 = 1バイト」とは限らないのか
  • なぜ文字数カウントや文字切り出しが意外に難しいのか

が自然に見えてきます。

2.5画像・音の表現

画像

  • 画像はピクセルの集まり
  • 各ピクセルに色の値を持つ
  • RGBなら赤・緑・青の強さで表す

  • 音は時間ごとの振幅のサンプル列
  • サンプリング周波数が高いほど細かい
  • ビット深度が大きいほど表現の幅が広い

つまり、連続的に見えるものもコンピュータでは離散的に刻んで扱います。

2.6圧縮

データはそのままでは大きいので、圧縮されることがあります。

  • 可逆圧縮: 元に完全に戻せる 例: ZIP, PNG
  • 非可逆圧縮: 一部を捨てて小さくする 例: JPEG, MP3

2.6.1 「表現」と「意味」は別問題

同じビット列でも、どう読むかによって意味は変わります。

  • 整数として読めば数値
  • UTF-8として読めば文字
  • 命令列として読めばCPU命令
  • 画像の一部として読めば色の情報

つまり、コンピュータの中に最初から「これは文字」「これは音」と書いてあるわけではありません。意味は、どの規約で解釈するか によって決まります。

flowchart LR A["同じビット列"] --> B["整数として解釈"] A --> C["文字として解釈"] A --> D["命令として解釈"] A --> E["画像データとして解釈"]

この視点があると、

  • 文字コードの不一致
  • ファイル形式
  • バイナリ互換性
  • ネットワークプロトコル

の理解がかなり楽になります。

2.7概念の見分け方

概念 何をしているか 混同しやすいもの 違い
Unicode 文字の体系 UTF-8 UTF-8は保存形式
2進数 数の表現 ビット列 ビット列は意味づけ前でもよい
可逆圧縮 元に戻せる圧縮 非可逆圧縮 情報を捨てない
サンプリング 時間方向の細かさ ビット深度 ビット深度は1点ごとの細かさ

2.8よくある誤解

よくある誤解

ビット列は最初から意味を持つわけではありません。同じビット列でも、「整数として読むか」「文字列として読むか」「命令として読むか」で意味が変わります。

2.9例題

【図4】情報の符号化・復号の手順:

flowchart LR A["対象を決める"] --> B["どう符号化するか考える"] B --> C["ビット列に変換"] C --> D["人間の意味に戻して確認"]

例題1: 10進数 11 を2進数で表せ。

解説: 11=8+2+111 = 8 + 2 + 1 なので

1110=1011211_{10} = 1011_2

です。

例題2: A という文字を保存するとき、なぜ文字コードが必要か。

解説: コンピュータは文字そのものを保存できず、番号に変換して保存する必要があるからです。

例題3: PNGJPEGの違いを一文で述べよ。

解説: PNGは主に可逆圧縮、JPEGは主に非可逆圧縮です。

仕様と実装の補足

Unicode Standard - 文字符号化の統一体系

Unicode 15.0と拡張: unicode.org(https://unicode.org/)は、世界中の文字・シンボルを統一的に符号化するUnicode標準を管理しています。以下の概念が定義されています:

  • Code Point: 各文字に割り当てられた番号(U+0000からU+10FFFFまで、17個のPlane)
  • Planes: 文字群を65,536文字ごとのグループに分割
    • BMP (Basic Multilingual Plane): U+0000-U+FFFF (ほとんどの現代言語)
    • SMP (Supplementary Multilingual Plane): U+10000-U+1FFFF (古代文字、象形文字、絵文字等)
  • Normalization: 同じ文字でも複数の符号化方式(NFC, NFD, NFKC, NFKD)をサポート
  • Bidirectional Text: アラビア語・ヘブライ語等、右から左へ書く言語への対応

UTF-8とメモリ効率: Unicode文字のバイト表現には複数の方式(UTF-8, UTF-16, UTF-32)がありますが、UTF-8は可変長(1~4バイト)であり、ASCII互換性を保ちつつメモリ効率的です。本セクションのテキスト処理で取り上げたエンコーディング変換は、このUnicode標準に基づいています。

版管理: Unicodeは年1回のリリースサイクルを採用しており、新しい言語・絵文字・記号が段階的に追加されています。2024年版では、新しい絵文字700個以上が追加されました。

NIST Cryptographic Standards

FIPS (Federal Information Processing Standards): CSRC.nist.gov(https://csrc.nist.gov/)はアメリカ国立標準技術研究所(NIST)が管理する暗号標準の公式リポジトリです。以下の重要な標準が含まれています:

  • FIPS 180-4: SHA(Secure Hash Algorithm)ファミリー
    • SHA-1: 160ビットハッシュ(現在は非推奨)
    • SHA-256: 256ビットハッシュ(最も一般的)
    • SHA-512: 512ビットハッシュ(高セキュリティ)
  • FIPS 186-5: ECDSA(楕円曲線デジタル署名アルゴリズム)
  • FIPS 197: AES(Advanced Encryption Standard)、ブロック暗号の標準
  • FIPS 202: SHA-3(新世代ハッシュ関数)

検証と準拠: これらのFIPS標準に準拠した実装は、暗号モジュール検証プログラム(CMVP)による認定が受けられ、政府機関やセキュリティ要件の高い企業での使用が可能になります。

脆弱性の発表: NISTは既知の暗号脆弱性(例: MD5のプリイメージ攻撃)についての公式見解を発表し、業界に推奨される移行パスを提供しています。

IEEE Standards - データ表現の規格化

IEEE 754浮動小数点数: IEEE Xplore(https://ieeexplore.ieee.org/)が管理するIEEE 754標準は、本セクションで説明した浮動小数点数の内部表現を定義しています:

  • 符号ビット: 数値の正負
  • 指数部: スケール(2の何乗か)
  • 仮数部: 有効数字

丸め規則: IEEE 754は複数の丸め規則(Round to Nearest, Round Toward Zero, Round Up/Down)を定義しており、異なるアーキテクチャ間での計算結果の一貫性を保証します。

NaN と Infinity: 浮動小数点数における「非数」(NaN)と「無限大」(Infinity)の表現・比較挙動は、IEEE 754で厳密に定義されています。

Opus Audio Codec - 音声符号化の最新標準

RFC 6716 Opus仕様: opus-codec.org(https://opus-codec.org/)およびRFC 6716は、現代の音声符号化を定義する国際標準です。以下の特徴があります:

  • 適応的ビットレート: ネットワーク帯域幅に応じて品質を自動調整(6~510 kbps)
  • 低遅延: 音声通話向けの5ms単位での符号化
  • 楽曲対応: 音楽配信向けに最適化された符号化モード
  • ロイヤリティフリー: 実装・配布に特許ロイヤリティ不要

WebRTCでの標準化: WebブラウザのリアルタイムメディアストリーミングAPIであるWebRTCは、音声コーデックとしてOpusを標準採用しており、VoIPアプリケーション、ビデオ会議、オンラインゲームの通信基盤となっています。

符号化プロセス: Opus内部では、低周波数成分をFOURIER解析し、高周波成分を心理音響学(Perceptual Audio Coding)に基づいて圧縮しており、人間が認知困難な周波数帯を効率的に削減します。

AOM (Alliance for Open Media) Codec

AV1ビデオコーデック: aomediacodec.org(https://aomediacodec.org/)が管理するAV1はビデオ符号化の最新標準です。以下の特徴があります:

  • H.265(HEVC)との比較: H.265比で30~50%の圧縮率向上
  • オープン標準: ロイヤリティフリー、パテントプール不要
  • ハードウェア対応: Google、Apple、Intel等による商用チップ実装が進行中
  • 適応的ストリーミング: YouTube、Netflix等のコンテンツ配信で採用

符号化のアルゴリズム: 動画フレーム間の差分検出、モーション予測、周波数領域変換(DCT)はAV1の中核アルゴリズムであり、世代ごとの複雑度向上を体現しています。

実装の複雑性: AV1エンコーダーは高い計算量を要するため、ハードウェアエンコーディング(Intel Quick Sync、NVIDIA NVENC等)の支援が必須となります。

Oracle Database - データ型表現

SQL標準とバイナリ表現: docs.oracle.com(https://docs.oracle.com/)が提供するOracle Databaseドキュメントには、リレーショナルデータベースのデータ型と内部表現が詳細に説明されています:

  • NUMBER型: 可変長浮動小数点数フォーマット、桁数・精度の指定
  • VARCHAR2: 文字列の最大長とキャラクタセット(UTF-8等)
  • BLOB/CLOB: バイナリ・テキスト大容量データのストレージ形式
  • DATE/TIMESTAMP: 日時データの内部表現、タイムゾーン対応

ストレージ効率: Oracleの内部表現では、NULLや固定長フィールドをビット単位で圧縮し、ディスク容量とI/Oパフォーマンスを最適化する設計が採られています。

暗号ハッシュ関数とセキュリティ

SHA-256 の内部アルゴリズム: SHA-256 は以下のステップで 256ビット(32バイト)の出力を生成します:

  1. Pre-processing: メッセージをパディングして 512ビット単位のブロックに分割
  2. Compression Function: 64 ラウンドで各ブロックを処理、内部状態を更新
  3. Output: 最終的な 8つの 32ビット値を連結

NIST FIPS 180-4 仕様により、全ての実装がこの手順を厳密に従うことで、異なるプログラミング言語・プラットフォームでも同じハッシュ値が得られます。

衝突耐性と一方向性: ハッシュ関数の安全性は以下の特性により定義されます:

  • 衝突耐性: 異なる入力で同じハッシュが得られることが計算上困難
  • 一方向性: ハッシュ値から元の入力を逆算できない
  • アバランシェ効果: 入力が 1ビット変わるだけで、出力の約 50% のビットが変わる

SHA-1の脆弱性: SHA-1 は 2017年に Google が初の衝突例(shattered.io)を報告し、NIST は非推奨化しました。SHA-256 や SHA-3 への移行が推奨されています。

楕円曲線暗号 (ECC) と ECDSA

楕円曲線上の点演算: ECDSA (Elliptic Curve Digital Signature Algorithm)の強力さは、以下の数学に基づいています:

  • 楕円曲線: y² = x³ + ax + b 形式の方程式
  • 点加算: 曲線上の 2点を加算する演算が群構造を形成
  • スカラー倍算: G を初期点として、n × G を計算することで秘密鍵から公開鍵を生成

離散対数問題: n × G = Q という関係で、G と Q から n を求めることが計算上困難であることが ECC の安全性の基盤です。これは RSA の因数分解問題と異なる数学的困難性です。

AES 暗号とブロック暗号モード

AES の内部構造: FIPS 197 仕様による AES-128/192/256 は、以下のステップを 10~14 ラウンド反復実行します:

  1. SubBytes: 各バイトを S-box で非線形変換
  2. ShiftRows: 行シフト(拡散)
  3. MixColumns: 列混合(拡散)
  4. AddRoundKey: ラウンド鍵との XOR

ECB vs CBC vs CTR: ブロック暗号のモード(Mode of Operation)により、同じ AES でも以下の特性が異なります:

  • ECB (Electronic Codebook): 同じ平文ブロックは同じ暗号文を生成(脆弱)
  • CBC (Cipher Block Chaining): 前ブロックの暗号文を次ブロックに使用(IVが必須)
  • CTR (Counter Mode): 初期化ベクタ + カウンタをAES暗号化してワンタイムパッドを生成(ストリーム暗号化)

NIST ガイダンスと実装

セキュリティレベルの定義: NIST SP 800-57 では、以下のセキュリティレベルが定義されています:

  • Level 1: < 80 bits (玩具レベル)
  • Level 2: 80~112 bits (短期秘密)
  • Level 3: 112~128 bits (一般用途)
  • Level 4: 128~192 bits (高度な暗号化)
  • Level 5: > 192 bits (国家レベル)

実装者はこのガイダンスに従い、適切な鍵長・アルゴリズムを選定します。

オーディオ・ビデオコーデックの心理音響学

Opus の周波数分割: Opus は、以下のアルゴリズムにより圧縮を実現します:

  • 時間領域分析: SILK フレームワーク(低周波数、< 8 kHz)
  • 周波数領域分析: CELT フレームワーク(高周波数)
  • 心理音響フィルタリング: 人間が聞き取りにくい周波数帯を削減

Bit Allocation: Opus は周波数帯ごとに必要なビット数を動的に割り当て、最大 510 kbps の制約内で効率的に圧縮します。

AV1 ビデオコーデックの符号化戦略

フレーム分割と予測: AV1 内部では以下のプロセスで動画圧縮が実現されています:

  1. フレーム型の決定: I フレーム(独立)、P フレーム(前フレーム参照)、B フレーム(双方向参照)
  2. ブロック分割: 64×64 スーパーブロックを可変サイズに分割
  3. 動き推定: 最適なモーションベクトルを探索
  4. 残差圧縮: 予測誤差を周波数変換(DCT)で圧縮

エンコーディング複雑性: AV1 は高い計算量を要するため、ハードウェアエンコーディングが必須です。

イーサネットとパケット表現

MAC アドレス(物理層): MAC アドレスは 48ビット(6バイト)であり、以下の構造を持ちます:

  • 最初の 24ビット: OUI (Organizationally Unique Identifier) - メーカー固有
  • 後の 24ビット: 各メーカーが付与するデバイス固有号

IP アドレス(ネットワーク層): IPv4 は 32ビット(4オクテット)で表現され、CIDR 記法(192.168.0.0/24)によりサブネットを定義します。

まとめ

情報の表現は、文字・数値・画像・音をビット列へ写す規約の理解が土台になります。表現と意味を切り分けて考えると、文字コード、浮動小数点、圧縮、ファイル形式、暗号ハッシュ、ネットワーク上のアドレス表現がひとつながりに見えてきます。

参考文献

公式・標準

解説・補助