CODE Polyglot / 直した不具合

ちょうど割り切れる袋数が1袋多くなる

6.5m² × 厚さ3cm・1袋0.013m³ → 16袋(正しくは15袋)

どの言語で起きるか

シルギアのツールは JavaScript で書かれています。この不具合が見つかったケースを、CODE Polyglot で10言語の「よくある書き方」で回した結果です(言語を返した答えごとにまとめ、赤い値は実際に返した間違った答え)。 JavaScript は 5件中5件で外れました。

ケース正解よくある書き方の答え(10言語)
c002袋数・割り切れる(0.1m³ の袋)
volume
0.3
liters
300
loss_volume
0.3
loss_liters
300
bags
3
  • PHP・Python・Go・JavaScript・Java・C#・Rust・Ruby・Kotlin・Swiftbags4
c003袋数・割り切れる(0.05m³ の袋)
volume
0.15
liters
150
loss_volume
0.15
loss_liters
150
bags
3
  • PHP・Python・Go・JavaScript・Java・C#・Rust・Ruby・Kotlin・Swiftbags4
c004袋数・割り切れる(10L の袋)
volume
0.07
liters
70
loss_volume
0.07
loss_liters
70
bags
7
  • PHP・Python・Go・JavaScript・Java・C#・Rust・Ruby・Kotlin・Swiftbags8
c006袋数・25L の袋
volume
0.3
liters
300
loss_volume
0.3
loss_liters
300
bags
12
  • PHP・Python・Go・JavaScript・Java・C#・Rust・Ruby・Kotlin・Swiftbags13
c009体積の四捨五入・0.5 ちょうど
volume
0.113
liters
113
loss_volume
0.113
loss_liters
113
bags
null
  • PHP・Python・Go・JavaScript・Java・C#・Rust・Ruby・Kotlin・Swiftvolume"0.112"liters112loss_volume"0.112"loss_liters112

何が起きていたか

面積と厚さからコンクリートの必要量と袋数を出すツールで、ちょうど割り切れる袋数が1袋多くなっていました。

  • 面積 6.5m²・厚さ 3cm・1袋 0.013m³(初期値): 体積は 0.195m³ で、0.195 ÷ 0.013 = 15袋ちょうどです。ツールは 16袋 と表示していました
  • 面積 3m²・厚さ 10cm・1袋 0.1m³ も、0.3 ÷ 0.1 = 3袋のところを 4袋 と表示していました

体積の端数が 0.0005m³ ちょうどになる入力では、体積とリットルが小さい方に丸められることもありました(面積 1.5m²・厚さ 7.5cm の 0.1125m³ を 0.112m³・112L、正しくは 0.113m³・113L)。

どのくらいの入力で起きていたか

袋数は、面積 1〜30m²(0.5m²刻み・59通り)× 厚さ 3・5・7・8・10・12・15・20cm(8通り)の472通りを、1袋の量5種類で数えました。

1袋の量1袋多い
0.01m³(10L)472通り中56通り
0.013m³(初期値)472通り中23通り
0.025m³472通り中25通り
0.05m³472通り中21通り
0.1m³472通り中16通り
合計2,360通り中141通り

袋数が少なくなる向きのずれは、2,360通り中0通りでした。

体積とリットルは、面積 0.1〜30.0m²(0.1m²刻み)× 厚さ 1.0〜30.0cm(0.5cm刻み)の 17,700通り で数えました。体積(m³・小数第3位まで)とリットルが、どちらも 0.001m³・1L 少なく表示されたのは、17,700通り中712通りです。

どうやって見つかったか

CODE Polyglot の仕様 コンクリート・生コンの必要量 を作るとき、元のツールと同じ式を4言語で書いて、正確な値と突き合わせました(2026-10-15)。正解表16件のうち、ちょうど割り切れる袋数の c002・c003・c004・c006 を、4言語とも1袋多く答えました。体積の四捨五入の c009 なども外しました。

同じ日、シルギア側の品質点検では、このツールは「不具合なし」と判定されていました。袋数の式 ceil(体積 ÷ 1袋の量) そのものは正しく、早見表の値も境目に乗らなかったためです。CODE Polyglot から反例(6.5m²・厚さ 3cm → 16袋)と、上の472通りで数えたずれの件数を示し、その日のうちに直りました。

原因

  • 0.195 や 0.013 は2進数の小数では正確に表せません。0.195 ÷ 0.013 は 15.000000000000002 になり、切り上げで16になります。袋数は足りないと困るので切り上げで出しますが、切り上げはこのわずかな誤差を拾います(解説)
  • 1.5 × (7.5 ÷ 100) は 0.1125 ではなく 0.11249999999999999 になり、四捨五入で 0.112 に切り下がります(解説)

どう直したか

計算の部分を calc.js に分けました。入力を十進の文字列のまま整数の分子・分母(BigInt)にして計算し、袋数の切り上げと、体積・リットルの四捨五入を整数で行います。

- var volume = area * (thickCm / 100); // m³
- var bags = Math.ceil(volume / bagVol);
- var r = Math.round(n * 1000) / 1000;
+ var v = div(mul(a, t), int(100)); // 体積 m³
+ bags: bag.n > 0n ? Number(ceil(div(v, bag))) : null,
+ var n = halfUp(mul(x, int(1000)));
+ var halfUp = function (x) { return (2n * x.n + x.d) / (2n * x.d); }; // x ≥ 0
+ var ceil = function (x) { return (x.n + x.d - 1n) / x.d; }; // x ≥ 0

確かめたこと

  • 修正後の calc.js(コミット 7b1b403d)で、6,904通り(上の472通り × 1袋の量4種類、無作為5,000通り、正解表16件)がすべて正解と一致(2026-10-15)
  • 本番に反映したあと、本番の calc.js で同じ6,904通りの一致を確認
  • シルギア側の記録では、テスト全体の227件がすべて通過

← 直した不具合の一覧へ