CODE Polyglot / 直した不具合

材料のグラム数が 0.1g 少なくなる

水45ml・かつおだし(3%)→ 1.3g(正しくは1.4g)

どの言語で起きるか

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

ケース正解よくある書き方の答え(10言語)
c0030.05 の境目・かつおだし 45ml
materials
[{"name": "かつお節", "grams": "1.4"}]
  • PHP・Python・JavaScript・Java・C#・Rust・Ruby・Kotlin・Swiftmaterials[{"name": "かつお節", "grams": "1.3"}]
  • Gomaterials[{"grams": "1.3", "name": "かつお節"}]
c0040.05 の境目・かつおだし 335ml
materials
[{"name": "かつお節", "grams": "10.1"}]
  • PHP・Python・JavaScript・Java・C#・Rust・Ruby・Kotlin・Swiftmaterials[{"name": "かつお節", "grams": "10"}]
  • Gomaterials[{"grams": "10", "name": "かつお節"}]
c0050.05 の境目・煮干しだし 155ml
materials
[{"name": "煮干し", "grams": "4.7"}]
  • PHP・Python・JavaScript・Java・C#・Rust・Ruby・Kotlin・Swiftmaterials[{"name": "煮干し", "grams": "4.6"}]
  • Gomaterials[{"grams": "4.6", "name": "煮干し"}]

何が起きていたか

水の量とだしの種類から、昆布・かつお節などのグラム数を出すツールで、材料のグラム数が 0.1g 少なくなることがありました。

  • 水 45ml・かつおだし(かつお節 3%): 45 × 3% = 1.35g で、小数第1位に四捨五入して 1.4g が正解です。ツールは 1.3g と表示していました
  • 水 335ml・かつおだし(10.05g)は 10g(正しくは 10.1g)、水 155ml・煮干しだし(4.65g)は 4.6g(正しくは 4.7g)でした

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

水 1〜5,000ml(1ml刻み)× 割合 1%・2%・3% の 15,000通り で、正確な値と比べました。

割合0.1g 少ない
1%(昆布・顆粒だし)5,000通り中0通り
2%(かつお節・昆布)5,000通り中0通り
3%(かつお節・煮干し)5,000通り中66通り
合計15,000通り中66通り

0.1g 多くなる向きのずれはありませんでした。

どうやって見つかったか

CODE Polyglot の仕様 だし(出汁)の割合計算 を作る前に、元のツールの式を Node で評価して、15,000通り中66通りで 0.1g 少なくなることを確かめました(2026-10-15)。仕様の正解表14件では、c003(45ml)・c004(335ml)・c005(155ml)を、元のツールと同じ書き方の4言語がそろって外しました。

同じ日、シルギア側の品質点検では、このツールは「不具合なし」と判定されていました。式(水の量 × 割合)そのものは正しく、早見表の値も境目に乗らなかったためです。CODE Polyglot から反例(水 45ml・かつおだし → 1.3g)と、15,000通り中66通りというずれの件数を示し、その日のうちに直りました。

原因

  • 3 ÷ 100 = 0.03 は2進数の小数では正確に表せません。45 × 0.03 は 1.35 ではなく 1.3499999999999999 になり、0.05 に届かないので四捨五入で 1.3 に切り下がります(解説)

どう直したか

水の量と割合はどちらも整数なので、0.1g を単位にした整数で計算するようにしました。計算の部分は calc.js に分けました。

- return { name: m.name, pct: m.pct, grams: water * (m.pct / 100) };
- var r = Math.round(n * 10) / 10;
+ return { name: m.name, pct: m.pct, gram: gramLabel(water, m.pct) };
+ return Math.floor((w * p * 10 + 50) / 100);

水 × 割合 ÷ 100 を 0.1g 単位で四捨五入すると、⌊(水 × 割合 × 10 + 50) ÷ 100⌋ です。2進数の小数を一度も通りません。

確かめたこと

  • 修正後の calc.js(コミット 7b1b403d)で、15,000通りすべてが正解と一致(2026-10-15)
  • 本番に反映したあと、本番の calc.js で同じ15,000通りの一致を確認
  • シルギア側の記録では、テスト全体の227件がすべて通過

← 直した不具合の一覧へ