何が起きていたか
シルギアの60本を超えるツールは、2進数の小数の誤差を補正して四捨五入する、共通の関数(roundHalfUp)を使っていました。丸める前に「値 × 1e-9」をほんの少し足して、375 × 2.3 が 862.4999999999999 になるような誤差を打ち消す関数です。
この足す量が値の大きさに比例していたので、金額が大きいと、0.5 に届いていない値まで切り上げていました。
- 年金の受給開始のツールで、累計 30,672,204.48円 → 30,672,205円(正しくは 30,672,204円)
- 同じく、年額 1,812,959.499円 → 1,812,960円(正しくは 1,812,959円)
- 暗号資産の損益のツールで、所得税 52,000.49995円 → 52,001円(正しくは 52,000円)
3,000万円台では 0.03円を足すので、端数が .47 を超えていれば切り上がります。
どのくらいの入力で起きていたか
お金や量を扱う8本のツールの Math.round をこの関数に置き換えた直後(2026-10-22)、本番のコードを全通り確かめると、2本で置き換える前よりずれが増えていました。
| ツール | 試した入力 | 置き換える前 | 置き換えたあと |
|---|---|---|---|
| 暗号資産の損益 | 594,740通り | 3,208通り | 13,505通り |
| 年金の受給開始 | 280,960通り | 10,420通り | 5,674通り(うち新しく出たずれ 4,486か所) |
どうやって見つかったか
CODE Polyglot で見つけた丸めのずれ(米の量・子どもの身長)を直す流れで、シルギア側がお金や量の8本をこの関数に置き換えました。直したあとの本番のコードを、CODE Polyglot で全通り確かめたときに見つかりました。
確かめ方は、本番の app.js をブラウザの代わりに Node でそのまま動かし、画面に出た文字を、同じ式を正確な分数で計算した正解と比べるものです(入力はツールあたり数万〜数百万通り)。
記事: 『誤差を補正する四捨五入』が、3,000万円で1円多く切り上げていた
原因
- 補正の量(値 × 1e-9)が値の大きさに比例していた。2進数の小数の誤差は有効数字16〜17桁目にしか出ないのに、大きな値では補正が有効数字10桁目まで届いていた
どう直したか
- 共通の関数を「有効数字12桁に整えてから丸める」形にした(2026-10-24、0c8e62ca8)。値に何かを足すのをやめたので、補正の量が値の大きさで変わらない。丸めて 0 になったときに「-0」と書かないようにもした。関数を使う64本すべてに入れ、同じ型のずれ(
toFixed・Math.ceilなど、関数を通っていない箇所)も直した - 年金の「差」は、画面に出した整数どうしを引く形にした。 1,000万円台の累計どうしを引いて 12.5円のような差を出す場所は、丸め方では直らなかったため
- 暗号資産の損益は、金額・数量・税金を整数(BigInt の分数)で計算する形にした(2026-10-26、b18c89ab6)。12桁に整える方式でも、平均取得単価が1,000万円台で小数第2位まで出すときや、利益が4,000万円を超える所得税で、二重の丸めが起きたため(10,000,777.6049… が 10,000,777.61円、11,066,460.49996 が 11,066,461円)
丸めの関数で「どこまでの誤差を許すか」を1つに決める方式は、どの幅でもどこかで外れました(3つの案を10本・約263万通りで比べた)。そこで、共通の関数は実用の範囲(有効数字12桁まで)用と割り切り、それを超える精度が要る計算だけを整数でする、という整理になっています。
確かめたこと
CODE Polyglot の検証(tools/shirugear-verify/。本番の app.js を動かし、画面の文字を正確な分数の正解と比べる)で、2026-10-26 時点の本番を確かめました。
| ツール | 試した入力 | 本番 |
|---|---|---|
| 子どもの身長 | 291,402通り | 一致 |
| 米の量 | 8,500通り | 一致 |
| タクシー料金 | 72,071通り | 一致 |
| 水分量 | 51,612通り | 一致 |
| モバイルバッテリー | 247,193通り | 一致 |
| 年金の受給開始 | 227,464通り | 一致 |
| 運動の消費カロリー | 453,794通り | 一致 |
| ランニングのペース | 328,228通り | 一致 |
| 単価比較 | 327,387通り | 一致 |
| 暗号資産の損益 | 619,011通り | 一致 |
単価比較は、数量 0.001 のような極端な入力で割高率が10億%を超える場合(有効数字12桁の限界。実際の利用では起きない範囲として据え置き)と、単価がちょうど同じ商品の並び順(決まりがない)を、確かめる入力から外しています。