ToolConvoyToolConvoyv2.6

int vs float:数値の格納方法

int は整数を正確に格納しますが値域に限りがあります。float ははるかに広い値域を持ちますが丸め誤差があります。バグの大半はこの 2 つを混同することで発生します。

広告

int vs float:数値の格納方法

int(整数)と float(浮動小数点数)はプログラミング言語が数値を表現する 2 つの方法で、選び方は実データに触れた瞬間に結果が出ます。

int は正確で数え上げができます。42 は 42 で、丸めも意外もありません。float は近似で連続的です。IEEE 754 倍精度では 0.1 + 0.2 が 0.30000000000000004 になります。初めて会う人は誰でも驚きます。

正確な値域

int は有限です。多くの現代システムで int32 は 2^32 個の異なる値を保持します(−2,147,483,648 〜 2,147,483,647)。int64 は 2^64 個。それを超えると、型はその数値を表現できません。

float はほぼ連続です。IEEE 754 float64(C 系言語の “double”)は約 10^−308 から 10^308 まで表現でき、有効桁は 15〜17 桁。落とし穴:その範囲でも正確には表現できない数値があります。多くの値(0.1 など)は丸められます。

なぜ 0.1 + 0.2 ≠ 0.3 か

2 進浮動小数では 0.1 はきれいな分数ではありません。十進の 1/3 が 0.3333… となるように、2 進の 1/10 は 0.000110011001100… と循環します。float は有限ビットに丸める必要があり、実際に格納される値はわずかにずれます。

2 つの丸めた数値を足すと丸め誤差が累積します。0.1 + 0.2 は 0.3 をわずかに超え、float は 0.30000000000000004 と表示します。

これはバグではなく、IEEE 754 が正しく動いています。バグは、本来正確にすべきところで float を使っていることです。

どちらを使うか

int を使う場面:

  • 数えるもの(行、インデックス、サイズ)
  • 通貨を最小単位で保存(セント、pence、satoshi — 常に最小整数単位)
  • ID、秒/ミリ秒のタイムスタンプ、バイト数
  • 正確な等価性が必要(a == b が期待通り)

float を使う場面:

  • 物理量計算(距離、重さ、角度)
  • 厳密性より値域が重要な集計
  • 広い値域が活きる計算(科学計算、グラフィックス)
  • 許容誤差つきの比較を受け入れる(abs(a - b) < epsilon)

混同の落とし穴

最も微妙なバグは int と float の混同から生まれます。動的型付け言語では:

  • 5 / 2 — 多くの言語で整数除算で 2。JavaScript では 2.5
  • 5.0 / 2 — どの言語でも 2.5
  • int(2.5) と Math.floor(2.5) — 多くの言語で 2。JavaScript には int 型がないので挙動が違う

int64 を超える整数(非常に大きな ID、高精度タイムスタンプ、ブロックチェーンの金額)は特別な型が必要です。Python の int は任意精度。C++ は __int128 や boost::multiprecision。JavaScript の数値は常に float64(2^53 を超える整数は BigInt)。

通貨と古典的な教訓

コンピューティング 50 年の歴史で、ほとんどの金融バグは通貨を float で保存したことから生まれました。普遍的な修正:通貨を最小整数単位で保存(セント、ペンス、サトシ)。1999 セントは 19.99 ドルで、絶対に近似しない。人が読む形への変換は表示時にだけ行い、10 進演算を行うライブラリ(または明示的な丸め規則を使った整数除算)を使う。

ツール

JSON や CSV データに埋め込まれた数値を扱う際 — float に見える int や int に見える float に遭遇するかもしれません — JSON to CSV と JSON to YAML は型を変えずに値を忠実に往復します。

SQL では、int か float かの列選択が下流のすべての問い合わせに影響します。SQL Formatter で状況が見えてきます。

関連

Related tools

広告