
固定小数点演算をPythonで実装する|小数を"整数のまま"扱うハードの技
2026-09-25 ・ 実践
小さなマイコンやDSP、AIアクセラレータの一部は、コストや電力のために浮動小数点回路を持ちません。それでも小数を扱うために使うのが 固定小数点。整数演算だけで小数を計算する技をPythonで実装します。低レイヤやハードウェア設計で必須の考え方です。
発想:整数を"何倍か"して使う
固定小数点は「小数点の位置を固定で決めておく」方式。例えば「常に256倍した整数」として扱えば、3.5は 3.5 × 256 = 896 という整数で表せます。演算は普通の整数演算、表示のときだけ256で割る——これだけです。
準備
Python標準機能だけ。
① Qフォーマットで小数を整数化
「Q8」=小数部8ビット(256倍)で実装します。
SCALE = 256 # 2^8(小数部8ビット = Q8)
def to_fixed(x): return round(x * SCALE) # 実数 → 固定小数点整数
def to_float(q): return q / SCALE # 固定小数点整数 → 実数
a = to_fixed(3.5)
b = to_fixed(1.25)
print("3.5 =", a, " 1.25 =", b) # 896 320
② 足し算・掛け算
足し算はそのまま。掛け算は「256×256倍」になるので、後で256で割って戻します。
def fixed_add(a, b):
return a + b # スケールが同じなのでそのまま
def fixed_mul(a, b):
return (a * b) // SCALE # 掛けると2乗倍 → 割って戻す
s = fixed_add(to_fixed(3.5), to_fixed(1.25))
m = fixed_mul(to_fixed(3.5), to_fixed(1.25))
print("3.5 + 1.25 =", to_float(s)) # 4.75
print("3.5 × 1.25 =", to_float(m)) # 4.375
出力は 4.75 と 4.375。整数演算だけで小数計算ができました。浮動小数点回路がなくても、シフトと整数の加減乗で済むのが利点です。
③ 丸め誤差を見る
小数部のビット数で精度が決まります。表せない値は近い値に丸められます。
x = 0.1
q = to_fixed(x)
print(f"0.1 → 整数 {q} → 戻すと {to_float(q)}") # 0.1 → 26 → 0.1015625
print("誤差:", to_float(q) - x)
0.1 はQ8では正確に表せず、わずかな誤差が出ます。ビット数を増やせば精度は上がるが、桁(メモリ・回路)が増えるというトレードオフ。用途に応じて小数部の幅を決めます。
AIの量子化にも通じる
近年のAIアクセラレータは、計算を軽くするため32bit浮動小数点でなく8bit整数(固定小数点に近い)で推論します(量子化)。「精度を少し犠牲に、速度と省電力を取る」——固定小数点の発想そのものが、最新のAIチップでも生きています。
オーバーフローに注意
掛け算は一時的に桁が大きく増えるため、途中でビット幅を超えると値が壊れます(2の補数のオーバーフロー)。固定小数点では「途中結果の桁数」を常に意識し、必要なら広いビット幅で計算します。
まとめ
- 固定小数点は小数を「一定倍した整数」として扱う
- 足し算はそのまま、掛け算は割り戻す(スケール調整)
- 浮動小数点回路がなくても整数演算で小数計算できる
- 精度とビット幅のトレードオフ。AIの量子化にも通じる発想
もう少し詳しく(背景と理論)
固定小数点は、小数点の位置をあらかじめ固定して整数として扱う数値表現です。整数演算器だけで小数を扱えるため、浮動小数点ユニットを持たない組み込み・DSP・FPGA・ASIC で電力と面積を大きく節約できます1。表記には Q フォーマット(例:Q15 は符号1bit+小数15bit)がよく使われ、整数部と小数部のビット配分で表せる範囲と分解能が決まります2。設計上の要は、限られたビット幅で生じる量子化誤差と、桁あふれ(オーバーフロー)の管理です——飽和演算やスケーリングで対処します3。浮動小数点より扱いは面倒ですが、決定論的で高速なため、ニューラルネット推論の量子化など現代の省電力AIでも重要な技術です。
次の一歩 🌸
数の基礎は2進数と2の補数、加算器は4ビット加算器、AIチップはAIチップとHBMへどうぞ。