
武蔵野個別指導塾の特徴
高校情報I 計算誤差—有限の桁で表す限界と比較条件の直し方を確かめる|武蔵野個別指導塾

小額の集計で等号が外れる理由を、十進の値と許容差を使って捉える計算誤差です。
よくあるのは、小数の計算結果を等号だけで比較し、手計算では同じはずなのに一致しない場面です。例えば、少額の合計を照合する係が、表示された数字を見て判定結果に首をかしげます。表示が似ていることと、内部に保持された値が厳密に等しいことは別です。
ここでは有限の桁で数を扱うときの誤差を区別し、照合条件を設計します。金額の例は理解のための自作の数値です。実際の会計で許される処理や端数の規則は別途定める必要があります。
どの条件で一致とみなすか
問われ方には、まず「なぜ等号が偽になるか」を説明する型があります。十進の文字列として書いた値と、プログラム内部で近似された値を区別します。次に「どの範囲なら一致と判定するか」を決める型があります。差の絶対値を測り、問題で与えた許容差以下かを調べます。さらに、桁落ちや打切りの原因を見分け、計算方法を考え直す型もあります。
入力、出力、比較の約束を先に書きます。以下の集計は有限個の金額のリストを受け取り、浮動小数点で計算した合計を、期待する十進の合計から作ったfloatの基準値と比べます。この基準値にも表現の誤差があるため、正確な十進数との差を直接測る処理ではありません。許容差は 0.000001 とし、2つの保持値の差の絶対値がその値以下なら True、超えれば False とします。空のリストの合計は 0、負の金額は返金を表すとして受け入れます。金額の小数点以下の桁数は例ごとに与え、許容差の単位も金額と同じです。
この True は誤差が 0 という意味ではありません。決めた範囲内に入ったという意味です。許容差が大きすぎると間違った集計まで通り、小さすぎると妥当な近似を拒むことがあります。許容差を無条件に広げるのではなく、目的と値の大きさに合わせて決めます。
近い値を保存すると何が起きるか
有限の桁で表せない数を、表せる近い数に置き換えるときに生じる差が丸め誤差です。十進でも 3 分の 1 を有限桁にすると差が残ります。2進の浮動小数点でも、十進で短く書ける 0.1 は有限桁で正確に表せません。計算の各段階で近似が入るため、十進の手計算と同じ見た目を期待しても内部の値が一致するとは限りません。
一方、打切り誤差は、無限に続く手順や項を有限のところで止めるなど、近似の手順を途中で打ち切ることによる差です。例えば無限に続く小数を途中までの和で代用したとき、残した項が差の原因です。有限桁への格納で生じる丸め誤差とは原因が異なります。小数の末尾を捨てる操作も文脈によって打切りと呼ばれるため、何を打ち切ったのかを明記します。
桁落ちは、近い大きな数の差を取るなどして、先頭の有効な桁が相殺され、結果に残る信頼できる桁が減る現象です。元の数に含まれた小さな誤差が、差に対して目立つことがあります。誤差の名前を覚えるだけでなく、どの操作で情報が失われたかを追います。
図1のように、十進の値を入力しても、浮動小数点への変換と計算を経た結果は近似値です。十進の正確な値は照合の基準に使えますが、近似値との距離がゼロとは限りません。図1の経路の途中で何を表しているかを言葉にしてみてください。

十進の小数を正確に扱いたい場合、金額を最小単位の整数で持つ方法があります。例えば 0.01 単位を 1 と数えれば、小数点以下 2 桁までの加算は整数の加算になります。Python の Decimal に十進の文字列を渡す方法もあります。ただし Decimal にも精度の設定があり、割り切れない除算などでは丸めが生じます。どの表現でも、入力の制約と計算の規則を確かめます。
基本例題:小額の合計を照合する
品物の記録が 0.1、0.2 の 2 件です。十進での合計は 0.3 です。浮動小数点による合計と十進の合計を比べ、許容差 0.000001 以下なら True を表示します。等号による比較も別に表示し、表示順を合計、等号、許容差の順とします。
手計算では 0.1 と 0.2 を足すと 0.3 です。図2のように、浮動小数点の合計は表示上 0.30000000000000004 となります。正確な十進数0.3からの差は約 0.0000000000000000444 です。一方、下のコードで使うfloatの基準値0.3も近似値なので、コードが求める差は約 0.0000000000000000555 です。いずれも指定の許容差より小さく、コードの判定は等号が False、許容差が True になります。

次のプログラムは入力をコード内に置きます。合計に金額を順に加えるので、途中状態を確認できます。
amounts = [0.1, 0.2]
total = 0.0
for amount in amounts:
total = total + amount
reference = 0.3
tolerance = 0.000001
print(total)
print(total == reference)
print(abs(total - reference) <= tolerance)
1行目が2件の入力、2行目が合計の初期値です。3行目は各要素を順に取り出し、4行目で現在の合計へ加えます。1回目の表示上の合計は 0.1、2回目は 0.30000000000000004 です。5行目は比較基準、6行目は許容差を設定します。7行目で合計、8行目で厳密な等号、9行目で差の絶対値が許容差以下かを表示します。abs により差の向きにかかわらず距離を比較します。
Python 3.15.0 で入力を上記のリストとして実行した結果は次のとおりで、期待値と一致しました。
0.30000000000000004
False
True
2件を十進で足した基準 0.3 に戻してみると、差は指定範囲内です。ただしこの結果だけで、どの金額やどの許容差でも正しいとはいえません。リストの長さが大きい場合や値の大小が大きく違う場合は、途中の丸めの影響も調べます。
条件を変えて設計する
標準例題として、記録 0.15、0.25、-0.10 を考えます。負の値は返金です。小数点以下 2 桁までとし、合計を十進の正確な値で答えてください。さらに許容差 0.000001 で浮動小数点の合計を照合します。手計算は 0.15 と 0.25 で 0.40、そこから 0.10 を引いて 0.30 です。最小単位で 15、25、-10 を足しても 30 となり、0.30 に戻ります。
基本例題のリストを [0.15, 0.25, -0.10]、基準を 0.30 に変更して実行すると、Python 3.15.0 の出力は 0.30000000000000004、False、True の順です。期待値も同じです。返金を差し引いた 0.30 と比較し、差が許容範囲にあることを確認できます。等号の False は集計の手順そのものが間違いだと即断する根拠にはなりません。
次は大きな値同士の引き算です。十進で 10000000000000000.0 に 1.0 を足してから元の数を引けば、正確な答えは 1.0 です。しかし浮動小数点では、足した後の値が元と区別できず、差が 0.0 になる場合があります。次のコードでは途中の値も表示します。
large = 10000000000000000.0
small = 1.0
added = large + small
result = added - large
print(added)
print(result)
1行目と2行目は入力、3行目は加算、4行目は差を求めます。5行目と6行目はそれぞれ途中と結果の表示です。Python 3.15.0 での実際の出力は 1e+16 と 0.0 です。期待した正確な差 1.0 と違います。1e+16 は 1 の後に 0 が 16 個続く数を表します。加算の時点で 1 の違いが保存されず、後から引いても取り戻せません。近い数の差による桁落ちを考えるときは、その前に入った丸めも追う必要があります。
同じ意味を保てるなら計算順序や数の表現を変えます。上の例なら整数として 10000000000000000 と 1 を足し、元の整数を引けば 1 です。ただし一般に式変形の途中に除算や丸めがあれば、計算順を変えた結果も常に同じとは限りません。正確な入力を保持できるか、必要な範囲を先に決めることが必要です。
誤答を直し、失敗側も調べる
基本例題で total == reference を合格条件とすると、十進の合計が 0.3 という期待に対して False が出ます。原因は、十進の表記と浮動小数点の保持値を同じものと考えたことです。図3のように差を測り、指定した範囲で判定し直します。図3の修正後の True は、差が 0 だという主張ではありません。

修正後も失敗を隠さない検証が必要です。許容差 0.000001、基準 0.3 に対し、計算結果が 0.30001 なら差は約 0.00001 で許容差を超え、False が期待されます。差が範囲外なのに True とする実装なら、比較の向きや許容差の値を見直します。また正確な金額の合否が必要な場面では、この近似判定を採用せず、整数や十進の文字列による計算を検討します。
境界は「以下」と指定したので、数学上の差が許容差と等しいときも True です。ただし浮動小数点で十進の境界を作ると、その表現自体が近似されます。境界の規則を厳密に試すには整数の最小単位などで比較し、浮動小数点では実際の保持値も見ます。空リストは合計 0.0 で基準 0.0 なら True、単一の 0.5 は基準 0.5 に対し True、同じ 0.1 を2回含む場合は基準 0.2 に対し True です。重複は取り除かず、記録された件数分を足します。
入力に文字列や数でないものが混じると、この加算コードは例外で止まります。空リストと壊れた入力を同じ 0 として扱ってはいけません。入力を受け付ける仕組みを作るなら、形式や範囲を検査してエラーを返す仕様を別に定めます。外部の読み込みや時間制限はこの短いコードの対象外です。外部から値を得る処理を付けるなら、読み込み失敗や時間切れを合計 0 と偽装せず、失敗として呼び出し側に伝える必要があります。
練習:値と判定の両方を追う
次の5問は互いに独立しています。十進の計算は正確な値を答え、近似比較は指定の差と許容差を数学上の値として扱います。判定の答えは True または False で書きます。
- 0.12、0.34、-0.05 の記録の合計を小数点以下2桁で答えてください。負の記録は返金です。
- 差の絶対値が 0.0004、許容差が 0.001 のとき、差が許容差以下という判定を答えてください。
- 差の絶対値が 0.002、許容差が 0.001 のとき、同じ判定を答えてください。
- 無限に続く項の和を途中までで近似したとき、残りの項を除いたことによる差は何という誤差ですか。有限桁への格納による差とは分けて答えてください。
- 近い大きな値の差を求めたところ、先頭の有効な桁が相殺されました。この現象の名前と、結果の信頼できる桁に起きうることを答えてください。
解答と戻し方
- 0.41 です。最小単位に直すと 12、34、-5 で、合計 41 です。0.12 と 0.34 の受取り 0.46 から返金 0.05 を引くと 0.41 に戻り、記録の方向とも一致します。
- True です。0.0004 は 0.001 以下です。基準から両方向に 0.001 の幅を取ると、その内側に差が収まります。差が 0 という意味ではありません。
- False です。0.002 は 0.001 を超えます。基準からの距離を場面に戻すと許された幅の外側なので、2問目のような範囲内の判定にはできません。
- 打切り誤差です。採用しなかった残りの項を戻せば、途中までの和との差に対応します。各項を有限桁に格納したことによる丸めは別に調べます。
- 桁落ちです。相殺後には信頼できる桁が少なくなり、元の小さな誤差が差に対して大きく見えることがあります。元の値と計算手順を見直して、差を直接求める方法があるかを調べます。
1問目は整数で 12 + 34 - 5 を計算して 41、2問目と3問目は十進の文字列から作った値で大小を比較して、それぞれ True、False となることを Python 3.15.0 で確認しました。4問目と5問目は原因の説明を条件に戻して照合しています。数字が近いという事実だけで誤差の種類を決めず、どの操作が差を生んだかを見ます。
覚えておくこと
丸め誤差は有限の表現への置換で生じます。打切り誤差は途中で手順などを止めることに由来します。桁落ちは相殺で信頼できる桁が減る現象です。近似値の比較は目的に合う許容差と境界を明示します。正確な金額には整数など適切な表現を選びます。
つまずいた場所を見つける
等号が False だったときは、まず十進の期待値を紙に書き、次に各加算後の値を処理表へ移します。期待値が違うのか、近似の差が生じたのかを切り分けられます。許容差の判定を説明するときは、差の符号を消す理由と、境界を含むかを本人の言葉で確認します。
個別指導で確かめる箇所は、入力の単位、基準、差、許容差の4つが同じ場面に対応しているかです。範囲外の値と壊れた入力でも結果を追い、True が出た理由だけでなく False や例外になった理由を説明します。数の表し方と照合の約束をそろえると、計算結果を根拠を持って読めます。
読んで終わりにするか、ここから変えるか。
武蔵境駅徒歩30秒、講師1人に生徒1人の完全1対1。授業のあいだ、先生は隣を離れません。いまの詰まりを、無料相談でそのまま話してください。
まず15分だけ電話で話したい方は、無料電話相談(15分)から。塾からお電話を差し上げます。
本気になった日が、入塾の日。
お子様の教育、迷ったら「丸投げ」してください。必ず、期待以上の結果で返します。武蔵野で育む、武蔵境で学ぶ。
電話は年中無休。365日、24時間、お電話可能。




