輝々凛々

ガンバるってことは、素晴らしい事だ。

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

適当なことやってんじゃねぇ!

最近、テスト駆動開発だとか、アジャイル開発だとか、継続的インテグレーションだとか、開発スタイルにやたらとこだわる人がいるけど、そんなもんを実践する前にやることあるだろう。

ソースコードにはコメントをつけろ。それがなきゃ、後から見てわかんねーだろうが。そのコードのテストコードが合ってるかどうかわかんねーだろうが。後から機能を追加もできねーだろうが。お前に聞きゃわかるって? お前が生きてんのはせいぜい100年だろうが。お前のコードは、お前に聞かなくてもわかるように書いてろ!

プログラムには仕様をつけろ。それがなきゃ、意義がわかんねーだろうが。仕様を残さないプログラマーは、職業プログラマー失格だぜ。何でそう決めたんだ? どんな要求があったんだ? 一言一句書いて残せ! お前のプログラムと同じようなもんが、何度も何度も繰り返し作られんのは、お前のプログラムの仕様が残ってないせいだ。きっちりみっちり仕様を残せ!

その上で、きっちりテストしろ。きっちりアジャイルしろ。きっちりCIしろ。

適当なことやってんじゃねぇ!

スポンサーサイト

平成20年度秋期:システムに必要なMIPS

あるオンラインシステムでは、1時間当たり360,000件のトランザクションを処理することが求められている。このシステムでは、トランザクションの20%が200万ステップ、80%が50万ステップの命令を実行する。CPU使用率が80%のときに、必要となるCPUの処理能力は最低何MIPSか。

ア 80

イ 100

ウ 400

エ 500

この問題、よろしくない。「トランザクションの20%」って何よ?「CPU使用率が80%のときに、必要となるCPUの処理能力は最低何MIPSか」って何よ。変じゃん。

1時間当たりのトランザクションの20%である

「トランザクションの20%」は、まず、この360,000トランザクションの20%が200万ステップ、80%が50万ステップということらしい。決して、1トランザクションを処理するのに5段階あって、1段階目、すなわち20%が、200万ステップかかって、残りは50万ステップかかるってことではない。

そんなわけで、1時間360,000トランザクションのステップ数[steps/hour]は、下記のようになる。

360,000 * 0.2 * 2,000,000 + 360,000 * 0.8 * 500,000 [steps/hour]

CPU使用率を80%にするために必要な処理能力MIPSを求める。

さて、次「CPU使用率が80%のときに、必要となるCPUの処理能力は最低何MIPSか」は、時制が変だ。すでに稼働しているシステムのCPU使用率をみて80%になっていることを確認した上で、「こんなシステムを作るには、何MIPS必要?」って何聞いてるのよ。もう、そこにあるじゃん。ま、そんなこたぁ、もういい。

先ほどの数式を計算すれば、1時間当たりのステップ数を求められる。

MIPSは、Mega-Instruction Per Second、つまり1秒当たりに命令(ステップ)を何百万命令処理できるかを表す性能指標値である。

つまり、「1時間当たりのステップ数」を「1秒当たりのステップ数」に変換する必要がある。

これは、つまり単に3600で割ればいい(1時間=60分=3600秒なので)。

結果、下記のようになる。

360,000 * 0.2 * 2,000,000 + 360,000 * 0.8 * 500,000 [steps/hour]
=(360,000 * 0.2 * 2,000,000 + 360,000 * 0.8 * 500,000) / 3,600 [steps/second]
=100 * 0.2 * 2,000,000 + 100 * 0.8 * 500,000 [steps/second]
=20 * 2,000,000 + 80 * 500,000 [steps/second]
=40,000,000 + 40,000,000 [steps/second]
=80,000,000 [steps/second]

さて、ここで、CPUの使用率が100%というのは、どういう状態だろうか。

CPUを人間に置き換えてもいいが、100%というのは能力の限界で処理している状態を指す。50%であれば能力半分。0%であれば、仕事がないか、仕事を放棄している状態だ。

つまり、80%の使用率というのは、自分の能力の80%で処理できる程度の仕事量を処理しているということになる。

今回の問題では、80%で処理できるような、CPUの処理能力を求めることになっている。

人間でいえば、100kgの重りを80%の力で持ち上げれるようになるには、筋肉をどれだけ鍛えればいいでしょう? みたいな問題になっている。

今回の仕事量は、先ほど求めた秒間ステップ数(下記)で決まっている。

80,000,000 [steps/second]

これを、80%で処理できる能力を X [MIPS] とすると、次式が成り立つ。

0.8X = 80,000,000 [MIPS]

つまり、求めるべき CPU性能 MIPS は、両辺を0.8で割ることで下記のように求まる。

X = 100,000,000 [MIPS]

さて、お気づきだろう。単位が間違っていたことを。

ここで、求めた X は、MIPSではなく、IPSになっている。

つまり、回答としては、さらに百万で割って、100としなければならない。

ただ、こういった間違いは普通に起こりえるもので、ただ気づけばいいのだ。

最後に「1億MIPSって変だぞ。速すぎるぞ」って気づければいいのだ。

人間は、コンピュータと違って、間違えていても気づける。間違えてもやり直せる。

ちなみに、1億MIPSというと、100TIPS(100Tera-Instraction Per Second) だけど、これはスパコンレベル。地球シミュレータ(第二世代)クラス。現在は、理化学研究所の「京」が世界一位で、8162TFLOPSをマークしている。

NSString stringWithFormat/NSLog

NSString stringWithFormatNSLog()には、文字列書式と引数を指定することで任意の文字列を作り出したり、ログ出力することができる。

つまり、これは、printfと同じといっていい。(事実、IEEE printf specification の拡張だと明記されている。)

おさえるべき点は、printfと同じ書式、%dや、%u、%fが使えるという点と、Objective-Cのオブジェクトを表示するためには「%@」を使用するという点だけである。

  • NSLog(@"%d", intValue);
  • NSLog(@"%@", nsStringValue);
  • [NSString stringWithFormat:@"%d - %@", intValue, nsStringValue];

See also

NSInteger/int/NSNumber/id/CoreData

NSIntegerは、単に整数を表すPOD型ですが、型のサイズを規定しません。つまりビルドターゲットによって、32bit/64bitへ変化します。

intは単に32bit整数のPOD型です。longは64bit整数のPOD型です。

NSNumberは、数を表すクラス型です。NSArrayやNSMutableArrayには、POD型の整数や小数をそのまま格納することはできません。そこで、POD型をラッピングしたNSNumberクラスのインスタンスを作成し、そのインスタンスをNSArrayに格納します。また、後述するid型への代入のために使用することもあります。

id型は、(void*) 相当の型です。あらゆるクラスのインスタンスを格納するために使用します。

CoreDataにデータを格納する場合、[coreDataObject setValue:value forKey:@"myKeyName"]とします。ここで、valueはid型ですので、intなどのPOD型は、いったんNSNumberクラスのインスタンスにしてからデータを格納します。

See also

権限!

Visual Studio 2005は、2005年末に発売され、Visual Studio 2008は、2007年末に発売されました。いまは、その後継バージョンであるVisual Studio 2010も発売されています。

で、それぞれでC#言語のバージョンは、2.0、3.0、4.0とバージョンアップして、少しずつ構文に改良が加えられています。

で、そんな中でだ!

いまさら「Visual Studio 2008対応実験」はないわなぁ。

いまさら「互換性を気にして書け」だ?

それに社内では、昨年に「Visual Studio 2008」へ以降が始まってるのに、ほんと、いまさらだよなぁ。

はぁ。

別に実行環境を変えているわけでもあるめぇし。

変わっていくべきだ

というか、少しずつ変えていく事ができないやつの言う事は「1から書き直したい」→「新しいの作ります。こんなに素晴らしいですよ」→「こういう問題がでました。」→「1から書き直したい」→無限∞

ちっくしょう、もっと権限!

C言語、数字かどうか判定する!

C言語で、あるcharが数字かどうかを判定するには、普通、標準ライブラリのisdigitを使うか、次のようなコードを書くと思います。

if ('0' <= ch && ch <= '9') {/* 数字 */}

ナニを今さら、って感じですが、自分は今日、次のコードに衝撃を受けました。

if ((unsigned)ch - '0' < 10u) {/* 数字 */}

ぅ・・・・、すごい。すごいわかりにくいけど、すごい。比較が2度は必要だと思っていましたし、それが最大限の最適化だと思っていましたけど、こっちの方が・・・・・、早いのかな?

このコードの解説を一応、しておきますと。もし、chが'0'であるなら、引き算の結果は、0となり10よりも小さいので、成立。そうでなくて、'9'なら引き算の結果は'9'となって、やはり成立。

'9'よりも大きい場合は引き算の結果が10以上となるので、不成立。'0'よりも小さい場合、unsignedにキャストしているので、ch - '0'の結果はunsigned intの大きな値になるので、やはり、不成立。

ところで、(unsigned)ch - '0'の結果がsignedってこともあるんじゃないか! と思ったけど、それはないか。

逆ポーランド記法

普通、学校では「1+2」という感じで数式を書く。

でもそれをコンピュータに解釈させる際には、ちょっと違った形で記述する。

それが逆ポーランド記法だ。(ポーランド記法もある)

逆ポーランド記法

ルールはいたってシンプル、演算は後に書きやがれだ。

たとえば、先ほどの「1+2」なら、演算である「+」を後ろにやり、「12+」とする。

これをコンピュータが解釈するときは、頭から「1」を取り出し、「2」を取り出し、「+」が来たら、その前2つの数字を「+」する。

また複雑な系では、「3*(1+2)」は「312+*」となる。

これ頭から「3」を取り出し、「1」を取り出し、「2」を取り出し、「+」が来て、その前2つの数字「1」と「2」を「+」して、「*」が来たらその前二つの数字、つまり「1+2」の結果である「3」と、その手前にあった数字「3」を「*」する。

基本的に括弧を使わずに数式を頭から解釈していけるのが逆ポーランド記法の素晴らしいところだ。

ポインタ

メモリのアドレスを示す特別な型。
メモリにはデータがドバって入ってて、そのデータの任意の位置(アドレス)を記憶するために使う。

たとえば文字列の途中を覚えておくとか、配列の途中とか最後とかを覚えておく。

あとはリンクリストつって、次のデータとか前のデータがどこにあるかを覚えたりする。

ちなみにnull(ヌル)は、ポインタがどこのアドレスも記憶していないことを示すために使う。

ちくちく

最近、ちょくちょくテンプレートをいじって、HTML5対応していってます。

もう、今日の修正でベースは出来上がったので、後は肉付けしていくだけです。

あ、残念なことにコメント欄等が復活するまで時間がかかります。あしらかず。

真のプログラマ

プログラミングは、何かを作る事だけど、プログラマにとって、プログラミングは仕事の一部分にすぎない。

プログラミング以外にも、ドキュメント書いたり、プレゼンしたり、保守したり、テストしたり、書き直して、より良い物にしたり、あるいは名前を考えたり、お客さんに合うプログラムがお客さんを幸せにするのか考えてみたり、あるいはお客さんには合わないから、別の解決策を見つけてあげたり・・・

真のプログラマは、決してプログラミングをするだけじゃない。

抽象的すぎるプログラムは悪だ

プログラムは、目的を達成するための道具で、具体的なものだ。

そこにピカソのような抽象的なプログラムは必要ない。

いや、ピカソというと語弊があるな。

抽象的を履き違えた「曖昧な」プログラムは必要ない、だ。

Do()

たとえば、よく見かけるのだけど、「Do()」という関数。抽象的を通り越して、中身を想像できないという意味で、かなり曖昧だ。まったく理解できない。中身を想像させたくない理由でもあるのか?

汎用的にする目的で抽象化するのであれば「Build()」とか「Compile()」とか「Read()」とか「Write()」とか「Fetch()」とかまでの抽象化で留めておくべきだ。

デバッグしにくい

想像できないほどの抽象化は、中身を想像できないだけでなく、デバッグもしにくい。だいたい何をやっているかわからないし、バグがあるであろう関数を見つけにくくなる。

ファイル読み込みに何らかのバグがあったとする(32ビット長のファイルしか読めないとか、日本語パスを読めないとか)。このとき、「Read()」のような関数があれば、すぐに検索して目的の関数を見つけられるし、関数名から関数の仕様を想像する事もできる。だけど「Do()」じゃわからない。

もちろん「fread()」や「ReadFile()」とかをキーに検索して関数を見つけられるかもしれないので、この例は不適切であるが。

あと「コメントがあればいい」というかもしれないが、コメントはなるべく書かない方がいい。重要なのはコメントを書く事ではなくて、わかりやすいコードを書く事。その上で、わかりにくい所やトリッキーな所、全体的な構造についてはコメントやドキュメンテーションすればいい。プログラマの時間は限りなく限られているのだ。残業しているうちはダメなんだ。

結論

ま、そんなわけで、結論。

美しい抽象化は何か、それを問え。

非論理的なプログラミング

ここんところ、ずっとプログラミングの発想がどこから来るのか考えてたんですが、何となくの答え(というか水準?)に到達しました。

タイトルにも書いていますが、ようわ、論理的ではないんですよね。全然。

というか、論理的思考の根源も非論理から生まれてる感じなんですよね。

プログラミングするときは、最終的には論理的な思考(プログラム)に落とし込んではいるんですけど、でもその論理にさえ論理とは違う根源があって、論理的思考を思いついている何かがあると感じていました。で、その何かが何なのかが問題でした。

で、ひとつの答えに到達。

なんとなくイメージだけ伝えると、「将棋」。ま、将棋でもチェスでもいいんですけど、将棋に強い人って、何手も先をよみますよね。これが、不思議だったんですね。コンピュータだって、そんな何手も先を読むのは得意じゃないのに、あれほど素早く考えるのが不思議でした。コンピュータに例えれば、ものすごいクロックあるいは並列性のあるCPUとか、超広大なメモリ空間(とアクセス速度)が必要なのに、なのに棋士はなぜ読めるのかが凄い不思議でした。

つまり、棋士って違う考えをしてるんだという結論に達しました。つまり論理的に「この手を打つと、次の盤面はこうだから、あの手を打ってくるから・・・」とか考えてないんですよね。たぶん。

で、同じ事を考える人はいるもので、理化学研究所にこんなページがありました。「将棋を用いた脳研究:脳研究協力棋士 募集

うん。コンピュータはまだまだ進化するなぁ。自分も進化せねば。

Mercurialが簡単だ。

バージョン管理システム「Mercurial」が簡単でいい。

プロジェクトのフォルダで「hg init」すれば使い始められる。

で、「hg add」でファイルを追加登録、「hg commit」でバージョン管理下にできる。

「hg log」でログを見れる。

「hg stat」でフォルダの状態を確認できる。追加し忘れているファイルがないかを確認できるわけだ。

ま、そんな感じ。

ライブラリの静と動

一般にライブラリには2種類ある。

実行できるアプリケーションに、「コンパイル時に」くっつける静的ライブラリと、実行できるアプリケーションの、「実行時に」くっつける動的ライブラリだ。ふたつはそれぞれ英語では「static link library」とか「dynamic link library」と言う。

さて。linuxやmac、windowsの世界では「動的ライブラリ」には2種類の動的性が存在している。ひとつが、「暗黙的リンク」で、もうひとつが「明示的リンク」だ。ようわ、くっつけられるか、自分でくっつけるかの違いだ。

暗黙的リンクの場合、コンパイル時に読み込むライブラリの名前などがわかっていて、プログラムを書くのは非常に楽だけど、「動的ライブラリ」のくせに、全然動的ではない。(ファイルという単位で分かれただけだ。

一方、明示的リンクの場合、プログラマには少し負担があるが、本当に「動的」にリンクできる。この「動的」の意味するところは、タイミングもそうだし、なくても動き出せることも当然だし、もっと言えば、同じ種類のライブラリで、複数の違う実装を実行時に判断して呼び分けることもできる。

一般に「プラグイン」とか「アドオン」、「アドイン」と呼ばれるものは、ほとんどが「動的ライブラリ」で「明示的リンク」によって実現されている。(ただし、スクリプト言語を用いるという方法もあるので、すべてが「動的ライブラリ」ではない。が、明示的なリンクには違いない。)

ちなみにWindowsでは、windows.hを読み込んで「LoadLibrary」によって、DLLを読み込み、「GetProcAddress」で関数へのポインタを取り出す。アドオンをビルドするときは、DLLでビルドする。モジュール定義ファイルを指定する事を忘れずに。

linux/macのgcc環境だと、dlfcn.hを読み込んで「dlopen」によって、DLLを読み込み、「dlsym」で関数へのポインタを取り出す。アドオンをビルドするときは、「gcc -shared myfunc.c -o mydll.lib」のようにする。

にしても、windows/linux/macに同じ仕組みが合って、本当に良かったと思う。しかも同じ手順だし。

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。