LoginSignup
1
0

More than 1 year has passed since last update.

MonoでDigit Separator (桁区切り文字)にハメられた話

Posted at

あらまし

まずは、こいつを見て欲しい

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超えとるぞゴルァとコンパイラに怒られていた。
勘のいい人はきっとここでなんかおかしいと気づけていたのかもしれない。
私は気づけませんでした。

  1. https://docs.microsoft.com/ja-jp/dotnet/csharp/language-reference/proposals/csharp-7.0/digit-separators に日本語翻訳があるが機械翻訳が酷すぎて読めたものじゃない

1
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0