100本ノック / 数値計算 / 数値計算100本ノック
製造業の数値計算入門|浮動小数点と誤差をPythonで学ぶ10本ノック
製造KPIの誤差を見抜く:浮動小数点数と数値計算の実務基礎10本ノック
製造現場では、センサー値、原価、歩留まり、設備稼働率などをコンピューターで集計し、その結果を品質判定や投資判断に使います。しかし、コンピューター上の数値は数学上の実数そのものではありません。本Notebookでは、数値の表現限界を理解し、誤差による誤判定を防ぐための基礎を、架空の精密部品工場を題材に確認します。
本シリーズ「製造業の意思決定に活かす数値計算100本ノック」は、浮動小数点数から方程式、線形代数、補間、微積分、微分方程式、最適化までを、現場の判断と結び付けて段階的に学ぶ全100問です。初回は、その土台となる No.001〜No.010 を扱います。
[!NOTE] 本資料は、数理工房 (もしくは代表である和山個人) が過去に企業研修において使用した notebook を企業様の許可を得て再構成・編集のうえ公開しています。
掲載データはすべて架空のものであり、実在する企業・工場・数値とは一切関係ありません。
1. はじめに:この記事で扱う製造業の実務課題
精密部品工場では、寸法公差が数 µm、材料使用量が数百万個分、設備ログが秒単位というように、大小の数値を同時に扱います。本記事の課題は、計算式が理論上正しくても、数値表現と演算順序のために集計値がずれ、合否・異常・採算の判定が変わり得ることです。
2. 現場でよくある状況
- Excel、PLC、データベース、Pythonで表示桁やデータ型が異なる
0.1 + 0.2のような単純な計算でも内部値が期待と一致しない- 巨大な累積値へ微小な補正を加えても反映されない
- 近い測定値の差を取ったところ、有効桁が失われる
- 正解値の桁が大きいだけで「誤差が大きい」と誤解する
3. なぜこの問題は判断が難しいのか
画面では丸めて表示されるため、内部誤差は見えにくい一方、閾値判定では微小差が結論を変えます。また、絶対誤差と相対誤差のどちらを見るべきかは用途によって異なります。品質保証では単位・分解能・許容差を含め、計算方法と判定ルールを設計する必要があります。
4. 今回扱うノックの全体像
| No. | テーマ | 製造業での主な論点 |
|---|---|---|
| 001 | 数値計算とは何か | 理論値・近似値・意思決定の関係 |
| 002 | 浮動小数点表現 | 表示値と内部値の違い |
| 003 | IEEE 754 | データ型、符号・指数・仮数 |
| 004 | 丸め誤差 | 金額や集計の丸め方 |
| 005 | 桁落ち | 近い測定値の差分 |
| 006 | 情報落ち | 大きな累積値への微小加算 |
| 007 | オーバーフロー | 指標やモデル計算の発散 |
| 008 | アンダーフロー | 微小確率の消失 |
| 009 | 機械イプシロン | 計算機で識別できる最小差 |
| 010 | 数値誤差の評価 | 絶対誤差・相対誤差と許容基準 |
5. Python 環境の準備
外部データには依存せず、NumPy、pandas、matplotlibで再現します。乱数シードは固定し、同じ結果が得られるようにします。
import sys
import numpy as np
import pandas as pd
import matplotlib
import matplotlib.pyplot as plt
import japanize_matplotlib
SEED = 42
rng = np.random.default_rng(SEED)
pd.set_option("display.precision", 10)
print(f"Python : {sys.version.split()[0]}")
print(f"NumPy : {np.__version__}")
print(f"pandas : {pd.__version__}")
print(f"matplotlib : {matplotlib.__version__}")
Python : 3.13.1
NumPy : 2.5.1
pandas : 3.0.3
matplotlib : 3.11.0
6. 架空データの作成
公称寸法 50.000 mm、公差 ±0.010 mm のシャフトを1,000本測定した想定です。測定器の表示分解能は 0.001 mm とし、内部の真値に近い値と表示値を両方保持します。さらに、原価集計用の数量と単価を作ります。
n = 1_000
measurement_raw = 50.0 + rng.normal(0, 0.004, n)
measurement_display = np.round(measurement_raw, 3)
factory_df = pd.DataFrame({
"lot": np.repeat(["L-A", "L-B", "L-C", "L-D"], n // 4),
"measurement_raw_mm": measurement_raw,
"measurement_display_mm": measurement_display,
"quantity": rng.integers(80, 151, n),
"unit_cost_yen": rng.uniform(118.0, 123.0, n),
})
factory_df.head()
| lot | measurement_raw_mm | measurement_display_mm | quantity | unit_cost_yen | |
|---|---|---|---|---|---|
| 0 | L-A | 50.0012188683 | 50.001 | 93 | 120.4056155088 |
| 1 | L-A | 49.9958400636 | 49.996 | 125 | 121.9110559763 |
| 2 | L-A | 50.0030018048 | 50.003 | 108 | 121.7399506448 |
| 3 | L-A | 50.0037622589 | 50.004 | 104 | 122.0753654811 |
| 4 | L-A | 49.9921958592 | 49.992 | 129 | 120.2412031659 |
7. No.001:数値計算とは何か
実務での意味
数値計算は、解析的な式を眺めるだけでなく、有限の桁数で近似値を求め、現場の判断に使える形へ変換する手続きです。たとえば平均寸法は、全測定値の総和を本数で割ることで求めますが、データ型、欠損処理、丸め、許容差まで決めなければ品質判定にはなりません。
分析・モデル化の考え方
測定値を とすれば、平均は
です。数値計算では、入力誤差、アルゴリズムによる近似誤差、有限精度の丸め誤差が結果へ伝播します。目的は「真値を完全に再現すること」ではなく、意思決定に必要な精度を保証することです。
Pythonで確認する
summary_001 = factory_df["measurement_raw_mm"].agg(["count", "mean", "std", "min", "max"])
summary_001.to_frame("測定値 (mm)")
| 測定値 (mm) | |
|---|---|
| count | 1000.0000000000 |
| mean | 49.9998844338 |
| std | 0.0039568684 |
| min | 49.9854063487 |
| max | 50.0127154147 |
結果の読み取り
平均だけでなく標準偏差と範囲を併記すると、工程中心とばらつきを分けて判断できます。数値計算の結果は単独の数字ではなく、単位、計算条件、判定目的とセットで管理することが重要です。
8. No.002:浮動小数点表現
実務での意味
多くの小数は2進数で有限桁に表せません。そのため、原価の加算や閾値との比較では、表示上は同じでも内部値がわずかに異なることがあります。
分析・モデル化の考え方
浮動小数点数は概念的に、符号 、仮数 、基数 、指数 を用いて
と表します。Pythonの通常の float は基数2の倍精度です。10進小数の厳密な金額計算には、整数(銭など)や decimal.Decimal も選択肢です。
Pythonで確認する
from decimal import Decimal
floating = 0.1 + 0.2
exact_decimal = Decimal("0.1") + Decimal("0.2")
pd.DataFrame({
"計算方法": ["binary64 float", "Decimal(文字列から生成)"],
"結果": [format(floating, ".17f"), str(exact_decimal)],
"0.3と一致": [floating == 0.3, exact_decimal == Decimal("0.3")],
})
| 計算方法 | 結果 | 0.3と一致 | |
|---|---|---|---|
| 0 | binary64 float | 0.30000000000000004 | False |
| 1 | Decimal(文字列から生成) | 0.3 | True |
結果の読み取り
float の結果は 0.3 の近傍ですが、厳密一致しません。センサー処理では許容差付き比較、会計では10進型や最小通貨単位の整数化など、目的に合う表現を選びます。
9. No.003:IEEE 754
実務での意味
装置、データベース、分析基盤の間で float32 と float64 が混在すると、保存容量だけでなく有効桁と演算結果が変わります。インターフェース仕様にデータ型を明記する必要があります。
分析・モデル化の考え方
IEEE 754の代表的な2進形式では、float32 は1符号ビット・8指数ビット・23仮数部ビット、float64 は1・11・52です。正規化数には暗黙の先頭1があるため、有効精度はそれぞれ24ビット、53ビット相当です。
Pythonで確認する
rows = []
for dtype in [np.float32, np.float64]:
info = np.finfo(dtype)
rows.append({
"型": dtype.__name__, "bytes": info.bits // 8,
"10進有効桁の目安": info.precision,
"最大値": info.max, "最小正規化正数": info.tiny,
})
pd.DataFrame(rows)
| 型 | bytes | 10進有効桁の目安 | 最大値 | 最小正規化正数 | |
|---|---|---|---|---|---|
| 0 | float32 | 4 | 6 | 3.4028234664e+38 | 1.1754943508e-38 |
| 1 | float64 | 8 | 15 | 1.7976931349e+308 | 2.2250738585e-308 |
結果の読み取り
float32 は省メモリですが、おおむね7桁程度の精度です。長期累積値や高精度測定では不足し得ます。必要精度、データ量、計算速度を基に型を決め、変換箇所をテストします。
10. No.004:丸め誤差
実務での意味
部品ごとに原価を1円単位へ丸めてから合計する場合と、合計後に丸める場合では結果が変わります。見積、標準原価、請求のルールは計算順序まで統一すべきです。
分析・モデル化の考え方
丸め演算を とすると、一般に
です。また、二進浮動小数点表現の近似誤差と、業務ルールとしての10進丸めを区別します。
Pythonで確認する
line_cost = factory_df["quantity"] * factory_df["unit_cost_yen"]
rounding_comparison = pd.Series({
"明細ごとに1円丸め後、合計": np.round(line_cost, 0).sum(),
"丸めず合計後、1円丸め": np.round(line_cost.sum(), 0),
})
rounding_comparison.to_frame("合計原価(円)").assign(
基準との差=lambda x: x["合計原価(円)"] - x.iloc[1, 0]
)
| 合計原価(円) | 基準との差 | |
|---|---|---|
| 明細ごとに1円丸め後、合計 | 13856809.0 | 13.0 |
| 丸めず合計後、1円丸め | 13856796.0 | 0.0 |
結果の読み取り
差は誤実装とは限らず、丸め規約の違いです。ただし大量明細では差が累積します。要件定義に「丸め単位・方式・タイミング」を明記し、会計システムとの照合例を用意します。
11. No.005:桁落ち
実務での意味
大きく、互いに近い2値の差を取ると、共通する上位桁が打ち消され、相対的に誤差の多い下位桁だけが残ります。基準位置からの微小変位やエネルギー収支の差分で注意が必要です。
分析・モデル化の考え方
と が近いとき、 の有効桁は入力の有効桁より少なくなります。安定な式への変形、基準値を早い段階で引くセンタリング、高精度型の利用が対策です。
Pythonで確認する
reference64 = np.float64(100_000_000.0)
measured64 = np.float64(100_000_000.125)
reference32, measured32 = np.float32(reference64), np.float32(measured64)
pd.DataFrame({
"型": ["float64", "float32"],
"基準値": [reference64, reference32],
"測定値": [measured64, measured32],
"差分": [measured64-reference64, measured32-reference32],
})
| 型 | 基準値 | 測定値 | 差分 | |
|---|---|---|---|---|
| 0 | float64 | 100000000.0 | 100000000.125 | 0.125 |
| 1 | float32 | 100000000.0 | 100000000.000 | 0.000 |
結果の読み取り
float32 では 0.125 の差分が消えました。座標を原点からの巨大値で保存するより、設備基準からの変位として保存するなど、データ設計の段階で有効桁を守ることが有効です。
12. No.006:情報落ち
実務での意味
大きな累積値へ非常に小さな値を加えると、小さい値が表現可能な桁より下に入り、加算結果へ反映されません。高速センサーの微小増分を長期間積算する場合などに生じます。
分析・モデル化の考え方
浮動小数点数の間隔は値の絶対値とともに広がります。大きい値 に対して小さい が 近傍の表現間隔より小さいと、 となります。小さい値から合計する方法や補償和が対策です。
Pythonで確認する
values = np.concatenate(([1e16], np.ones(1_000_000)))
naive_sum = values.sum()
small_first_sum = values[::-1].sum()
import math
compensated_sum = math.fsum(values.tolist())
pd.DataFrame({
"方法": ["大値からNumPy合計", "小値からNumPy合計", "math.fsum(補償的合計)"],
"合計": [naive_sum, small_first_sum, compensated_sum],
"理論値との差": [naive_sum-(1e16+1e6), small_first_sum-(1e16+1e6), compensated_sum-(1e16+1e6)],
})
| 方法 | 合計 | 理論値との差 | |
|---|---|---|---|
| 0 | 大値からNumPy合計 | 1.0000000001e+16 | -12.0 |
| 1 | 小値からNumPy合計 | 1.0000000001e+16 | 0.0 |
| 2 | math.fsum(補償的合計) | 1.0000000001e+16 | 0.0 |
結果の読み取り
同じ値でも加算順序により結果が変わります。重要な累積KPIでは、単位を適切にスケーリングし、安定な集計法を採用し、再集計時の許容差を定義します。
13. No.007:オーバーフロー
実務での意味
指数関数を含む故障モデルや尤度計算、単位変換を誤った指標は、型の最大値を超えて inf になることがあります。後続の平均や最適化結果まで汚染します。
分析・モデル化の考え方
float64 の最大有限値は約 です。指数計算では直接積を取らず対数領域で計算する、入力範囲を検証する、isfinite で異常を検知する方法が有効です。
Pythonで確認する
growth_rates = np.array([700.0, 710.0, 720.0])
with np.errstate(over="ignore"):
direct = np.exp(growth_rates)
result_007 = pd.DataFrame({"指数": growth_rates, "exp(x)": direct, "有限値か": np.isfinite(direct)})
result_007
| 指数 | exp(x) | 有限値か | |
|---|---|---|---|
| 0 | 700.0 | 1.0142320547e+304 | True |
| 1 | 710.0 | inf | False |
| 2 | 720.0 | inf | False |
結果の読み取り
警告を消すだけでは対策になりません。入力上限、単位、有限性を検証し、積や指数を比較するだけなら対数値のまま扱います。inf を欠損値として黙って除外する運用は避けます。
14. No.008:アンダーフロー
実務での意味
多数の微小な不良確率や尤度を掛けると、真の値は正でも計算結果が0になります。異常検知モデルで候補間の比較ができなくなる原因です。
分析・モデル化の考え方
確率の積 は、対数を使えば
となります。積を和に変えることで、表現可能範囲を超えにくくし、大小比較も維持できます。
Pythonで確認する
probabilities = np.full(1_000, 0.01)
direct_probability = np.prod(probabilities)
log_probability = np.log(probabilities).sum()
pd.Series({
"確率の直接積": direct_probability,
"対数確率": log_probability,
"有限な対数として保持": np.isfinite(log_probability),
}).to_frame("値")
| 値 | |
|---|---|
| 確率の直接積 | 0.0 |
| 対数確率 | -4605.1701859881 |
| 有限な対数として保持 | True |
結果の読み取り
直接積は0になりますが、対数確率は保持できます。予知保全や品質モデルでは対数尤度を標準とし、「0」が真のゼロか数値限界かを区別します。
15. No.009:機械イプシロン
実務での意味
機械イプシロンは、1.0の近傍で計算機が区別できる相対的な間隔です。ただし、すべての比較に機械イプシロンをそのまま許容差として使えるわけではありません。
分析・モデル化の考え方
機械イプシロン は、対象の型で となる最小の正数です。値 の近傍の実際の間隔は np.spacing(x) で確認できます。業務許容差は測定分解能や公差を優先して定めます。
Pythonで確認する
scale_values = np.array([1.0, 50.0, 1e8, 1e16])
pd.DataFrame({
"値 x": scale_values,
"x近傍の次の表現値までの間隔": np.spacing(scale_values),
"相対間隔": np.spacing(scale_values) / scale_values,
}).assign(float64機械イプシロン=np.finfo(np.float64).eps)
| 値 x | x近傍の次の表現値までの間隔 | 相対間隔 | float64機械イプシロン | |
|---|---|---|---|---|
| 0 | 1.0000000000e+00 | 2.2204460493e-16 | 2.2204460493e-16 | 2.2204460493e-16 |
| 1 | 5.0000000000e+01 | 7.1054273576e-15 | 1.4210854715e-16 | 2.2204460493e-16 |
| 2 | 1.0000000000e+08 | 1.4901161194e-08 | 1.4901161194e-16 | 2.2204460493e-16 |
| 3 | 1.0000000000e+16 | 2.0000000000e+00 | 2.0000000000e-16 | 2.2204460493e-16 |
結果の読み取り
絶対的な間隔は値が大きくなるほど広がります。比較には np.isclose の相対・絶対許容差を用途に合わせて設定し、機械精度と工程能力を混同しないことが重要です。
16. No.010:数値誤差の評価
実務での意味
誤差を「何mmずれたか」だけで見るか、「基準に対して何%ずれたか」で見るかにより評価が変わります。品質、原価、シミュレーション検証では、目的に合う指標と合格基準が必要です。
分析・モデル化の考え方
真値 、近似値 に対し、絶対誤差と相対誤差は
E_{\mathrm{rel}}=\frac{|\hat{x}-x|}{|x|}$$ です。真値が0付近なら相対誤差は不安定になるため、絶対許容差を使います。参照値そのものにも不確かさがある場合は、その不確かさを含めて評価します。 ### Pythonで確認する ```python raw = factory_df["measurement_raw_mm"].to_numpy() displayed = factory_df["measurement_display_mm"].to_numpy() abs_error = np.abs(displayed - raw) rel_error = abs_error / np.abs(raw) error_summary = pd.Series({ "最大絶対誤差 (mm)": abs_error.max(), "平均絶対誤差 (mm)": abs_error.mean(), "最大相対誤差 (%)": 100 * rel_error.max(), "表示分解能の半分 (mm)": 0.0005, }) display(error_summary.to_frame("値")) fig, ax = plt.subplots(figsize=(8, 4.5)) ax.hist(abs_error * 1_000, bins=20, color="#2878B5", edgecolor="white") ax.axvline(0.5, color="#C82423", linestyle="--", label="表示分解能の半分") ax.set_title("測定値を0.001 mm単位で表示したときの丸め誤差") ax.set_xlabel("絶対誤差 (µm)") ax.set_ylabel("測定数") ax.grid(True, alpha=0.3) ax.legend() plt.tight_layout() plt.show() ``` <style scoped> .dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } </style> <table border="1" class="dataframe"> <thead> <tr style="text-align: right;"> <th></th> <th>値</th> </tr> </thead> <tbody> <tr> <th>最大絶対誤差 (mm)</th> <td>0.0004999639</td> </tr> <tr> <th>平均絶対誤差 (mm)</th> <td>0.0002556658</td> </tr> <tr> <th>最大相対誤差 (%)</th> <td>0.0009999378</td> </tr> <tr> <th>表示分解能の半分 (mm)</th> <td>0.0005000000</td> </tr> </tbody> </table> /var/folders/3y/fmw40k0x78xblvb3gkcyvy1h0000gn/T/ipykernel_76425/1972374313.py:22: UserWarning: Glyph 181 (\N{MICRO SIGN}) missing from font(s) IPAexGothic. plt.tight_layout() /Users/hiroshi/private/kobo/notebook/.venv/lib/python3.13/site-packages/IPython/core/pylabtools.py:170: UserWarning: Glyph 181 (\N{MICRO SIGN}) missing from font(s) IPAexGothic. fig.canvas.print_figure(bytes_io, **kw)  ### 結果の読み取り 丸めによる絶対誤差は理論上、表示刻み 0.001 mm の半分以内です。この誤差が公差 ±0.010 mm に対して十分小さいか、判定境界付近の製品を再測定すべきかを業務要件として決めます。相対誤差が小さくても、合否境界を跨ぐなら無視できません。 ## 17. 対象ノックを通して見える実務上の示唆 1. **データ型は設計事項**:保存容量だけでなく、測定分解能、累積期間、演算内容から決めます。 2. **丸め規約は業務仕様**:桁数だけでなく、方式とタイミングを統一します。 3. **式の正しさと計算の安定性は別**:数学的に同値でも、有限精度では結果が異なります。 4. **異常値を機械的に除外しない**:`inf`、0、`NaN` が数値限界の兆候か確認します。 5. **誤差を判断基準へ接続する**:絶対・相対誤差、測定不確かさ、公差、損失を合わせて評価します。 ## 18. 実務導入する場合に必要なこと - PLC・センサー・DB・BI間のデータ型と単位を棚卸しする - 重要KPIごとに精度、丸め、欠損、有限性、許容差の仕様を定義する - 境界値、大値・小値、加算順序を含む自動テストを用意する - 元データ、変換履歴、ライブラリ版、乱数seedを記録し再現性を確保する - 品質保証、経理、生産技術、ITが同じ計算例で受入確認する 小さく始めるなら、合否・請求・設備停止に直結するKPIを3つ選び、現在の計算経路と誤差予算を可視化するのが現実的です。 ## 19. まとめ 浮動小数点数は便利ですが、有限の表現です。丸め誤差、桁落ち、情報落ち、オーバーフロー、アンダーフローを理解し、機械イプシロンと業務許容差を区別することで、計算結果を安全に意思決定へ使えます。重要なのは、桁数を増やすことだけではなく、データ表現、安定な計算、検証基準を一体として設計することです。 ## 20. 法人向けのご相談 数理工房では、製造データ分析、数値シミュレーション、数理最適化、AI導入に加え、既存KPIの計算精度レビューや社内研修についてもご相談を承ります。現場データの特性と意思決定の流れを整理し、PoCから運用設計まで支援します。 > 📩 **お問い合わせ**: [surikobo.co.jp/contact](https://surikobo.co.jp/contact) > まずはお気軽にご相談ください。