あらまし
まずは、こいつを見て欲しい
using System;
static class Program {
static void Main() {
long x1 = 33076206526426037;
long m1 = 1000000007;
long x2 = 33076206526426037;
long m2 = 1_000_000_007;
Console.WriteLine(x1 % m1);
Console.WriteLine(x2 % m2);
}
}
違いは、m2
が3桁ごとに_
で区切られているというところだけ。
この区切りは、Digit Separator (桁区切り文字)
と呼ばれるものである。
digit-separators.mdから引用すると 1、
Being able to group digits in large numeric literals would have great readability impact and no significant downside.
(snip)
The syntax is straightforward, and the separators have no semantic impact
とあるように、ソースコードの可読性のためだけに特化した機能。
実際このコードを手元のdotnet SDK
でビルド・実行すると、両者とも294892595
という結果となる。
本題
ここからが本題で、上述のコードを、6.8系のMono JIT compiler
でビルド・実行すると前者が294892595
であるのに対し、後者が206526194505
と両者で違う結果となり、めっちゃ頭を抱えた。
実際には、競プロによくある。
ただし、答えは非常に大きくなる可能性があるので、1,000,000,007 で割った余りで出力してください。
な問題を解いてて、WAになってあるぇとなったのが発端。
何やかんや調べていて行き着いた先が、monoのissues/16648で、どうにも_
の次の数値をコピーする振る舞いらしい。
atcoderでは、dotnet core
を選択できるので回避可能ではあるが、Mono-mcs 6.8.0.105
も用意されているため使用しないよう注意が必要と思われる。
paizaに至っては、Mono-mcs 6.8.0.105
のみ(2022/7/2日現在)のため、スキルチェック問題でdigit separator
を使用するとぜっつぼ〜を味わうことになる。
おまけ1
issues/16648にて、pull/18539が提出され、既にmain
ブランチに取り込まれてる模様。ただしリリースパッケージ化されているかどうかは不明(そもそも手元環境はdotnet sdk6
だし)
おまけ2
1000000007
という数値は、int
に収まる値であるにもかかわらず、1_000_000_007
にしたらint
超えとるぞゴルァとコンパイラに怒られていた。
勘のいい人はきっとここでなんかおかしいと気づけていたのかもしれない。
私は気づけませんでした。
-
https://docs.microsoft.com/ja-jp/dotnet/csharp/language-reference/proposals/csharp-7.0/digit-separators に日本語翻訳があるが機械翻訳が酷すぎて読めたものじゃない ↩