現在PCのHDD接続インターフェースとしてはSerialATAが主流ですが、SerialATAには「IDE互換モード」と「AHCIモード」と呼ばれる2つの動作モードがあります。
IDE互換モードはSerialATA1.0で用意された規格で、まるでパラレルATAのように振る舞うことで従来のシステムとの互換性を高めています。
それに対してSerialATA2.0で用意されたAHCI(Advanced Host Controller Interface)モードでは、パラレルATAとの互換性を排除して、より高度な制御が可能となっています。
SerialATAのドライブ本来の性能を発揮するには、IDE互換モードではなくAHCIモードで使用する必要があります。しかし、AHCIモードを使用するにはOSやドライバの対応が必要で、XPで使うには面倒な手順でOSをインストールする必要がありました。
私が現在使っているPCは、OSはVista、チップセットはICH9R、HDDはもちろんSerialATAの最近の物で、AHCIはすぐにでも使える状態ですが、今まではIDE互換モードになっていました。
せっかく使えるのだから試しに使ってみようとBIOSでAHCIに切り替えてみると……はい、起動しなくなりましたorz
一瞬顔が青くなりましたが、Vistaのインストール時にIDE互換モードにしていると、AHCIドライバを読み込まないように自動的に設定されるのが原因でした。
ブート ドライブの SATA モードを変更した後で Windows Vista ベースのコンピュータを起動すると、エラー メッセージ "STOP 0x0000007B INACCESSABLE_BOOT_DEVICE" が表示される(Microsoftサポートオンライン)
レジストリを書き換えてから改めてAHCIモードに変えてみると、無事に起動しました。
今回は「BIOSに設定があったからなんとなく試してみた」だけで、事前に何も情報を集めていなかったので、とりあえずAHCIモードで何か問題がないか2ち○んねるで情報収集しようとギ○ナビを起動したら……起動時のプログレスバーの進み方がめちゃくちゃ速い!!ギコナビ以外のアプリケーションも起動が速くなりました。
「体感できなかった」という報告もよく見るので全く期待していなかったのですが、これは嬉しい誤算。私の使っているHDDは、シーケンシャルアクセスは物凄く速いがランダムアクセスが遅い、直線番長なんて言われたりするドライブなので、特にNCQが効果的なのかもしれません。
先日リリースされたMovable Type 4.2に更新しようとしたら、ここで使っているs33.xrea.comサーバは、PerlやMySQLのバージョンが古いせいで、上手くインストールできませんでした。
システム更新時のトラブルを避けるために、別のサーバで導入テストまでやったのに、そのテストしたサーバとこのサーバでは、インストールされているソフトのバージョンが違うという罠がありましたorz
元に戻そうとしたら、MySQLのバックアップファイルを誤って紛失してしまったので、Movable Typeに組み込まれているバックアップ復元機能を利用しましたが、なぜか50件の記事しか復元されませんでした。
とりあえず応急処置で、復元されなかった記事は以前に出力されたhtmlを見ながら日付を調節して1つずつ投稿しなおしておきましたが、何か不具合があるかもしれません。また、コメントは戻していないので、7月以降のコメントは消えているかもしれません。
4.0で出来たばかりのバックアップ機能ではなく、以前からあるエクスポート/インポート機能でバックアップを取ればよかったorz
CGIプログラムは通常はWebサーバから呼び出されて実行されるので、高機能なデバッガが利用できないため、とてもデバッグがしにくいです。
しかし、Pythonの標準ライブラリには、CGIのデバッグに役立つ2つのモジュールが用意されていて、デバッグがかなり楽にできます。
まず最初に紹介するのが、cgitbです。このモジュールを使うと、CGIプログラムで捕捉されない例外が発生したときに、トレースバック情報をHTMLで出力してくれます。使い方は非常に簡単で、
import cgitb; cgitb.enable()
と最初の方に書いておくだけです。後は例外が発生したときに、勝手になんとかしてくれます。
実際にcgitbの出力がどんな感じになるのか、サンプルを用意しました。
http://niisaka.s33.xrea.com/cgi-bin/test/python-cgi.cgi
このCGIは1行コメントを投稿して、10行まで保存しますが、コメント欄が空欄のまま投稿すると例外が発生します。(フォームにinput要素があっても値が空の場合はFieldStorageには登録されないため)
例外が発生すると、例外の詳細と前後のソースコードが表示されます。この場合は、form['comment']から暗黙的に呼び出された FieldStorage.__getitem__() でKeyError例外が発生しています。
ユーザにソースコードを見せたくない場合は、cgitb.enable(display=0, logdir="/tmp") のようにすると、/tmpディレクトリにファイルとして出力され、ブラウザ上には出力されなくなります。また、context引数で出力されるソースコードの行数を指定できます。(標準ではcontext=5)
もう1つとても便利なのが、CGIHTTPServerモジュールです。これはCGI実行機能付きの簡易的なWebサーバとして動くモジュールで、Apache等をインストールしなくてもローカルでCGIのテストができます。
使用方法は、コマンドプロンプトから python -m CGIHTTPServer とするだけです。 このときのカレントディレクトリがWebサーバのドキュメントルートとなります。標準ではポート8000に設定されているので、ブラウザから localhost:8000 を開くことでアクセスできます。
CGIスクリプトは、cgi-binという名前のディレクトリより下に置く必要があり、拡張子は.pyでなければなりません。また、cgi-bin以下のディレクトリでは.py以外のファイルにはアクセスできなくなっています。画像などを表示する場合は、cgi-bin以外のディレクトリに配置しなければなりません。
このモジュールには1つ困った問題があり、CGIスクリプトが実行されるときにカレントディレクトリがドキュメントルートのままになっています。通常はCGIスクリプトのあるディレクトリがカレントディレクトリになるので、実際にApache等で動かした場合と動作が異なってしまいます。CGIHTTPServerを修正してしまうか、CGIスクリプト側でカレントディレクトリを設定しなおすといいかもしれません。
このような素晴らしい機能が標準で付いてくるのもPythonの魅力ですね。
CGIと言えばいまだにPerlが主流ですが、PythonはCGI用のライブラリも標準で用意されており、特別なパッケージを別途インストールする必要無しに、簡単にCGIを作成することができます。
CGI作成に使うのは、その名の通りcgiモジュールです。
cgiモジュールの使い方は非常に簡単で、import cgiをした後に form = cgi.FieldStorage() とするだけで、フォームの内容を取得できます。メソッドがPOSTかGETかだとか、そんなことは一切気にする必要はありません。この一行だけで、後はformを介してフォームの値にアクセスできます。
例えば掲示板の名前入力欄にnameという名前を付けていれば、form['name'].valueでname欄に入力された値が取得できます。'name'が存在しない場合はKeyErrorの例外が投げられますが、getvalueメソッドを使って name = form.getvalue('name', '名無しさん') のようにすると例外の代わりにデフォルト値を返してくれます。
'name'に該当する項目が1つだけならば、form['name'].valueは文字列を返しますが、チェックボックス等は同じ名前で複数の項目を使用することがあります。その場合に同名の項目が2つ以上選択されていると、form['name'].valueはリストを返します。同名の項目数に関わらず、常に単一の文字列を返して欲しい場合はgetfirstメソッドを、逆に常にリストで返して欲しい場合はgetlistメソッドを使います。
フォームからファイルをアップロードした場合は、form['name']はファイルオブジェクトになります。アップロードされたファイルの読み取りは普通のファイルと同じように行います。オリジナルのファイル名はform['name'].filenameで、MIMEタイプはform['name'].typeで取得できます。
投稿サイズに制限を設けたい場合は、import cgiの後でcgi.FieldStorage()を呼ぶ前に、cgi.maxlen = 102400 のようにバイト単位で指定します。フォームの内容がこのサイズを超えていると、cgi.FieldStorage()がValueErrorの例外を投げます。(ただし他のエラーでもValueErrorを投げるので、厳密に判定したければエラーメッセージを調べる必要がある)
掲示板CGI等でよく使う、<>&"のエスケープもcgiモジュールに用意されていて、s = cgi.escape(s) でエスケープされた文字列が得られます。デフォルトでは"をエスケープしてくれないので、それもエスケープして欲しい場合は、 s = cgi.escape(s, True) のようにします。
Pythonの強力なライブラリのおかげで、単純な掲示板くらいならあっという間に作ることができます。CGIを配布する場合も、余計なライブラリは必要ないのでライセンス等を気にしなくていいのは気楽です。
floatからintへ変換すると、小数点以下が丸められます。このとき小数点以下の数字をどう扱うかについてはいくつか考え方がありますが、C++の場合は単純に切り捨てられます。
切り捨てというのは、言い方を変えると「0に向かって丸める」とも言います。10進表記で小数点以下が無かったことになります。一般的に小数点以下切り捨てと言ったら、この方法を指します。
この変換をグラフにしてみると、次のようになります。
この図からも分かるように、正と負の値で丸められる向きが逆になり、値が0となる範囲だけが他よりも広くなっています。
この性質は、座標のような値を扱うときには注意しないといけません。例えばマウスカーソルの座標をパース変換してゲーム画面内の整数グリッド位置(チェス盤のマス目等)を計算する場合に、0の座標値を持つグリッドの幅が2倍になり、正と負の座標値で1マスずれることになります。
一方、70~80年代に流行していたBASIC(主にMicrosoft製)では、浮動小数点数から整数への変換は床関数が使われていました。
床関数は、その数以下で最大の整数に変換されます。負の無限大に向かって丸めるとも言います。この方法では、正の値は切り捨てられ、負の値は切り上げられます。
床関数のグラフは次のようになります。
先ほどの切り捨てとは違い、0の周囲でも同じ規則でグラフが変化しています。
座標のような値の場合は、切り捨てよりも床関数の方が合っています。床関数ではfloatの値に+1したら変換後のintの値も必ず+1されますが、切り捨てではfloatの値が0を跨ぐときだけintの値が変化しません。
逆にオフセットのような値は、床関数よりも切り捨ての方が合っています。

