この記事、何?
少し前の記事でいろいろとこんな風にかけるよってコメントをもらった。
で、正直、一目見たときに意味不だったので理解してみた。
※流石に今回はVisual Studio使いました。
少し前の記事
■C#手遊び(指数計算: 37^95を323で除算したあまりを計算。少しラムダ式)
https://qiita.com/siinai/items/2b1d8d32b8dccb8381af
順番に行きますよ。
1つ目
Enumerable.Repeat(37, 95).Aggregate(1, (a, b) => a * b % 323)
ラムダ式だけはわかる。これ。「(a, b) => a * b % 323」。aにbをかけて323で割った余りを返すという関数。
ただ、EnumerableもRepeatもAggregateもわからん。。。何それ?
1つ目の1つ目:Enumerable
参考にしたサイト
■未確認飛行:標準クエリ演算子(その他)> 生成演算子
https://ufcpp.net/study/csharp/sp3_stdqueryo.html
//コード
Show(Enumerable.Range(5, 3));
Show(Enumerable.Repeat("abc", 3));
//出力
5 6 7
abc abc abc
なるほど。ひとまず、数を並べてどーにかするクラス(メソッド?)群の親ラスという理解で進めてみよう。
1つ目の2つ目:Repeat(37, 95)
これも上記サイトからなるほど。と。
つまり、「Repeat」の言葉の通り、{37, 37, 37, 37, ... , 37 }と37を95個生成しますという意味。
だからこの後ろにLinqで.Sum()とか書くと37*95がReturnされる感じ。なるほど。近づいてきた。
1つ目の3つめ:Aggregate(1, (a, b) => a * b % 323)
変数をおかっけてみようと思ってlambda式を分解して、F11をとんとんしておっかけてみた。
Aggregate(1, GetInt)
private int GetInt(int a, int b){ return a * b; }
なるほどね。理解した。
最初のT(今回は多分int扱いの1)を起点として、次々とそのもとになる数列を処理する感じ。
直前に{37, 37, ..., 37}が来てるから、1回目で1*37%323が来て、2回目でその戻り値に「*37%323」する。
なるほどね。これで37を95回かけて処理する、が成立するのね。
じゃ、これで階上が計算できる?
var tmp = Enumerable.Range(1, 6).Aggregate((a, b) => a * b);
できるね。
tmpに6!の解、720が入ってました。
もしかしてフィボナッチの数列も作れる?
・・・あっ、無理か。そりゃそうだ。
必要な場合が出てきそうなので覚えておこう・・・
というか、コーディングそのもののリテラルは忘れてしまいそうだから、この投稿か、未確認飛行のサイトを参照できるようにしておこう。
2つ目
for (int i = 0x40000000; i > 0; i >>= 1) {
answer = answer * answer % divisor;
if ((exponent & i) > 0) {
answer = answer * @base % divisor;
}
}
これもなるほどという感じでした。
これも分けていきます。
2つ目の1つ目:int i = 0x40000000
いや、まあ、こういう書き方できるんだなぁ・・・と。
これからやろうとしていることの伏線ですね。
2つ目の2つ目:>>=
これ、知識になかった。というか、見てもわからなかったなので調べた。
参考にしたサイト
参考にしたサイト
■未確認飛行:組込み演算子 > シフト
https://ufcpp.net/study/csharp/st_operator.html
(引用)
<< は左シフトを、 >> は右シフトを行う演算子です。
なるほど。自分で先の記事で「2進数で数えて7回ループ」とか言っていたこともあり、やろうとしていることを考えるとこれですね。
そして3つめに続くです。
2つ目の3つめ:(exponent & i) > 0
はい、きましたこれ。
昔、6 and 13 = 4 とかって処理の意味が分からなくておっかけたことがあった。
それを考えると、わかるわ・・・
ビッグエンディアンとして上のビットから数えるということですね。
2つ目の4つ目:@base
※qiitaのエスケープがよくわからなかったので@は全角文字で書いちゃました。。。
予約語のスペルも変数として定義できると。
確かに int @int = 3; とかできた。
ちょっと前に親クラスから継承して・・・とか記事書いてたので「おっ、これは呼び出し元の数をどうにかするのか?」とか思ったけどそうでもなかったみたい。
感想
自分でZeroから書いた記事よりよっぽど勉強になった。
たんに書き方、というより、数を扱うということをそういう風にまとめるという考え方が参考になった。
本業は機械学習でPythonなのでそっちでpandasやnumpyあたりと向き合うとき、いいフィードバックになってくれることと思います。
(先の記事以外も含め)Qiitaでコメントくださる方々、ありがとうございます!
・・・というか、これからもよろしくです。
(をぃ!)
忘れてた。。。
指摘の BigInteger.ModPow 調べてない。。。
また追記します。
調べた!
なるほど。最初にPythonは10文字って書いたけど、C#もやるね。
var bint = System.Numerics.BigInteger.ModPow(37, 95, 323);
流石に998!とかその100乗とかを平気で計算するPythonにはびっくりだけど。