まず断っておきますが、これは日記です。日記ですよ。はい。すごく暇なときにどうぞ。ちゃんとプログラムに関する話題は出てきます。
こんなことがありました
筆者は学生なのですが、今度の学校行事の関係で、クラスを10グループに分けなければいけないのです。そこで、どんなチーム分けの方法がいいかという(無駄な)話し合いをすることになりました。なんでや...😞
みんなが、どうすれば均等に分けられるか考えている間、私は「しっているぞ こんなときはプログラムを書いてだな...乱数を使ってウンチャラカンチャラ...ぼくはくわしいんだ」などと考えていたわけです(本当に詳しいだなんて思ってないです)。
そして、発表の時間になって、司会さんがみんなの意見を聞いて行く中で、こんな意見が出たのです。「お財布の中の合計金額を使って分けてみたらいいのではないか(一部脚色)」例えば、Aさんは892円持っていて、Bさんは9980円持っているとします。これらの数値を使って、チーム分けをしようというのです。なかなか斬新な考えですね!?
斬新ですが、合計金額の多い順で、1から10まで順番に番号を振っていって...、という方法でチーム分けをするというのは、教育上あまりいいとは思えません。バッドアイデアです。
名案(名案とは言っていない)を思いついた
そこで、私は、合計金額という斬新なアイデアを採用しつつ、チーム分けをする方法を考えました。「合計金額を10で割った余りをグループ番号にすればいいのではないか」と。
お財布を忘れた?人数が均等にならなそう?細けぇこたぁ気にすんな(`・ω・´)
ということで(?)この方法を、近くの席のクラスメイトに話してみました。すると、数秒してから、こんな答えが返ってきました。「つまり、下1桁の数字ってこと?」
......確かにそうとも言いますね。その説明の方が、多くの人にとって分かりやすいかも知れません。しかし、偉い人は言いました。「人間にとって分かりやすいことと、コンピューターにとって分かりやすいことは、同じとは限らない(超意訳)」のだと。
プログラマーとして...
私もプログラマーの端くれです。ここは、10で割った余りスタイル と 下1桁の数字スタイル でどっちの実行速度が速いのか確かめなければなりません(落ち着け)(謎の使命感)。話し合いの結果、合計金額案はボツになったので、みんなの合計金額のデータは手元にありません...ならば、作ればいいのです!
ということで作りました。
using System;
public class Hello{
public static void Main(){
var seed = Environment.TickCount;
for(int i = 0; i < 10000; i++)
{
//毎回シード値を変更して、
//1以上100000未満の整数(乱数のようなもの)を生成する
Random r = new Random(seed++);
var num = r.Next(1,100000);
//生成した乱数のようなものを出力して、
//区切り文字としてスペースも出力する
Console.Write(num + " ");
}
}
}
追記
random.csによって生成される数字を乱数と表記していましたが、正確には乱数のようなものであり、乱数ではありませんでした。
こんな感じでいいでしょう。実行速度の違いが分かりやすいように、クラスメイトは1万人いることにしました。過密!過密!圧倒的過密!
それでは、このプログラムによって得られた1万人分の所持合計金額のデータを入力値として、10で割った余り VS 下1桁の数字 対決をしましょう。
たいけつだ!
ルール:入力されたデータを、Split()を使ってstring型の配列に格納するところまでは共通とする。
赤コーナー:10で割った余りスタイル
using System;
public class Hello{
public static void Main(){
DateTime start, end;
//string型の配列に1つ1つ格納
string[] str = Console.ReadLine().Split(' ');
//計測開始
start = DateTime.Now;
for(int i = 0; i < 10000; i++)
{
//配列strの中身をint型に変換してから
//10で割った余りを出力する
Console.Write(int.Parse(str[i]) % 10 + " ");
}
//計測終了
end = DateTime.Now;
Console.WriteLine();
//処理にかかった時間を秒単位で出力
Console.WriteLine((end - start).TotalSeconds);
}
}
説明は、コメント文に書いた通りです。これは勝てそう!(フラグ)
青コーナー:下1桁の数字スタイル
using System;
public class Hello{
public static void Main(){
DateTime start, end;
//string型の配列に1つ1つ格納
string[] str = Console.ReadLine().Split(' ');
//計測開始
start = DateTime.Now;
for(int i = 0; i < 10000; i++)
{
//配列strのi番目の要素の、
//配列strのi番目の要素の文字列の長さ - 1 番目の文字を出力する
Console.Write(str[i][str[i].Length - 1] + " ");
}
//計測終了
end = DateTime.Now;
Console.WriteLine();
//処理にかかった時間を秒単位で出力
Console.WriteLine((end - start).TotalSeconds);
}
}
str[i][str[i].Length - 1]
のところがヤバい。
集計しよう
ということで実行時間を集計していきます。今回はpaiza.io にて計測しました。10回ずつ交互に計測し、平均を取りました。最大値と最小値もあります。結果はこのようになりました。
結果発表
今回の計測では、10で割った余りスタイルよりも、下1桁の数字スタイルの方が処理が速いという結果になりました。確かに、10で割った余りスタイルの「string型からint型に変換して、それを10で割った余りを出力する」よりも、下1桁の数字スタイルの「各配列の要素に直接アクセスする」方が速そうな気がしますね。
まとめ
【悲報】10で割った余りスタイルさん
人に伝わりにくいだけでなく、実行速度の面でも敗北か/(^o^)\ /(^o^)\
感想
今回はpaiza.io さんで計測しましたが、Visual Studioとかで計測してみようと思いました。また、pythonやRubyなどのC#以外の言語でも同じ結果になるのか気になりました。