2012-12-16 [長年日記]
2012-12-10 [長年日記]
■括弧を忘れてmethodが返ってくる罠
やってることは嘘だけど、ざっと省略してこんなソースを書いてた。
n1=foo() #datetime型 n2=bar #datetime型 td=n1-n2 #timedelta型 if td.total_seconds>0: print "n1が%s秒早いです"% td.total_seconds() else: print "n2が%s秒早いです"% -td.total_seconds()
これ、elseが実行されなかった。
n2のほうが小さい状況はまずありえないけど「一応書いておいた」ケース。
なのでそこを通すテストをわざわざやってみるまで間違いに気づかなかった。
if の部分、td.total_secondsの括弧を忘れていて、method型が返ってきてた。(Python2系では)0と比較することが許されて、(多分)必ず真。
テストして気がついてよかった。
2012-12-01 [長年日記]
■2012年11月の読書メーター
読んだ本の数:4冊
読んだページ数:1272ページ
ナイス数:34ナイス
書物審問 (講談社ノベルス)の感想
犯人……あんた馬鹿だろ……
読了日:11月27日 著者:赤城 毅疾走!千マイル急行〈下〉 (ソノラマ文庫)
読了日:11月22日 著者:小川 一水図書館戦争 図書館戦争シリーズ(1) (角川文庫)の感想
p126「正論は正しい、だが正論を武器にする奴は正しくない」読んでいてニヤニヤしたり涙が浮かんだりと、外で読むには向かない本だった。郁が図書隊員を目指すきっかけになった事件のくだりですでに涙が出る。
読了日:11月18日 著者:有川 浩疾走!千マイル急行〈上〉 (ソノラマ文庫)
読了日:11月11日 著者:小川 一水
読書メーター
2012-11-26 [長年日記]
■random.shuffleの話
かなり小さい len(x) であっても、 x の順列はほとんどの乱数生成器の周期よりも大きくなるので注意してください; このことは長いシーケンスに対してはほとんどの順列は生成されないことを意味します。
9.6. random - 擬似乱数を生成する - Python 2.7ja1 documentation
どういうことだろう?
例えば乱数の周期が5しかないとする。この乱数で要素5の配列をシャッフルする。
[4, 2, 3, 5, 1]
とでた。
まあシャッフルされたっぽい。
繰り返してみる。
[2, 3, 5, 1, 4]
[5, 1, 4, 2, 3]
[4, 2, 3, 5, 1]
[1, 4, 2, 3, 5]
[5, 1, 4, 2, 3]
という感じで出てきた。
順列組み合わせは5!あるはずだが、[4, 2, 3, 5, 1, 4, 2, 3, 5] の部分列5種類しか出てこない。
こういうことが起きるって話か。
ところで「かなり小さい len(x)」っていったいどのぐらいだろう?
Python は中心となる乱数生成器として Mersenne Twister を使います。これは 53 ビットの浮動小数点を生成し、周期が 2**19937-1、本体は C で実装されていて、高速でスレッドセーフです。
9.6. random - 擬似乱数を生成する - Python 2.7ja1 documentation
周期は2**19937-1だそうだ。
桁数だけ評価する
\(\log_{10}~2^{19937}~+~1=~19937~\times~\log_{10}~2~+~1\)
ですな。
import math 19937*math.log10(2)+1=6002.635023552793
まあ、6002桁ぐらい*1。
順列組み合わせが6002桁ぐらいになる配列。
math.log10(math.factorial(2081)) #=> 6003.615625445271
このへんか。
2000個程度の配列から上はrandom.shuffle()は十分にランダムではない。
実際は、もっと小さな配列からrandom.shuffle()の結果に周期性が入り込んでくるはずだ。
*1 mathモジュールは19937*math.log10(2)+1でもmath.log10(2**19937)+1でも、同じ結果を返すのだけどね。:-P