CODE Polyglot / 直した不具合

ちょうど7GB なのに10GB プランを勧め、22.5GB を「22 GB」と表示する

音楽・1日3.5時間・月25日 → 「10GB プランが目安」(正しくは7GB プラン)

どの言語で起きるか

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

ケース正解よくある書き方の答え(10言語)
c002SNS・月22.5GB(整数への四捨五入が .5)
monthly
23 GB
per_day
922 MB
hours_3gb
10 時間
hours_20gb
66 時間 40 分
plan
30GB プランが目安
  • PHP・Python・Go・JavaScript・Java・C#・Rust・Ruby・Kotlin・Swiftmonthly"22 GB"
c003音楽・月ちょうど7GB(プランの境目)
monthly
7.0 GB
per_day
287 MB
hours_3gb
37 時間 30 分
hours_20gb
250 時間
plan
7GB プランが目安
  • PHP・Python・Go・JavaScript・Java・C#・Rust・Ruby・Kotlin・Swiftplan"10GB プランが目安"

何が起きていたか

用途と利用時間から1か月の通信量(ギガ)と目安のプランを出すツールで、境目の値が反対側に落ちていました。

  • ちょうど7GB なのに「10GB プラン」: 音楽ストリーミング(0.08GB/時)を1日3.5時間・月25日使うと、0.08 × 3.5 × 25 = 7GB ちょうどです。目安のプランは「7GB 以下」なので、正解は「7GB プラン」です。ツールは 「10GB プランが目安」 と表示していました
  • 22.5GB が「22 GB」: SNS(0.3GB/時)を1日3時間・月25日使うと 22.5GB で、整数に四捨五入して 23 GB が正解です。ツールは 22 GB と表示していました

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

用途の選択肢にある1時間あたりの通信量11種類(0.04〜7.0GB)× 1日の利用時間 0〜24時間(0.5時間刻み)× 月の利用日数 1〜31日の 16,709通り で、正確な値と比べました。

ずれ件数
1か月の通信量の表示が 0.1GB(10GB 以上では 1GB)少ない16,709通り中182通り
目安のプランが1つ上になる16,709通り中4通り

1日の通信量の表示は日数によらないので、11種類 × 49通りの 539通り で数えました。539通り中20通りで 0.1GB 少なく表示していました(例: 0.3GB/時 × 4.5時間 = 1.35GB → 1.3 GB、正しくは 1.4 GB)。

プランが1つ上になった4通りは、どれも月の通信量がちょうど7GB の組み合わせでした(0.08GB/時 × 3.5時間 × 25日 など)。「3GB で使える時間」「20GB で使える時間」は、16,709通りすべてで正しく表示されていました。

どうやって見つかったか

CODE Polyglot の仕様 データ通信量(ギガ)の目安 を作るとき、元のツールと同じ式を4言語で書いて、正確な値と突き合わせました(2026-10-11)。正解表11件のうち、c002(22.5GB)と c003(ちょうど7GB)を4言語とも外しました。元のツールと同じ式を Node で評価すると、公開中のツールも11件中この2件で正解と違うことがわかりました。

原因

  • 0.08 や 0.3 は2進数の小数では正確に表せません。0.08 × 3.5 × 25 は 7.000000000000001 になり、「7 以下」を満たさずに次の 10GB プランへ進みます。0.3 × 3 × 25 は 22.499999999999996 になり、0.5 に届かないので toFixed(0) で 22 に切り下がります(解説)

どう直したか

計算の部分を calc.js に分けました。1時間あたりの通信量・時間・日数を十進の文字列のまま整数の分子・分母(BigInt)にして掛け、プランの境目との比較と、表示の四捨五入を整数で行います。表示の形(10GB 以上は整数、1GB 以上は小数第1位、1GB 未満は MB)は変えていません。

- var monthly = perDay * days;
- if (gb >= 10) return gb.toFixed(0) + " GB";
- if (monthlyGb <= tiers[i]) return tiers[i] + "GB プランが目安";
+ var monthly = mul(perDay, d); // GB/月
+ return String(roundHalfUpDiv(n, d)) + " GB";
+ // r <= tier  ⇔  r.n <= tier * r.d
+ if (r.n <= BigInt(tiers[i]) * r.d) return tiers[i] + "GB プランが目安";

確かめたこと

  • 本番が配信している calc.js(リポジトリと同じ内容、コミット 011c958e)で、無作為な100,000通りがすべて正解と一致(2026-10-11)
  • 本番のページで「7.0 GB・7GB プランが目安」「23 GB」と表示されることを確認
  • シルギア側のテスト16件がすべて通過

← 直した不具合の一覧へ