情報の表現

概要

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

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

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

この章で重視すること

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

目次

  1. 情報表現の全体像
  2. ビットとバイト
  3. 2進数と整数表現
  4. 浮動小数点数
  5. エンディアン
  6. 文字コード
  7. 画像と音の表現
  8. 圧縮
  9. データ形式とシリアライズ
  10. エラー訂正とハッシュ
  11. 暗号化の入口
  12. ベクトル表現と埋め込み
  13. 量子情報入門
  14. 2026年の動向
  15. よくある落とし穴
  16. 発展ルート
  17. 参考文献

情報表現の全体像

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

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)

PNG と WebP は 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)段階。実用的な量子優位性はまだ限定的。


2026年の動向

Neural Compression(AI による圧縮)

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

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

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

NIST が 2022年に 4 つの標準化アルゴリズムを選定。

Lattice ベース:

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

非 Lattice:

SPHINCS+ (tree-based, stateless)

2026 年以降、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、分散システム、メッセージング
  • ハッシュ・暗号化 → セキュリティ、ブロックチェーン
  • ベクトル表現 → LLM、RAG、検索エンジン
  • 量子情報 → 量子コンピューティング、将来の暗号

何に使うか

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

何に似ているか

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


たとえるなら

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

小さな題材

  • 同じ文字列を UTF-8 と UTF-16 で保存してサイズを比べる
  • 0.1 + 0.2 を複数言語で試す
  • PNG と JPEG を見比べて圧縮の違いを観察する
  • 同じテキストファイルを 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: PNG と JPEG の違いを一文で述べよ。

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

2.10 練習問題

  1. 1001_2 を10進数へ直せ。
  2. Unicode と UTF-8 の違いを述べよ。
  3. サンプリング周波数が上がると、何が細かくなるか。
  4. 可逆圧縮が向いているデータの例を1つ挙げよ。

2.11 練習問題の答え

  1. 9
  2. Unicode は文字体系、UTF-8 はその符号化方式
  3. 時間方向の表現
  4. 例: ソースコード、文書、ロゴ画像

まとめ

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