小数点の位置を固定して数値を表現する方式。整数部と小数部のビット配分で精度と範囲が決まります。
私たちは「11.75」のように小数点を使って数を書きますが、コンピュータの中には小数点という記号は存在しません。あるのは0と1の列だけです。固定小数点数は、「ここに小数点がある」と事前に場所を決めておくことで、0と1だけで小数を表現する方法です。たとえば「上位4ビットが整数部、下位4ビットが小数部」と決めておけば、8ビットで小数を扱えます。
具体例を見てみましょう。整数部4ビット・小数部4ビットで 1011.1100 という値の場合:
- 整数部: 1×8 + 0×4 + 1×2 + 1×1 = 11
- 小数部: 1×0.5 + 1×0.25 + 0×0.125 + 0×0.0625 = 0.75
- 合わせて 11.75
小数部の各ビットの重みは 0.5, 0.25, 0.125, 0.0625... と半分ずつ小さくなっていきます。整数部が 1, 2, 4, 8... と2倍ずつ大きくなるのと対称的です。
重要なのは、メモリには 10111100 というただの8ビットの整数が入っているだけということです。「4ビット目と5ビット目の間に小数点がある」というのはプログラマー同士の約束事であり、ハードウェア的には普通の整数と区別がつきません。上のツールでスライダーを動かすと、値がどのようにビットに変換されるか確認できます。
合計16ビットを持っているとして、整数部と小数部にどう分けるか? これが固定小数点で最も重要な設計判断です。日常に例えると、お小遣い帳に「千円の位まで書くか、1円の位まで書くか」を決めるのと似ています。桁数が同じなら、大きい単位を書くほど大きな金額を扱えますが、細かい金額は書けなくなります。
具体的な数字で比較してみましょう。
- 整数12ビット + 小数4ビット → 最大値は約4095、でも小数の刻みは0.0625(かなり粗い)
- 整数4ビット + 小数12ビット → 最大値は15しかないが、小数の刻みは0.000244(とても細かい)
同じ16ビットなのに、配分次第で全く違う性質になります。温度センサー(範囲は狭いが精度が要る)と距離計(範囲は広いが粗くてOK)で最適な配分は異なります。
上のツールで整数部・小数部のスライダーを動かすと、最大値と解像度(最小の刻み幅)がどう変化するか試せます。ビット配分を変えると数直線上の点の密度が変わる様子を確認してみてください。
これまで説明した固定小数点数は「0以上の数だけ」(=符号なし・unsigned)を扱うものでした。しかし温度(−10℃)や音声の振幅(プラスにもマイナスにも振れる)など、負の数も必要な場面では「符号あり(signed)」固定小数点を使います。
最上位ビット(先頭1ビット)を符号ビットとして使うのが基本的なやり方です。
・符号ビット = 1:負の数
・符号ビット = 0:正の数(または0)
符号ビットを1ビット使うと、その分だけ数値を表すビット数が減ります。たとえば8ビットのうち1ビットを符号に割くと、残り7ビットで数値を表します。負の数の内部表現には「2の補数」という方式がよく使われます。これは「ビットを全部反転して1を足す」方法で、コンピュータの加算回路をそのまま使って引き算もできるという利点があります。身近な例では、エアコンの温度設定(−30〜+30℃)や音声ファイルの波形データなど、日常の多くの場面で符号あり固定小数点が使われています。
| 項目 | 固定小数点 | 浮動小数点 |
|---|---|---|
| 小数点の位置 | 固定 | 動的(指数で指定) |
| 表現範囲 | 狭い | 非常に広い |
| 精度 | 一定 | 値によって変動 |
| 計算速度 | 高速(整数演算) | やや遅い(専用回路必要) |
| 主な用途 | 組込み・DSP・金融 | 科学計算・一般用途 |
固定小数点数と浮動小数点数の一番の違いは「精度が一定かどうか」です。固定小数点は、0.001でも1000でも同じ刻み幅(例えば0.0625)で値を表します。どこでも同じ精度なので計算結果が予測しやすく、バグを見つけやすいのが利点です。
一方、浮動小数点(IEEE 754)は小数点が「浮動」するため、小さい数は細かく、大きい数は粗く表現します。たとえば1.0の近くでは0.0000001刻みですが、1000万の近くでは1刻みになります。非常に広い範囲の数を扱えますが、「大きい数を足した後に小さい数を引くと精度が消える」といった落とし穴があります。
まとめると、「狭い範囲を一定の精度で正確に」が固定小数点、「広い範囲を柔軟にカバー」が浮動小数点です。
固定小数点の最大値と精度は、整数部と小数部のビット数から簡単に計算できます。最大値は「整数部で表せる最大の整数 + 小数部で表せる最大の小数」です。解像度(最小の刻み幅)は小数部の一番右のビットの重みで決まります。
整数部4ビット・小数部4ビットの場合で計算してみましょう。
- 整数部の最大値: 2の4乗 - 1 = 15
- 小数部の最大値: 1 - 2の-4乗 = 1 - 0.0625 = 0.9375
- 合計の最大値: 15 + 0.9375 = 15.9375
- 解像度: 2の-4乗 = 0.0625
つまり0, 0.0625, 0.125, ... 15.875, 15.9375 の256段階の値しか表現できません。0.1のようにこの刻みに乗らない値は、最も近い値に丸められます。
上のツールでスライダーを動かすと、これらの値がリアルタイムで計算されます。色々な配分を試して、最大値と解像度がどうトレードオフになるか感覚をつかんでください。
「整数部8ビット、小数部8ビットの固定小数点」を毎回書くのは面倒なので、Qフォーマットという短い書き方があります。Q8.8 と書けば「整数部8ビット・小数部8ビット」を意味します。DSP(デジタル信号処理)やゲーム開発の現場でよく使われる表記です。
よく使われるQフォーマットの例:
- Q8.8(16ビット): 最大値 255.996、刻み 1/256 ≈ 0.004。センサーデータの処理に
- Q16.16(32ビット): 最大値 約65535、刻み 1/65536 ≈ 0.00002。高精度な制御に
- Q1.15(16ビット): 最大値 約1.0、刻み 1/32768。音声信号処理に(振幅を-1.0〜+1.0で扱う)
プログラムでの実装はとてもシンプルです。Q8.8で3.5を表すには、3.5 × 256 = 896 を普通のint型変数に入れるだけ。読み出すときは 896 ÷ 256 = 3.5 に戻します。この「固定倍率で整数にする」テクニックにより、小数点計算の専用回路(FPU)がない安いマイコンでも、整数の足し算・引き算だけで小数計算ができます。
「今どき固定小数点なんて使うの?」と思うかもしれませんが、身の回りの電子機器の多くが固定小数点で動いています。Bluetoothイヤホンの音声デコード、エアコンの温度制御、車のエンジン制御、ゲーム機のグラフィック処理。これらに使われるマイコンの多くは浮動小数点計算の専用回路(FPU)を持っていないため、固定小数点が唯一の選択肢です。
固定小数点が選ばれる理由は3つあります。
- 速度: 内部的には整数の足し算・掛け算と同じなので、FPUを使う浮動小数点より何倍も高速。音声処理のように毎秒何万回も計算する場面で効きます
- 省電力: FPU回路が不要な分、チップが小さく消費電力が少ない。電池駆動のIoTセンサーには必須
- 予測可能な精度: どんな値でも同じ刻み幅なので、「この計算で最大どれだけ誤差が出るか」を事前に正確に見積もれる。安全性が重要な車の制御に適しています
金融系でも固定小数点の考え方が使われます。浮動小数点では 0.1 + 0.2 ≠ 0.3 という丸め誤差が発生しますが、「1円 = 100」と決めて整数で計算すれば正確です。