下記のお題で書く。積分や分数を含む式。
Q.169 ☆5
— どちゃ楽数学bot (@so_easy_math) 2017年7月26日
次の極限値を計算せよ。
Find the limiting value.pic.twitter.com/T9mOJmpvJN
十分大きな については において
であるから
より
感想
ここまで来たら何で書いても多分しんどい。数学やってる人はえらい。
下記のお題で書く。積分や分数を含む式。
Q.169 ☆5
— どちゃ楽数学bot (@so_easy_math) 2017年7月26日
次の極限値を計算せよ。
Find the limiting value.pic.twitter.com/T9mOJmpvJN
十分大きな については において
であるから
より
ここまで来たら何で書いても多分しんどい。数学やってる人はえらい。
はてながMathJaxに対応しているらしいので、試しに使用してみる。
題材は下記の問題の解答を書くこと、としてみる。
Q.127 ☆8 [高2鉄緑校内模試]
— どちゃ楽数学bot (@so_easy_math) 2017年7月25日
(a+b)(b+c)(c+a)=2^2016を満たす自然数の3つ組(a,b,c)は幾つあるか。
ここでは、 に対して下記の一般解を求めることから始める。
として一般性を損なわない。
右辺の素因数は2のべきなので、左辺の各項(?)は
と書くことができる。ここで の大小関係から
が言える。
明らかに いずれかに奇数があるとすると、他の2つも必ず奇数となる。逆に、いずれかに偶数があると、他の2つも必ず偶数となることが容易に言える。
上記から は常に偶数であり、この差を と表すと、(a)の第一式から
と書ける。また、これを(a)の第二式、第三式に適用すると
となり、
となる。
(b)より、 となるためには が必要。(a)とあわせると となる。
ここで奇数解の場合、 となりうるのは の時のみ。すなわち、 となり、解は
となる。
一方、偶数解においては に対する解 がある場合、
に対する解 が必ず存在することが容易に確認できる。この関係を偶数解である限り繰り返したどることで、 に対する偶数解 に対して、 に対する奇数解 を得ることができる。逆にいうと、偶数解はある に対する奇数解 を用いて に対する解 と表すことができる。
前記の議論から、すべての解は奇数解 を用いて
と表すことができる。
(c)における奇数解の定式化と(d)における一般化を踏まえれば を用いて
により におけるすべての解が得られることがわかる。なお、対応する は
であり、すべての は異なる解を生成する。
原題はの解の数を求めるのであるから、(e)より を満たす の組み合わせの個数を数えれば良い。
これに該当するのは の計336個である。
sh/bashのパイプ/リダイレクションの使い方についてよく使いがちなものを理解できるようにまとめておく。
シェルスクリプトに書かれているリダイレクションが理解できない。
これまで、運用とかしてこなかったので人の書いたスクリプトを読むこともなく生きてきて、シェルはtcshでできる部分でいいや、という感じで生きてきた。でも環境はいつもデフォルトで使っちゃう派なので何かしら自動化しようとするとsh/bashを使わないと色々めんどいことに気づいた。しかたがないのでいまさらながらリダイレクションの記法について学ぶことにしてみた。
自分の理解度テスト的に下記を上げてみたけど、こんな感じ。
cmd > file # わかる cmd >& file # なんだっけ? cmd1 | cmd2 # わかる cmd1 |& cmd2 # わかる気もする。でも自分で書くときはこれが出てこない。 cmd 2>&1 > /dev/null # えっ?
以下に大体の読み方の基本から順番に書いていく。
sh/bashのリダイレクションは基本的に (ディスクリプタ)> (ファイル) の羅列の形式である。
たとえば、
cmd 1> file
だとディスクリプタ1の出力先をfileという名前のファイルに設定する、という意味になる。
基本的にディスクリプタの1は標準出力、2は標準エラー出力なので、下記は「標準出力の出力先をfile1に、標準エラー出力の出力先をfile2に設定する」という意味になる。
cmd 1> file1 2> file2
>の代わりに>>を使うとファイルに追記する意味になる。
cmd 1>> file1 cmd >> file1
パイプは標準出力の出力先を後続のコマンドの標準入力に設定することを意味する。
下記はcmd1の標準出力をcmd2の標準入力に設定する。
cmd1 | cmd2
パイプにはディスクリプタ番号は指定できない。常に標準出力を次のコマンドの標準入力につなぐ。
>& 記号を使ったディスクリプタの複製について説明するが、これは複製?よくわからないので複製というのは「そういう名前」だと思って深く考えないほうが読みやすいかもしれない。
a>&b はディスクリプタaの出力先をディスクリプタbと同じにすることを意味する。
下記は標準エラー出力を標準出力と同じターミナルに出力する。
cmd 2>&1
なお、ディスクリプタaは省略できてデフォルトは2である。bは省略不可。
つまり、下記も同じ意味になる。
cmd >&1
複数の記述がある場合、基本的には左から解釈される。
この過程をこれから述べるように表の形式で理解していくと出力結果を考えやすい。
基本的に何もしなければ標準出力等の出力先は下記のように設定されている。
ディスクリプタ | 出力先(当初) |
1 | 標準出力(ターミナル) |
2 | 標準エラー出力(ターミナル) |
ファイルへのリダイレクションが追加されると
cmd 1> file1 2> file2
ディスクリプタ | 出力先(当初) | 1> file1 適用後 | 2> file2 適用後 |
1 | 標準出力(ターミナル) | file1 | file1 |
2 | 標準エラー出力(ターミナル) | 標準エラー出力(ターミナル) | file2 |
標準出力はfile1へ、標準エラー出力はfile2へ出ることになる。
複製を含む場合、上記で説明したように複製を「出力先を同じにする」と理解するのがポイントになる。
下記のような複製がなされた場合、複製は出力先を同じにするので下記のようになる。
cmd 2>&1
ディスクリプタ | 出力先(当初) | 2>&1適用後 |
1 | 標準出力(ターミナル) | 標準出力(ターミナル) |
2 | 標準エラー出力(ターミナル) | 標準出力(ターミナル) |
下記のように順序を逆にすると結果が変わる。
cmd 2>&1 1> file1
ディスクリプタ | 出力先(当初) | 2>&1適用後 | 1> file1 適用後 |
1 | 標準出力(ターミナル) | 標準出力(ターミナル) | file1 |
2 | 標準エラー出力(ターミナル) | 標準出力(ターミナル) | 標準出力(ターミナル) |
逆パターンだと
cmd 1> file1 2>&1
ディスクリプタ | 出力先(当初) | 1> file1 適用後 | 2>&1適用後 |
1 | 標準出力(ターミナル) | file1 | file1 |
2 | 標準エラー出力(ターミナル) | 標準エラー出力(ターミナル) | file1 |
ディスクリプタの数を増やしてみる。新しいディスクリプタ3にはデフォルトでは何も設定されていない。
cmd 2>&1 3>&2
ディスクリプタ | 出力先(当初) | 2>&1適用後 | 3>&2適用後 |
1 | 標準出力(ターミナル) | 標準出力(ターミナル) | 標準出力(ターミナル) |
2 | 標準エラー出力(ターミナル) | 標準出力(ターミナル) | 標準出力(ターミナル) |
3 | 未設定 | 未設定 | 標準出力(ターミナル) |
逆にしてみると
cmd 3>&2 2>&1
ディスクリプタ | 出力先(当初) | 3>&2適用後 | 2>&1適用後 |
1 | 標準出力(ターミナル) | 標準出力(ターミナル) | 標準出力(ターミナル) |
2 | 標準エラー出力(ターミナル) | 標準エラー出力(ターミナル) | 標準出力(ターミナル) |
3 | 未設定 | 標準エラー出力(ターミナル) | 標準エラー出力(ターミナル) |
パイプを含む場合、標準出力の当初値が変わる。
cmd1 | cmd2
ディスクリプタ | 出力先(当初) |
1 | cmd2の標準入力 |
2 | 標準エラー出力(ターミナル) |
複製と併用するとこんな感じになる。
cmd1 2>&1 | cmd2
ディスクリプタ | 出力先(当初) | 2>&1適用後 |
1 | cmd2の標準入力 | cmd2の標準入力 |
2 | 標準エラー出力(ターミナル) | cmd2の標準入力 |
この例は比較的記法の似た cmd 2>&1 1> file のパターンよりは cmd 1> file 2>&1 のパターンとの類似性を強く感じるものになっている。
よく「左から読め」と言われるのだけれども、パイプだけは右側に書かれているのに、一番左に書いたような挙動をするので非常にわかりにくい感じがする。
複製には他の構文とまとめる記法がある。
ファイル出力とまとめて書くことができる。
cmd 2>& file
これは下記と同じ。
cmd 1> file 2>&1
パイプとまとめて書く記法がある。
cmd1 |& cmd2
これは下記と同じ。
cmd1 2>&1 | cmd2
出だしにあったコマンド群
cmd > file # わかる cmd >& file # なんだっけ? cmd1 | cmd2 # わかる cmd1 |& cmd2 # わかる気もする。書けない。 cmd 2>&1 > /dev/null # えっ?
は下記であることがわかるようになります。
cmd > file # 標準出力をfileに設定 cmd >& file # 標準出力と標準エラー出力をfileに設定 cmd1 | cmd2 # 標準出力をcmd2の標準入力に cmd1 |& cmd2 # 標準出力と標準エラー出力をcmd2の標準入力に cmd 2>&1 > /dev/null # 標準出力を/dev/nullに、標準エラー出力をターミナルに標準出力として出力
2年ぶりに書いた記事がこれかよ、と悲しんでいる。
つらぽよAdvent Calendarにネタを提供したわけでも何でもないんだけど
自宅のデスクトップPCが壊れた。具体的に言うと、HDDがクラッシュした。
もうちょっと正確に言うと、動作真っ最中に子供がぶつかって倒してしまった。
昔のHDDと比べると、あのカツーン、って音がかなりささやかだけど、ありがちなあの音を立てて起動しない現象になった。
PC自体はLenovoのやっすいやつ(H520S)である。キーボードとか、スピーカーとか、こまいパーツコミコミで4万円とかしなかった。Core i5でWindows7が載ってた。
でも、我が家では結構ハイスペックマシンである。
どうしようか悩んだ。なぜか換装用のHDDはあった。SATA-II出だしの頃のやつで遅いけど、容量300Gとかあるので、デスクトップ機としては問題ない。Lenovoにはリカバリディスクを送ってくれるサービスがあるらしい。このHDDとリカバリディスクでハッピーになれそう。。。なわけなかった。7000円払う必要があるし、なによりLenovoの窓口自体が年末年始で休業中だ。
あー、じゃー、Linuxとかでいいじゃん。
Ubuntuのインストールディスクを手持ちのネットブックで焼いて、インストールしたら、無事インストールできた。さすが!余裕じゃないですか。いつもVMPlayerでやってるのと同じじゃん!
と思ってインストール後にPCを再起動したら、
Error1962:No operating system found.
ありー、なんかやり方まずかったかな。。。。
起動ディスクを別途作って起動しようとしても、全然起動しない。
ググってみると
Amazon.com: Customer Reviews: Lenovo H520s Desktop
Linux起動がうまく行かない、というような阿鼻叫喚の嵐。
集めた情報をだいたいかいつまんでまとめてみると
なるほど、secure bootをOFFにする必要があるのね、、、どうりで立ち上がらなかったわけだ。
と思い、BIOSのメニューを探してみたが、
secure bootに関するメニューすらない。。。。
マジか、、、同じ機種名の中でもOFFにできないモデルっぽい。
それでも、secureのまま、dual bootに成功している例はあるらしい。でも、逆に言うとdual bootの例しかない。どうも、Windowsのローダーを踏み台にして立ち上がるのは可能だが、それ以外はダメ、という感じらしい。(多分。たぶんね。)
つまり、WindowsのEFIローダーを書いておいて、起動シーケンスを横から頂戴すればいいのね!?
…いや、それやったら普通にリカバリディスク注文するし!
まー、どうしようかさんざん悩んだ挙句、Ubuntuのインストールディスクが起動していたのを思い出した。外部ブートはできるけど、光学ドライブのISOイメージだけってことっぽいんだよな。。。USBからも立ち上がんなかったし。
で、試しに、UbuntuのインストールディスクのgrubからHDD上のgrub.cfgを読み込んでみると、嘘のようにすんなりインストール後のHDDからシステムが起動した。
そういうわけで、当面、光学ドライブを踏み台にして起動する方向になりそうです。
なんだか変な感じではあります。
現時点ではUbuntuのインストールディスクを使っていますが、めんどいしアホいので、そのうちもっと小さなisoイメージ作ろうかなと思っています。
他にいい方法ないのかな。
正直、secure bootなるものにこういう風にいじめられるとは、なにか数奇な関係があるのかもしれません。
http://partake.in/events/9f226986-2812-441d-98b7-1f5cca9be432 にオンライン参加してきたので、Evalモナドを使った並列評価を行なってみた。
ナイーブな素数探索アルゴリズムです。指定された数以上の一定個数の素数を抽出します。
import Control.Parallel.Strategies -- rseq first n elements in parallel, then next n.. parListWithN :: Int -> [a] -> Eval () parListWithN n l = do parSeqListPar $ take n l case drop n l of [] -> return () _ -> parListWithN n $ drop n l -- rseq in parallel for finite length list parSeqListPar :: [a] -> Eval () parSeqListPar [] = return () parSeqListPar (hd:tl) = do rpar hd parSeqListPar tl rseq hd return () -- filter f l with parallel precalcuration for l filterEval :: (a -> Bool) -> [a] -> [a] filterEval f l = runEval $ do rpar $ runEval $ parListWithN 100 l return $ filter f l -- prime testing isPrime :: Integral b => b -> Bool isPrime n = not $ or $ map ((==0).(n `mod`)) [2..(n-1)] -- find 100 successive primes after 435300 main = print $ take 100 $ filterEvalN isPrime [435300..]
このコードの挙動のポイントはいくつかあります。
filterEval
関数:並列処理のトリガーを引くコードを処理キューに積んで、全体評価を始めます。parListWithN
関数:最初のn個の処理を並列処理にかけ、完了したら次のn個、というようにEval
モナドの挙動を指示する関数です。並列処理がしたければ、rparを使ってタスクを積んでいくだけの簡単なお仕事です。
でも、次のような問題点があります。
Evalモナドはこの辺りのコントロールが難しい感触があります。この後の並列計算ではこの辺りが解消されるか、気になるところです。
使用時はthreadedオプションを付けてコンパイルします。
ghc -threaded FindPrime.hs
実行時は並列コアを指定します。
./FinePrime +RTS -N -RTS
threadscopeの実行結果とか見たかったけど、メモってる時点で時間切れなのでまた手が開けばやります。。。
下記を参考に
モンゴメリ乗算 - Wikipediaを参考に、サンプルとして、モンゴメリ乗算の計算をしてみる。
`11*18(mod 169)`を計算する。
単純に、
11*18 = 198 = 1*169+29
で答えは`29`です。
これをあえてモンゴメリ乗算でやってみる。
モンゴメリ乗算は剰余算を減算回路の繰り返しなしに実現するテクニックです。剰余算、割り算が出てきますが、実際には2のべきしか使わないので、ビットマスクやシフト演算で高速にできるのが特徴。
`R`をひとつ決めると、サブの演算子を下記のようにとって
MR(x) = (x + (x*N' mod R)*N)/R Ninv : N' * N = -1 (mod R) となる数 R2 = R*R mod N
a * b = MR(MR(MR(a*R2)*MR(b*R2)))
とかけます。`R2`求めるときに`mod N` やってるやん!
R:256
に設定すると、下記のように関連する数値が導出されます。
Ninv:103 R2:133
`A=MR(a*R2)` `B=MR(b*R2)`とすると
A=(a R2+(a R2 Ninv mod R)N)/R =(11*133+(11*133*103 mod 256)*169)/256 =112 B=(18*133+(18*133*103 mod 256)*169)/256 =45 AB=112*45=5040 MR(AB)=((AB)+(AB Ninv mod R)N)/N = 157 MR(MR(AB)=(157+((157*103)`mod`256)*169)`div`256 =29
あー、戻ってきた!
モンゴメリ乗算処理のテストケースを作ってみたのだけどそのままブログに書いてみましたの巻。
GCのマークビット判定などに使用される__builtin_ffs
というGCCコンパイラ拡張が気になったので 「__builtin_ffsはどこへ行くのか? - dec9ue's diary」って記事をちょっと前に書きました。
続編です。
さて、何の話だったかというと、__builtin_ffs
とは
Returns one plus the index of the least significant 1-bit of x, or if x is zero, returns zero.
ということで、ビットマップ何かを操作するときに使えるGCC拡張のようだ。
そして、今回は
でも、対象をもうちょっとモダンなアーキテクチャに変えちゃうかも。。。
の予告通り、armv7-aのアーキテクチャに変えてみました。
arm-linux-gnueabihf-gcc -O0 -S -std=gnu99 builtin_ffs_test.c
の結果:
test: @ args = 0, pretend = 0, frame = 8 @ frame_needed = 1, uses_anonymous_args = 0 @ link register save eliminated. push {r7} sub sp, sp, #12 add r7, sp, #0 str r0, [r7, #4] ldr r3, [r7, #4] rbit r3, r3 clz r3, r3 ldr r2, [r7, #4] cmp r2, #0 bne .L2 mov r3, #-1 .L2: add r3, r3, #1 mov r0, r3 add r7, r7, #12 mov sp, r7 pop {r7} bx lr
ARMv7AのARMインストラクションセットにはclz
という先行0ビット判定を行うインストラクションがあります。これ使っちゃえば楽勝じゃん?
本当にありがとうございました。
clz
とrbit
の組み合わせがあれば使う価値があるのですが、これはARMv6T2以降のARM/32bitThumbで使えるはずです。じゃぁ、なんでCortex-M3向けのコードはあんなややこしいコードになってたのか。16bitThumbを使うことを優先したのかな?