FC2ブログ

名もなき黒猫の散歩道

MENU

じゃんけんを判定する [Python3]

こんにちは。黒猫です。今回はちゃんとPythonを解説したいと思います!

前回の記事で40人でじゃんけんをしてはいけないことがよくわかりました。今回の記事はちょっとプログラミング側の話で、じゃんけんの勝敗をどうやってPythonで判定するのが一番良いのかについて述べたいと思います。

え、何でそんなこと考えないといけないかって?
実は前回の記事のデータ、2〜40人すべての計算が終わるまでになんと1日以上かかっているのです!つまり、いい加減な方法で勝負判定していると、もっと時間がかかってしまって、大変なことになります。こういう地道な努力と気配りがプログラミングでは大事だったりするのです。

では考えていきましょう。
2人程度のじゃんけんをプログラムで認識させるのであれば、じゃんけんの優劣(グーはパーに負けてチョキに勝つ、など)を全て記載して、勝敗を判定させれば良いと思います。

しかしこの方法では、人数が増えてくるとたちまち計算量がハンパなくなってきます。(3人なら3C2 = 3回の勝負判定くらいですが、10人なら10C2 = 45回の勝負判定、20人なら20C2 = 190回の勝負判定、というようにだんだんと増えてくる)
しかも3人以上の時には2人では起こりえない「あいこ」、つまり全員違う手を出す、という可能性も考えねばなりません。

ですので、方法を少し考えないといけません。

じゃんけんで勝負が着くとは、簡単に言えば「あいこ」にならないことです。
「あいこ」とは、

  1.  全員同じ手を出している
  2.  「グー」「チョキ」「パー」が出揃っている

の2通りが考えられます。逆に考えれば、「グー」「チョキ」「パー」のうち、どれか2種類だけが出ていれば勝負が着いている、ということです。

なので、例えばグー、チョキ、パーをそれぞれa, b, cと略記して、例えば10人が出した手をaabbbccabcと表現してやれば、あとはこの文字列を分析して何種類の文字があるのかを調べればよいことになります。

というわけで、以下の3つの方法を考えました。

  1. 集合の要素数で判断
  2. if で場合分け
  3. stripで削る

1. 集合の要素数で判断

Pythonには、“集合 (set)”という概念があります。これは“お互いに異なるデータの集まり”という意味です。例えば、

{あ, い, う}、{10, 21, 32, 43, 54}、{A, 65, え, 猫}

みたいなものはすべて集合ですが、

{あ, い, う, あ}

は、"あ"が2つあるので集合ではありません。この場合は強制的に"あ"が1つ削除されて、{あ, い, う}に変換されます。これを使ってやれば、

{a, a, b, b, b, c, c, a, b, c} --> {a, b, c}
{a, a, b, b, b, a, a, a, b, a} --> {a, b}
{a, a, a, a, a, a, a, a, a, a} --> {a}

というように変換可能ですので、あとは集合のデータの種類数(集合の長さ)を調べてやれば、勝敗が決まったかどうかが分かりそうです(上の例だと2番目だけ勝負が着いている)。

というわけでPythonでこれを書くと以下のようになります。
s = "aabbbccabc"       # じゃんけんの手を示した文字列をsと命名
s_set = set(s)         # 文字列sを集合に変換
if len(s_set) == 2:    # 集合の長さ(LENgth)が2のとき
    print("勝負あり") 
else:                  # 集合の長さが2以外のとき
    print("あいこ")

2. if で場合分け

Pythonには、文字列に目的の文字があるかどうかを検索する方法があります。それを使えば、

if aがある -- yes --> if bがある -- yes --> if cがない -- yes --> 勝負あり
if aがある -- yes --> if bがある -- yes --> if cがない -- no --> あいこ
if aがある -- yes --> if bがある -- no --> if cがない -- no --> 勝負あり
if aがある -- yes --> if bがある -- no --> if cがない -- yes --> あいこ

のように場合分けすることで勝負が着いたかどうかを判断できそうです。というわけでPythonでこれを書くと以下のようになります。
s = "aabbbccabc"             # じゃんけんの手を示した文字列をsと命名
if "a" in s:                 # 文字列sの中に"a"はあるか?
    if "b" in s:             # 文字列sの中に"b"はあるか?
        if "c" not in s:     # 文字列sの中に"c"は無いか?
            print("勝負あり")
        else:                # 文字列sの中に"c"がある時
            print("あいこ") 
    elif "c" in s:           # 文字列sの中に"b"は無いが"c"はあるか?
        print("勝負あり")
    else:                    # 文字列sの中に"b"も"c"も無い
        print("あいこ")
elif "b" in s:               # 文字列sの中に"a"は無いが"b"はあるか?
    if "c" in s:             # 文字列sの中に"c"はあるか?
        print("勝負あり") 
    else:                    # 文字列sの中に"c"が無い時
        print("あいこ")
else:                        # 文字列sの中に"a"も"b"も無い
    print("あいこ") 

3. stripで区切る

Pythonには、ある文字を使って文字列の両端からその文字を引き剥がす(strip)方法があります。例えば以下のような感じです。

"aabaaaacabaaa" -- aでstrip --> "baaaacab" 
"aabaababbbbb" -- bでstrip --> "aabaaba" 
"aaaaaaaaaaaaa" -- aでstrip --> "" 

複数文字を使ってstripすることもできます。

"aabaaaacabaaa" -- aとbでstrip --> "c"
"aabaababbbbb" -- aとbでstrip --> ""
"aabaababbbbb" -- aとcでstrip --> "baababbbbb" 
"aaaaaaaaaaaaa" -- aとbでstrip --> ""
"aaaaaaaaaaaaa" -- aとcでstrip --> ""

この例からわかるように、もし文字列に2種類の文字しか含まれない場合、その2種類の文字でstripしてやった時にのみ、文字列から文字がなくなってしまう、ということがわかります。
これを使えば、stripした後の文字列の長さを数えることで、勝負が着いたかどうかを判定できそうです。というわけでPythonでこれを書くと以下のようになります。
s = "aabbbccabc"                # じゃんけんの手を示した文字列をsと命名
method = ["ab", "bc", "ca"]     # 異なる手のペア(全3組)
ans = []                        # 解析結果の一時保存場所
for i in method:                # methodから1組ずつ取り出して解析(iにab, bc, caのいずれかが代入される)
    p = s                       # コピー作成(元の文字列を変更しないよう)
    ans.append(len(p.strip(i))) # iをpからstripした後のpの文字数(LENgth)を一時保存
if ans.count(0) == 1:           # strip後に文字列pが消えた(文字数 = 0)ときが1回だけあるとき
    print("勝負あり") 
else:                           # 上記以外
    print("あいこ") 


検証
という感じでじゃんけん勝負判定メソッドを3つ用意しました。次は、この実行速度を測ります。これ以上説明を書くと長ったらしいので、測定に使用した本丸のコードは追記に載せます(勝負判定メソッド自体に変化はありません)。どうやってPython3でグラフを書くのかなど、気になる方は見て下さい。

今回は1000人でのじゃんけんを10000回(勝負が着くとは限らない)行って、1回あたりの処理に必要な時間を調べています。結果は以下のような感じになりました。
janken_speedtest.png  
というわけで2つ目の「if で場合分け」法が一番速い、ということが分かりました。他に比べて5倍以上速いですね。すばらしい!

この結果を基に、前回の記事でのシミュレーションはすべて、この「ifで場合分け」法を使って行っています。これでも1日かかるとは。。やはり40人でじゃんけんしてはいけませんね。。笑

実は黒猫は、一番はじめに3.のstripの方法を思いついて計算を開始したのですが、2日経っても計算が終わらなかったので、諦めて改善方法を探ることにしたのが、今回の発端でした。いやはや、プログラムの効率って本当に大事です。。痛感。。


そんな感じで、終わりたいと思います!
私の自己満足にお付き合い頂きありがとうございました!笑

スポンサーサイト

クラスのみんなでじゃんけん [Python3]

こんにちは、黒猫です。もう20年くらい昔、小学生の黒猫はあることを思っていました。

この教室のみんなで一緒にじゃんけんしてみたい」と。

基本的に10人くらい集まってじゃんけんする時は、2人組をたくさん作ってじゃんけんして、その勝った人同士でまたじゃんけんする、というようなことを繰り返すと思います。もちろんこれは、大人数で同時にじゃんけんすると、勝者が決まるまでに時間がかかってしまうことを経験的に知っているためです。

では、もしもクラスの全員(40人)が一緒にじゃんけんをしたらどれくらい時間がかかるのでしょうか?これが今回解きたい問題です。

というわけでいつも通り、Pythonでシミュレーションしてみることにしました!
具体的なコードは次回の記事に書くとして(自己満です 笑)、さっそく結果に行きましょう!

下のグラフでは、横軸は“じゃんけんに参加した人数”、縦軸は“1回勝負が着く(あいこではなくなる)までにじゃんけんをした回数”を示します。各人数、100シミュレーション行って、その平均値を図示しました。
janken_result_100trial_2-40people_v3.png    
100回しかシミュレーションしていないので、かなりブレブレではありますが、だいたいこんな感じでした。というわけで、40人でじゃんけんして1回勝負が着くためには、約320万回かかるみたいですね!1回のじゃんけんに5秒かかるとしたら、1600万秒かかるので、寝食なんてせずに行ったとすれば、だいたい185日かかるみたいですね!は、半年だと。。

というわけで「40人でじゃんけんはやってはいけない」が答えです 笑
ちなみに、16人までを拡大してみるとこんな感じです。
janken_result_100trial_2-40people(upto16).png 
16人程度で既に200回近くかかるので、1勝負つくのに1000秒、つまり約15分かかることになります。まだまだ現実的に行うには厳しいですね。10人でやっと20回くらい、つまり1分半くらいなので、これならまだできるかな?という感じです。

ですので、今回のシミュレーションで、「じゃんけんを一度にするなら、多くても10人まで」ということがわかりました。是非日常生活(?)に役立てて下さい 笑

ではでは今回はこのあたりで。最後まで読んで下さりありがとうございました!プログラミングに興味がある方は、次回の記事も是非見て下さいね!

読了して

こんにちは、黒猫です。先日からせっせと読んでいて本をやっと読み終わったので、自分のためにちょっとした感想を残しておきたいと思います。


読んだのは小説やらエッセイやらではなく、「入門Python3」という(これです)、これまた誰でも何の本かわかるようなものです 笑

正直、これを読む以前に既にPythonの基礎は知っていたので、「確認程度に読み直そう」と考えながら読んでいました。

が。

めちゃくちゃ勉強になりました。結局使ったことがなかったためによく知らなかったSQLのこと、なじみのなかったウェブサーバーのこと、サーバーとクライアントの関係、などなど。さらに、Pythonでこれらのことに上手く対応できるということも、とても良く理解できました。
この本は入門書にしてはハードルが高すぎるとは思いますが 笑、初心者から初級者になった人くらいが読むと、とても世界が広がりそうです。

正直、この本を読み終わったらC#の勉強をちゃんと始めようかと思っていたのですが。。もっとPythonを深めた方が良いのだろうか。。二兎追うと失敗しそうだし。。笑
でも、インタプリタ言語のPythonとは別に、ひとつくらいコンパイル言語を学びたいんですよね。。コンパイル言語は、C++かSwiftかC#かでずっと迷っていましたが、難易度と今までの言語の成熟度合い、普及率を考えるとC#だろうなとは考えています。とりあえずC#も初心者から初級者くらいにはなっておいて損はないか。。

まぁせっかくC#の本も買っているので(←)、C#をやりますか。次回からは少しC#の記事が増えそうですね。誰も期待してないかも知れませんが 笑、お楽しみに。それでは最後まで読んで頂きありがとうございました!

続・まじめに数当てをやってみた

こんにちは黒猫です。今回は前回の続きで、数当てする方法の改善に挑みます。前回記載した、


ランダムのいいところは、1~100全ての数字に対して等しく、1発で当てる可能性を秘めていることです。つまり、数字の当てやすさを全ての数字に対して均等に配分してくれる性質があります。この性質を、無駄がないけれども数字の当てやすさが均等ではない1/2法に足し合わせることができれば、もう少し改善できるかも知れません

という予想に則って、次のような案を考えました。

1. 推測後の可能性のある範囲の大きさが、推測前の可能性のある範囲の大きさの1/3以下になるまでランダムで粘り、1/3以下になったら1/2法で確実に求める(毎回判断ver.1)
2. 1.と同じだが、1回目の推測だけは1/2法を使う(毎回判断ver.2)
3. 開始地点をランダムにして、あとは1/2法で頑張る(はじめだけランダム)
4. はじめ1回は1/2法で全体を2分して、そこからランダムに選んでいく(はじめだけ1/2法)

というわけで1.から順番にシミュレーションしてみました。前回と同様、1~100の各値を答えにした時の試行を各1000回繰り返し、その時の平均値と標準誤差を示しています。

1. 毎回判断ver.1
1.png
ぜ、全然変わらないだと・・・!?ま、まぁこういうこともあるよね・・・汗


2. 毎回判断ver.2
2.png
山がいっぱいできました 笑 少し良くなっている気はしますが、波打っているせいでバラツキが大きいので、もう少し何とかしたいところ。 


3. はじめだけランダム
3.png う、美しい・・・。これだと全体的に6回程度で当てられそうです!


4. はじめだけ1/2法
4.png カモメみたいになってしまいました 笑 全体的にあまり改善されてなさそうです。

というわけで全部を試してみた結果、 3. はじめだけランダム法 が最も優秀そうだということがわかりました!ちなみに謎の数の値を無視して、全体での当てるまでにかかった試行回数の平均値を求めると下のようになりました。
Statics.png
全体的な平均値も、1/2法とはじめだけランダム法とではほとんど変わりませんでした。どうしてはじめだけランダム法ではバラツキがここまで減ったのか、よくよく考えれば当たり前な気もしますが(詳しくは追記へ)、逆に今回学んだのは、「予想ができなくても、プログラミングで網羅的に試してみて仮定を生み出すことができる」ということ知れたことです。やはりプログラミングは新しいモノの見方を与えてくれるような気がします。

こういうことを知ったら、実際に試してみたくなるのが世の常です 笑
というわけで以下に、数当てプログラムを作りました。しかし、今回はあなたが1つ数字を決め、コンピューターがそれを当てる、というものです(前のブログ記事と立場が逆バージョン)。上の結果も踏まえて、コンピューターには6回しかチャンスを与えていません。コンピューターの推理方法も3通りありますので、違いを感じるかどうか、是非試してみて下さい(再生ボタンを押すと始まります)!



それではこのあたりで!最後まで読んで下さりありがとうございました!

まじめに数当てをやってみた

皆さんお久しぶりです、黒猫です。最近色々あってプログラミング(Python3)から遠ざかっていたので、リハビリがてらに今回はまじめに数当てをやることにしました。

え、「数当てって何?」ですって?それはこんなゲームです(ゲーム開始後「降参」と入力すると答えを教えてくれます、昔ここに載せたものとほとんど同じです)。


簡単に言うと、1から100までの中にある「謎の数」を当てるゲームです。毎回、推測した数字が謎の数より大きいか小さいかを教えてくれます。そのヒントを基に謎の数を当てるわけです。

実際、与えられたヒントを基にデタラメに数を推測してやってみると、下のような結果になります。
random.png  
ここでは、1から100までの各値を謎の数に設定して、プログラムにその数字を当てさせています。各値に1000試行かけて、その平均値(と標準誤差)を表したのが上の図です(色は10個毎に変えています)。だいたい8回くらいチャンスがあれば平均的には当てられる、ということになります。


で、今回黒猫が試したのは、「じゃあもう少し工夫して、少ないチャンスで当てられるようにならないのか?」ということです。


少ないチャンスで数を当てるには、どれだけ効率よく候補を絞ることができるかがカギとなりそうです。なのでまずは単純に、「常に可能性のある範囲の数の真ん中を狙う」という方法を考えました(1/2法)。例えば、答えが27なら、

27を当てる 
という感じで6回で当てることができます。これを1~100全ての数でシミュレーションしてみると、
half.png  
となりました。50は1回で確実に当てられるし、おそらくこれが最善策なのでは、と思います。

というより、黒猫は結局これを凌駕する方法を思いつかなかったのです 泣

・・・と、ここで終わっては面白くないので、
7回もかかることがこんなにあったらダメだろう
という難癖をつけ 笑、その解決に挑みました。

ランダムのいいところは、1~100全ての数字に対して等しく、1発で当てる可能性を秘めていることです。つまり、数字の当てやすさを全ての数字に対して均等に配分してくれる性質があります。この性質を、無駄がないけれども数字の当てやすさが均等ではない1/2法に足し合わせることができれば、もう少し改善できるかも知れません。

・・・と、ここでかなりの長さになってきたので、続きは次回にします 笑
ここまで読んで下さってありがとうございました、次回もお楽しみに!





大蛇の咆哮

ヘビが吠えるのかどうかはさておき 笑

こんにちは、黒猫です。

前回のブログでは、Pythonがいかに遅いかをまざまざと見せつけられたため、さらに他の言語とも比較してみようと思い、Java, Ruby, R言語も追加して全部やり直してみました。その結果がこちら!
Fig_180222_test_1.png

なんでPython2の方が遅くなってるんだ・・・?
もしかしすると私のPCで時間を計る時に、他のアプリをどれくらい開いているのかに、結果が影響を受けているのかも知れません。しかし全てのデータは同じ日に取っていますので、やっぱりPythonが遅いということには変わりないようです。

ちなみに速いお方達の拡大図はこちら。

Fig_180222_test_2.png 
じ、Javaはえぇ。。。
このあたりはコンパイラ(機械語へ翻訳するプログラム)がいかに優秀かに依存しているようです。ちなみにこれを計った後に、C++を最適化してコンパイル(機械語へ翻訳)する方法を知りまして、それをやってみると、0マイクロ秒以下になって計測不能になりました
なので、おそらく最速はC++です。Cは試していませんが、おそらくこの程度ならC++とほぼ同じ速度を発揮すると思います。


というわけで、汚名を挽回できず最下位に終わったPython
しかし、ちまた(特に機械学習やAI系)ではPythonは大人気です。機械学習やAIでこういう煩雑な処理が皆無とはとても思えません。なので何とかなるのではないかと思って色々と考えてみました。
今回使用したコードは以下になります。


#coding: utf-8
import time

for i in range(10):
    start = time.time() #計測時間開始
    ans = 0
    for i in range(100000000):
        ans += (i+1)
    end = time.time() #計測時間終了
    print(end - start)


このコードがなぜ遅いかというと、1億回の繰り返しを行っている“for i in range(100000000)”というところが遅いからに他なりません。ここでは、「ansという名前の変数を読んできては、数字を足して、ansにもう一度値を代入する」という動作を1億回行っています。実はこの「ansにもう一度値を代入する」というのは時間を遅くする要因になったりします。というわけで、値を代入する回数を減らそうと思いました。その結果がこちら。


#coding: utf-8
import time

def ichioku(que):
    for i in range(100000000):
        que += (i+1)
    return que

for i in range(5):
    start = time.time() #計測時間開始
    ans = 0
    ans = ichioku(ans)
    end = time.time() #計測時間終了
    print(end - start)


このコードでは、ichiokuという名前の関数(道具)を作っています。この関数を使えば、ある値を渡してやると、その関数の中で1億回足し算をしてくれ、その結果だけを返してくれます。つまり上のコードと比べて、「ansにもう一度値を代入する」という動作が少なくて済みます。

さらに、関数を作ってやると、「JITコンパイラ」というものを使うことが出来ます。これは簡単に言うと、「Pythonの処理を最適化しよう」という道具です。これの使い方は簡単で、以下のように、"import numba" と "@numba.jit" を書き加えるだけです。


#coding: utf-8
import time
import numba

@numba.jit
def ichioku(que):
    for i in range(100000000):
        que += (i+1)
    return que

for i in range(5):
    start = time.time() #計測時間開始
    ans = 0
    result = ichioku(ans)
    end = time.time() #計測時間終了
    print(end - start)


というような感じで、3種類用意してみました。果たしてその結果はいかに!?

Fig_180222_python.png 

Inlineが何も変化を加えていない1つ目、Definitionが関数を作った2つ目、そしてJITがJITコンパイラを用いた3つ目です。
JITコンパイラ速過ぎるやろ。。
ちなみに平均値を書くと、Inlineが27秒、Definitionが17秒、そしてJITが0.2秒でした。
Definitionで約2倍に速度が向上するのにもびっくりしたのですが、それにもましてJITコンパイラの威力にただただ脱帽しました。これでもC/C++・C#・Javaには敵わないのですが、使える程度には十分に速いと私は思います。
(ちなみに関数を作ると今回Pythonは速くなりましたが、Rubyで同じことをしても速くなりませんでしたし、C#では遅くなってしまいました。このあたりは書き方や、言語のクセに、結果が左右されるようです)


というわけで、何とか汚名を挽回できました。よかったね、Python 笑
(ちなみにC++とPython以外の速度の向上方法は調べておりませんので、全ての言語がもっと速くなる可能性は十分にあります。特にSwiftは速いと言われるのでもっと速くできると思います。)

というわけで、自己満足は一区切り尽きました 笑
読んで下さった方々、どうもありがとうございました!


続・言葉の壁

こんにちは黒猫です。前回の記事を書いてから、C++を主に勉強していたのですが、「C#の方が汎用性高いですよ」というアドバイスを受け、今はC#をメインに勉強しています。
(C++のメモリの扱いが意味わからなくて挫折したなんて一言も言ってませんからね)


C#は、Microsoftが2000年頃に開発したプログラミング言語です。"C"と付くだけあって、C/C++をもちろん踏襲してはいるのですが、どちらかというと、C/C++よりもJavaという言語によく似ていると言われます。開発元がMicrosoftなだけあって、Windows用のアプリケーションの作成には今でもかなり用いられています。昔はWindows“でしか”動かない印象が強かったC#ですが、今ではMacやLinuxでも使われるように進化してきています。

一方、Appleは昔から、Objective-Cという言語を用いて開発を行ってきていました。しかし、2014年にAppleも新しいプログラミング言語を開発しました。それがSwiftと呼ばれる言語です。少し前のiPadが公表された時に「子供でもプログラミングを学べる」という謳い文句で、“Playground”というアプリが公表されました。このPlaygroundはまさに、Swiftで動いています。黒猫がプログラミングに興味を持つきっかけになったのも、実はこのPlaygroundです。

まぁなんでこんなプログラミング言語の紹介をしたかというと、「結局どれが速いんだろう」というのが知りたくて、上記の言語を試してみたので、それをお見せしたかったからです。いわゆる自己満足ですね 笑

やったことは、前回の記事と全く同じです(1億回の足し算に要する時間を比較)。
というわけで結果に移りましょう!刮目せよ!
(Python3とC++も計り直しました)
Fig1_180214.png ぱ、Python遅すぎるやろ。。。

Python以外がもう見えなくなってしまいそうです 笑

ちなみにPythonは少し前にPython2からPython3へ進化を遂げたので、
今回はその2つの比較もしてみたのですが。。
なんで2より3の方が遅いんや!?
完全にPythonだけに蛇足なことがあったのかもしれません 笑
(注:pythonとは本来ヘビの一種です)

Python2に1点だけ30秒超えがありますが、これはなぜか何回やり直しても出ます。
反復処理で10回、1億回の足し算を計算させているのですが、
その1回目だけ、なぜか時間が延びる傾向がありました。
(たまに2,3秒しか延びないこともあるのですが、それでも2回目以降より遅い)
何なのでしょうね、1回目は色々と初期化するから遅くなるのかな?


さて、見えにくい残りの5本を拡大してみましょう!
Fig2_180214.png  
C#が一番速くて、その次にCおよびC++、その次にSwift_1、Swift_2(違いは後述)という結果になりました。

CやC++は速いとの評判が強いので、C#の方が速かったのは意外でした。CやC++のコードの書き方が悪かったのかもしれません。それか、この2つはコンパイル言語なので、コードを別ファイルに書き換える(コンパイルする)ために別のツールを使うのですが、もしかしたらそのツールの性能の差が出ているのかも知れませんね(いかにそのツールが機械にとって読みやすい物を書いているかどうか、ということです)。

この中でSwiftは唯一コンパイルしてもしなくても使える言語です。Swift_1はコンパイル無し、Swift_2はコンパイルありで実験してみたのですが、予想外にコンパイルが無い方が速いという結果になりました。何でなんだろ。。Swiftは今回のためにちょこっとだけ勉強しただけなので、よく分かりません 笑

こういう結果を見ると、Pythonはダメなんじゃないかという雰囲気になってしまいますが、私はPythonが大好きです。やはり何と言ってもシンプルですし、特に科学系のデータを扱う時には、Pythonはかなり道具が揃っています。上のグラフも、今回はPythonで書いてみました。Pythonならプログラミング素人の黒猫でもこれくらいなら作ることが出来るのが、Pythonのすごいところです。

しかし、やはり計算量が必要な時には言語の使い分けが必要なのもまた事実なのかも知れませんね。プログラミングは奥が深いと思いました。

というわけで今日はこのあたりで。読んで下さりありがとうございました!


追記で今回使ったソースコードを置いておきます。

言葉の壁

こんにちは、黒猫です。最近プログラミングのことしか書いてない気がしますが、今日もプログラミングの話。


年始の挨拶にも書きましたが、最近C++をちょっとずつ勉強しています。C++とPythonは、同じ「オブジェクト指向性言語」というジャンルには属しますが、全く構造の違う言語なので、なかなか苦労する毎日です。そんな中、この2つの言語の差がどれくらいあるのか気になって調べてみました。

C++は、プログラミング言語として有名な「C言語」の発展系にあたる言語で、「コンパイル言語」のひとつとして知られています。コンパイル言語とは、簡単に言うと、「人間が書いたものを、一度コンピューター内で翻訳して新しいファイルを作成し、その新しいファイルを実行することで、書いたプログラムを実行する」という形式を取る言語を言います。

一方でPythonは、最近はやりの機械学習などで大活躍中の言語で、「インタプリタ言語」のひとつです。インタプリタ言語とは、「人が書いたものを、1行ずつ翻訳することで、書いたプログラミングを実行する」という形式をとる言語を言います。

つまり、C++では一度別のファイルを作らないと動かないのに対して、Pythonでは書いたコードのファイルをそのまま実行できるという利点があります。Pythonの方が人間が実行するのは楽なのです。しかし、コンピューターからすれば、一度翻訳してくれているファイルがある方が、スムーズに処理できるわけで、そういう意味でC++はコンピューターにとっては実行しやすい言語となります。

しかし昨今のコンピューター技術は凄まじく、インタプリタ言語でもかなりの速度で実行することが出来るようになってきています。そんな背景から、「実際、どれくらい計算スピード違うんだろ?」と思うに至り、計算することにしました。・・・すごい前置きしっかり書いてしまった 笑

やった内容は、「1から1億まで足すのに必要な時間」を10回測って、その平均値を求めるというものです。その時に使ったPython3とC++のコードは追記に載せました。というわけで早速その結果がこちら!

Py3_vs_C++

Python3の平均時間が約28.3秒、C++の平均時間が約0.37秒でした。つまりPython3よりもC++の方が100倍計算が速いということになります(もちろんP < 0.001で統計的に有意差ばっちり)。C++すごすぎるやろ。。

Pythonは、色々なツールが揃っていて非常に便利な上に、コードも書きやすい言語なのですが、処理が遅いのは前から少し感じていて、そういう言語の特徴に由来する壁を越える必要がある時に備えて、C++をやろうとは思ったのですが。。こんなに速いとは思ってもいませんでした。C++、好きになりそうです(単純)。

またC++をブログで実行する術を探さねばですね。
ではそんな感じで、最後まで読んで下さりありがとうございました!

クリスマスとお正月はパソコンと遊ぼう

クリスマスも終わりましたね!皆様いかがお過ごしでしょうか?

サンフランシスコ市内ユニオンスクエアでは、こんな立派なツリーが立っていました。
S__10215595.jpg 

なんととその隣には屋外スケート場までできていました!
S__10215597.jpg 

私はスケート苦手なので滑ってはいませんが。。
こういうものがあると、さぞかし「リア充(カップル)」が多いイメージが膨らむかも知れませんが、案外12/24の昼のサンフランシスコ市内ではカップルは少なく、どちらかというと友達複数人グループが目立った印象です。アメリカだし、クリスマスは家族で、みたいな感じなのかも知れませんね。人もいつもより多いとはあまり感じませんでした。

まぁそんなクリスマスシーズンですが、黒猫からみなさまにゲームをプレゼントすべく(嘘)、
数字当てゲームを作ってみました!



簡単に言うと、1 ~ X(自分で設定できる)までの整数のうちで、パソコンが選んだ数字を当てるというゲームです。1回数字を入力する度に、パソコンが選んだ数字がその数字より大きいか小さいかを答えてくれます。それを基に頑張って推理して下さい!

初めにプレイヤー名の入力、次にXの設定、次に入力回数の設定です。それが終わったらゲーム開始になります。ちなみに、ゲーム開始後の数字入力欄に「Give up」と入力すると、途中で投了できます。
プレイヤー名以外は半角で打たないと認識しないので注意して下さい!終わった後は上の画面のRunボタン(▶)を押すと、もう一度挑戦できます。

是非是非楽しんで下さい!君は何回で当てられるかな?
それではメリークリスマス、良いお年を!

パソコンの計算能力

お久しぶりです、黒猫です。今日は室温が20℃を久々に下回って、寒くなったな、と思う毎日です。


さて、今日はプログラミングの話。
ふと「パソコンの計算の速さってどれくらいなのだろう」と思い立ち、「1から整数xまで順番に足し合わせるのに必要な時間」を計測することにしました(なぜ、とは聞かないで)。
使った言語はPython3で、こんな感じに書いて、

コード
(画像でごめんなさい、初心者なので不適切な箇所があるかも知れませんがあしからず)

あとは2行目の1e5 (= 100000、これが整数X)を色々と変えて、実行してから9のアウトプットが出てくるまでの時間を計ってもらいました(by Atomのパッケージ)。

で、その結果が以下の感じになりました。
Python3_speedtest 見事に、1から10の5乗までを足す計算を境に、計算時間が直線的に増加しています。
このグラフは両軸常用対数なので、この範囲では
log(要した時間) = k × log(整数X) + C
が成立しているということです。手元にある統計ソフトで近似すると(図の点線)、k = 0.979、C = -6.381だったので、計算し直せば、私のノートパソコン(MacBook)では、

整数Xまでを順番に足すのに要する時間(秒) = 4.16 × (10の-7乗) ×(整数X)の0.979乗

となるようです!

だからどうした。

・・・と自分でも突っ込みたくなりましたが、まぁそんな感じになるとは知らなかったので、少し感動しました 笑。整数Xは別の言い方をすれば「足し算をした回数」であることと、0.979は1とほとんど一緒であることを考えれば、
整数Xまでを順番に足すのに要する時間(秒) = 4.16 × (10の-7乗) ×(足し算をした回数)
と、近似できそうですので、1回の足し算あたり0.416マイクロ秒かかっている、ということになるのかもしれません。この0.416マイクロ秒が何を示すのかは分かりませんが、おそらく使用したプログラム言語、コードの書き方、ハードの能力など、色々な因子が絡み合った結果なのだと思います。ちなみに、10の5乗以下の足し算は、プログラムが動くまでにかかる時間が足し算の時間より長いために、一定になっていると思われます。それにしてもものすごい速さで計算できるのですね。改めて実感しました。

この計算をしている時に少し面白いことを知ったのですが、それを記事にするには私の知識が浅すぎるので、またの機会に書きたいと思います。

それでは、最後まで読んで下さってありがとうございました!



生まれてからxx日目はいつでしょう?

こんにちは、黒猫です。昨日ははじめてこちらで雨に降られました。

小粒の細かい雨で、日本はそろそろ梅雨で豪雨かと思うと、良い環境だなぁと思います。雨期にはまだ遭遇したことがありませんので、もしかするとすごいのかも知れませんが。

先日、プログラミングを始めたと書きました。で、今回は勉強のためにとあるプログラムを書きました。その名も「生まれてから○○日目は□□年××月△△日だと教えてあげちゃう君」です!
(ネーミングセンス・・・)

で、早速試してみたのですが。案外、生まれてからかなりの日が過ぎているものだなぁと感じました。5000日目とか、そんなに前に通過していたの!?という印象です。
(ちなみに生まれてから5000日目は、中学2年生の秋くらいでした)
これまでにそれだけ寝て起きてきたのかと思うと。。感慨深いというか、なんか無駄に過ごした日も多いなと思ったり。。
逆に30000日目(だいたい82歳)とか、そんな年月なのかと感じてみたり。日本とか世界がどうなっているのか、全然想像できない。。

と、どうでも良い感想を得たのでブログを書きました 笑
こういうプログラムをこういうブログ上で走らせるにはどうしたら良いんだろうか。。
(そもそもPythonでは厳しいのかな?Javaは有名な気がするけども。。)
まだまだ学ばなければならないことが多そうです!
そんな感じで!読んで下さってありがとうございました!

新しい言葉を使うこと

こんにちは、黒猫です。

実はちょっと前からプログラミングを遊びで始めてみました。
まだはじめて1ヶ月くらいしか経っていませんので、
少しずつ勉強している感じです。

その勉強の一環として、
「パソコンとじゃんけんするプログラムを組んでみたら?」
と言われたので、それにこの1ヶ月挑戦していました。

何とか、じゃんけんをパソコンとできるようになったのですが、
これを作っている間、「じゃんけん」というものは何かとても考えた気がします。
グーを出した相手に対して、グーならあいこ、チョキなら負け、パーなら勝ち。
これは簡単なのですが、いざパソコンにこのルールを分からせるにはどうすればよいのか。

もちろん、自分相手を別にしたグーチョキパーの全部の組み合わせ(3*3 = 9通り)を書いて、
それぞれの勝敗をパソコンに分からせても良いのですが、
それではプログラムを書く量がどうしても長くなってしまう。
結局、グーチョキパーを数字(-1, 0, 1)にして、計算の結果で勝敗(or あいこ)を理解させることにしました。
久しぶりに算数を考えました 笑

英語やドイツ語を前向きに初めて学んだ時にも感じたことですが、
(前向きに、というのは中学の頃、黒猫は英語が嫌いだったためです 笑)
日本語ではない言語は、外国人が物事を日本人と異なるように理解していることを見せつけてきます。

例えば英語なら、普通の疑問文でも否定疑問文でも、“Yes”と答えると「自分(主語)が」肯定的であることを示しますし、
(日本語で“はい”と答えると「相手に」肯定的であることを示しますよね)
ドイツ語の時は物に性別があることに衝撃を受けました。
(すいません、ドイツ語は1年しかやってないのでこれくらいしか分かりません 笑)

プログラミング言語もまた、パソコンが物事をどうとらえるのかを、私に非常にアピールしてきます。
やはりプログラミング言語もある意味、「言語」なのだなと思いました。
感じるものは文化ではなく、数学ではありますが 笑


プログラミングの目標は、
自分の研究の中で動画解析などに使っていきたいと思っているのですが、
それはかなり夢だと思っていますので、
とりあえず今は簡単なゲームやアプリケーションを作っていきたいと思っています。
何か私に次のテーマを与えてやってください 笑


それではこのあたりで!

このカテゴリーに該当する記事はありません。