何が起きていたか
身長と体重から BMI を出し、日本肥満学会の基準で「低体重(やせ)・普通体重・肥満(1度〜4度)」に分けるツールで、BMI がちょうど区分の境目になる入力を、下の区分と判定していました。
- 身長 160cm・体重 64kg: 64 ÷ 1.6² は 25 ちょうどで、「肥満(1度)」が正しい区分です。ツールは「普通体重」と出していました
- 110cm・36.3kg(BMI 30 ちょうど)は「肥満(1度)」と出ていました(正しくは「肥満(2度)」)
区分のほかに、「普通体重まであと何kg」という目標の文言にも、境目のずれがありました。
- BMI がちょうど25のとき、目標の文言が消えていた(100.0cm・25.0kg)
- 減らす量が 0.05kg に満たないのに「あと約 0.0kg 減が目安です」と出ていた(100.1cm・25.1kg)
どのくらいの入力で起きていたか
身長 100.0〜200.0cm × 体重 10.0〜150.0kg(0.1刻み)の 1,402,401通り で、正確な値と比べました。
| 画面のどこか | 直す前 |
|---|---|
| 区分(とコピーの文字・目盛りの読み上げ) | 9通り |
| 目標の文言 | 487通り |
どうやって見つかったか
CODE Polyglot の ローレル指数 で同じ種類の不具合(直した不具合)が見つかりました。そこで、シルギア側が、同じように体重を身長の累乗で割って区分を決めるツールを探して直しました。CODE Polyglot は、直したコードを本番に出す前と出したあとに、全通りで確かめました。
本番に出す前の確認では、もう1つずれが見つかりました。差(体重 − 適正体重)や減らす量がちょうど 0.05kg のとき、「ほぼ標準」「あと約 0.1kg 減」の分かれ目がずれていました(例 150cm・49.45kg、170.0cm・72.3kg)。シルギアは、ここも直してから本番に出しました。
原因
- 64 ÷ 1.6² を2進数の小数で計算すると 24.999999999999996 になります。区分は
bmi < 25で決めていたので、「普通体重」に入りました - 0.05kg の分かれ目も、2進数の小数で引き算した結果(0.04999… や 0.05000…01)を 0.05 と比べていました
どう直したか
計算を新しいファイル calc.js に分けました。入力の文字列(「160」「64」)を分数(BigInt)のまま扱い、区分と 0.05kg の分かれ目を、割り算をせず掛け算で比べるようにしました。BMI・適正体重などの 0.1 単位の表示は、もともと正しく出ていたので変えていません。
確かめたこと
CODE Polyglot の検証(tools/shirugear-verify/。本番の app.js と calc.js をそのまま動かし、画面の文字を正確な分数の正解と比べる)で確かめました。
入力は次の 1,685,752通り です。
- 上の 1,402,401通り
- 整数の身長 × 体重 0.01刻み
- 身長 0.1cm ごとに BMI が 18.5・25・30・35・40 ちょうどになる体重
- 差・減らす量がちょうど ±0.05kg になる体重
1e2のような書き方- エラーになる入力
比べたのは、BMI・区分・適正体重・差・目標の文言・早見表・目盛りの読み上げ・コピーの文字です。
| 版 | 不一致 |
|---|---|
| 直す前の本番 | 1,685,752通り中5,006通り |
| 1回目の修正(3bb9c6640) | 1,685,752通り中1,543通り(0.05kg ちょうどの分かれ目) |
2回目の修正(e82a5a944)・本番に反映したあと(2026-10-30。本番の app.js・calc.js がこのコミットと同じことも確認) | 1,685,752通り中0通り |