CODE Polyglot / 直した不具合

炊き上がりの上限が 5g 少なく出る(合から入れたときの生米のグラムも 1g 少ないことがある)

2.5合 → 炊き上がり上限 860g(正しくは865g)、0.41合 → 生米 61g(正しくは62g)

どの言語で起きるか

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

ケース正解よくある書き方の答え(10言語)
c0025g の境目・2.5合
gou
2.5
rice_g
375
ml
450
cooked_low
790
cooked_high
865
bowls
6
onigiri
8
  • PHP・Python・Go・JavaScript・Java・C#・Rust・Ruby・Kotlin・Swiftcooked_high860
c0035g の境目・4.5合
gou
4.5
rice_g
675
ml
810
cooked_low
1420
cooked_high
1555
bowls
10
onigiri
14
  • PHP・Python・Go・JavaScript・Java・C#・Rust・Ruby・Kotlin・Swiftcooked_high1550
c0045g の境目・5.5合
gou
5.5
rice_g
825
ml
990
cooked_low
1735
cooked_high
1900
bowls
12
onigiri
17
  • PHP・Go・JavaScript・Java・Rust・Ruby・Kotlin・Swiftcooked_high1895
  • Python・C#cooked_low1730cooked_high1895
c012グラムから・5g の境目
gou
1.2
rice_g
175
ml
210
cooked_low
370
cooked_high
405
bowls
3
onigiri
4
  • PHP・Python・Go・JavaScript・Java・C#・Rust・Ruby・Kotlin・Swiftcooked_high400
c013グラムから・合は小数第1位
gou
0.2
rice_g
25
ml
30
cooked_low
55
cooked_high
60
bowls
0
onigiri
1
  • PHP・Go・JavaScript・Java・Rust・Ruby・Kotlin・Swiftcooked_high55
  • Python・C#cooked_low50cooked_high55

何が起きていたか

米の合数・生米のグラム・茶碗の杯数から、炊き上がりの量などを出すツールで、炊き上がりの上限(生米 × 2.3 を 5g 単位に丸めた値)が 5g 少なく出ることがありました。

  • 2.5合(生米 375g): 375 × 2.3 = 862.5g、5g 単位に四捨五入して 865g が正解です。ツールは 860g と表示していました
  • 4.5合は 1,550g(正しくは 1,555g)、5.5合は 1,895g(1,900g)、9.5合は 3,275g(3,280g)でした

直している途中で、合から入れたときの生米のグラム表示にも同じ型のずれが見つかりました(0.41合 → 0.41 × 150 = 61.5g が 61g、正しくは 62g)。

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

ツールをそのまま動かし、表示された値を正確な値と比べました。

入力範囲ずれていた
合から0.01〜20合(0.01合刻み)2,000通り中71通り(炊き上がりの上限 9・生米のグラム 62)
生米のグラムから1〜5,000g(1g 刻み)と 0.1〜100.0g(0.1g 刻み)6,000通り中41通り(炊き上がりの上限)
茶碗の杯数から0.1〜50.0杯(0.1杯刻み)500通り中132通り(炊き上がりの上限)
合計8,500通り中244通り

入力欄の刻み(0.5合)どおりの合数だけでも、0.5〜10合の20通り中4通り(2.5・4.5・5.5・9.5合)でずれていました。ずれはすべて、正しい値より小さい向きでした。

どうやって見つかったか

CODE Polyglot の18本目の仕様 米の量と炊き上がり・人数 を作る前に、元のツールの式を Node で評価して、炊き上がりの上限がずれることを確かめました(2026-10-22)。仕様の正解表16件では、c002(2.5合)・c003(4.5合)・c004(5.5合)・c012(175g)・c013(25g)の上限を、10言語のよくある書き方がそろって外しました。

最初の修正(a7d63b63c)で炊き上がり・茶碗・おにぎり・ml はすべて正しくなりました。CODE Polyglot で表示まで含めて全通り確かめたところ、合から入れたときの生米のグラム表示に62通りのずれが残っていました。それも直した版(d0ee748a6)が本番に反映されています。

原因

  • 2.3 は2進数の小数では正確に表せません。375 × 2.3 は 862.5 ではなく 862.49999999999988… になります。5 で割ると 172.49999… で、四捨五入すると 172、5 を掛けて 860g になります(解説)
  • 生米のグラム表示も、0.41 × 150 が 61.499999999999993 になり、四捨五入で 61g になっていました

どう直したか

5g 単位の炊き上がり(上限・下限)、茶碗・おにぎりの数、ml、生米のグラム表示、合数の表示、茶碗の杯数から 0.5合単位にする丸めを、すべて2進数の誤差を補正する四捨五入(roundHalfUp)にそろえました。

  function round5(x) {
-   return Math.round(x / 5) * 5;
+   return roundHalfUp(x / 5, 0) * 5;
  }
  function grams(x) {
-   return Math.round(x).toLocaleString("ja-JP") + "g";
+   return roundHalfUp(x, 0).toLocaleString("ja-JP") + "g";
  }

確かめたこと

  • 最初の修正(a7d63b63c)を本番に反映する前に、app.js をそのまま動かして上の8,500通りを確かめました。炊き上がり・茶碗・おにぎり・ml は全通り一致し、生米のグラム表示に62通りのずれが残っていたので、シルギア側に伝えました(2026-10-22)
  • 本番に反映したあと(コミット d0ee748a6)、本番の app.js がこのコミットと同じであることを確かめました。そのうえで、同じ8,500通りすべてが正解と一致することを確認しました

← 直した不具合の一覧へ