2012年12月23日日曜日

Software Development for Infrastructureの紹介

静的次元解析

Bjarne Stroustrupさんが、C++11仕様の決定を記念して書いたC++のコーディング・スタイルに関する記事 Software Development for Infrastructureで紹介されていた静的次元解析のコードを試しに実装してみた。

C++11スタイルでコードを書くと今までのスタイルとまったく違うのコードになるのに驚いた。しかし、 C++のテンプレート静的に(実行時のオーバーヘッドなしで)、ここまでできるとは素晴らしい。

上記記事、ここに挙げた静的次元解析以外にもC++で実装するときにスタイルについて、助言が書かれているので お勧めです。

 1:  #include <iostream>
 2:  
 3:  // 単位を表現するテンプレート・クラス。
 4:  template <int M, int K, int S>
 5:  struct Unit {
 6:    enum {m = M, kg = K, sec =S};
 7:  };
 8:  // 単位付き値を表現するテンプレート・クラス。
 9:  template <typename Unit>
10:  struct Value {
11:    double val;
12:    explicit constexpr Value(double b) : val(b) {}
13:  };
14:  
15:  using Speed = Unit<1,0,-1>;
16:  using Length = Unit<1,0,0>;
17:  using Time = Unit<0,0,1>;
18:  
19:  // -------------------------ユーザ定義リテラルの定義-----------------------------------------
20:  /*
21:    C++には組み込みのリテラルがありました。C++11から、ユーザがリテラルを定義できるようになりました。
22:  
23:    true; boolリテラル。
24:    "hello, world!"; 文字列リテラル。
25:    1l; longリテラル。
26:    1.0d; doubleリテラル。
27:  
28:    型安全なコードを書くために以下のようなリテラルを定義します。リテラルには(_)アンダースコアが
29:    含まれていることに注意。(_)を付けないリテラルは標準で予約さているので警告。
30:  
31:    30.0_km; 30 kmを表現するリテラル。
32:    2.0_hr; 2時間を表現するリテラル。
33:  */
34:  constexpr Value<Length>
35:  operator"" _km(long double d) {
36:    return Value<Length>(1000*d);// Lengthの基本単位がメートルなので、1000倍して、kmからmに変換。
37:  }
38:  
39:  constexpr Value<Time>
40:  operator"" _hr(long double d) {
41:    return Value<Time>(60*60*d);// Timeの基本単位が秒(sec)なので、時から秒に変換。
42:  }
43:  
44:  // ------------------------ 単位付き値に対する演算を定義。-------------------------------------
45:  template <typename Unit>
46:  Value<Unit> operator+(Value<Unit>&& lhs, Value<Unit>&& rhs) {
47:    return Value<Unit>(lhs.val + rhs.val);
48:  }
49:  
50:  template <typename Unit1, typename Unit2>
51:  Value<Unit<Unit1::m - Unit2::m, Unit1::kg - Unit2::kg, Unit1::sec - Unit2::sec>>
52:  operator/(Value<Unit1>& n, Value<Unit2>& d) {
53:    return Value<Unit<Unit1::m - Unit2::m, Unit1::kg - Unit2::kg, Unit1::sec - Unit2::sec>>(n.val/d.val);
54:  }
55:  
56:  // Valueが正しい単位を持っているか確認するための関数テンプレートisSpeed。
57:  template <typename T>
58:  constexpr bool isSpeed(){ return false; }
59:  
60:  template <>
61:  constexpr bool isSpeed<Value<Speed>>(){ return true; }
62:  
63:  // Valueを表示するために<<演算子をオーバーロード。
64:  template <typename Unit>
65:  std::ostream& operator<<(std::ostream& os, Value<Unit>& v){
66:    return (os << v.val << std::endl);
67:  }
68:  
69:  int main() {
70:    // 家からオフィスまでの通勤時の平均時速を求めたい。
71:    auto homeToOffice(30.0_km);// 家からオフィスまでの距離。30km
72:    auto time(1.0_hr);// 所要時間 1.0時間
73:    auto average_speed = homeToOffice/time;// 時速を計算。
74:    // 計算したaverage_speedの単位が正しいかチェック。
75:    static_assert(isSpeed<decltype(average_speed)>(),"Check failed!!");
76:    std::cout << average_speed << std::endl;
77:  
78:    // 距離と時間は足せない。コンパイル・エラー。
79:    // auto bug_1 = homeToOffice + time;
80:  
81:    // 時速を計算したいのに割り算が逆。static_assert部分でコンパイル・エラー。
82:    // auto bug_2 = time/homeToOffice;
83:    // static_assert(isSpeed<decltype(bug_2)>(),"Check failed!!");
84:  
85:    return 0;
86:  }

2012年11月24日土曜日

C vs Python vs Ruby vs Haskell(無意味な処理deベンチマーク)のC++版

memo.org

最近、nshinchan01さんのブログで、4つの言語を利用したコードの実行速度(しんちゃんの日記:C vs Python vs Ruby vs Haskell(無意味な処理deベンチマーク))の比較が行われていた。

TL上で、Haskellの実行速度がありえないほど早いのを見て興味を持ったので、C++11の 勉強がてら、C++版でお題の問題を書いて実行時間を計測してみた。

詳しくは、nshinchan01さんのブログを見て欲しいが、お題は、4000x4000整数の2次元配列arrayが あり、arrayの要素array[i][j]は、整数4000*i+j+1。arrayの各要素array[i](整数の配列)を反転して、 arrayの最後尾の要素の最後尾の要素を表示する処理の実行時間を測定する。

C++11で導入されたRangeベースのforループ、autoキーワードを用いた型推論を利用してお題を 解いてみると以下のようなコードになった。これを、clang++ version 3.0で、O3オプションを指定して コンパイル。

#include <algorithm>
#include <iostream>
#include <vector>

static const unsigned int N = 4000;
int main(int argc, char *argv[]) {
  std::vector<std::vector<int> > array(N,std::vector<int>(N));
  int i = 0;
  for (auto& a: array) {
    std::iota(a.begin(),a.end(),N*i+1);
    ++i;
  }
  for (auto& a: array) {
    std::reverse(a.begin(), a.end());
  }
  std::cout << array.back().back() << std::endl;
  return 0;
}

しんちゃんの日記:Haskellで実行時間計測用のコマンドを作る で作った、difftimeコマンドを利用して実行時間を測定。10回の平均を取ると、0.2824988secになった。

nshinchan01さんのブログに書いてある、Cのコードを同じ環境で測定した結果は、0.2928458secとなり、C++との差が3%程とC++でCのコードと遜色のないコードが書けることがわかる。(※ただ、nshinchan01さんのところではCのコードの実行時間が0.083と、手元の環境より3倍ほど早いのが気になる。コンパイラの違いかな?)

で、最初にC++で実装するきっかけとなったHaskellのコードだが、C/C++と同じ環境で測定すると0.0282011sec となり、C/C++の約10倍という圧倒的な性能となる(^^;) Haskell恐るべし。

ただ、Haskellって遅延評価(データが欲しいときに計算を実行する)なので、Haskellとその他の言語での実装を比較するときは、問題の設定方法に気をつけないとまともな比較にならない。

今回のお題では、4000x4000の配列を生成して(処理1)、その配列を反転して(処理2)、最後尾の要素の最後尾の要素を取得(処理3)する。3処理の実行時間を計測するというもの。C/C++のような命令型であれば、処理を順に書いていくだけで単純だけど、Haskellだと遅延評価のおかげで余分な処理を実行されないので、3つの処理が実際に実行されているかはわからないような気がする。(多分されていない)

ともかく、Haskell適切に書くと読み易く効率の良いコードが書けるのが素晴しい。C++でも、遅延評価の仕組みを取り入れてHaskellにせまる実行速度のコード書けるのかな?(そもそも最初は、Templateメタプログラミングでコンパイル時に問題を解いて答えを表示するだけのコードを実装しようとしたけど、コンパイルが終了しなかったorz)

2012-11-24 Sat 13:55

2012年9月12日水曜日

emacsからBloggerに記事を投稿する方法。

outfile

普段、emacsの中で生活しているのでBloggerへの記事の投稿もemacsから行いたい(それほど、 投稿は多くないのだけど。。。)

emacsからBloggerへの投稿には、Ideas and Bulbs - Andrei Matveyeuで紹介されているemacsのorg-modeと pythonスクリプトbloggerpost.pyを利用した方法を試す。org-modeはかなり有名なパッケージなので、説明は省略。

bloggerpost.pyは、Beautiful Sourp library(python HTML/XML parser)、googlecl(Googleサービスを 利用するためのコマンド・ライン・ツール)に依存しているため、これらのライブラリをインストール する。

Ubuntuならばこれらのツールのパッケージが用意されているため、以下のコマンドでインストール。

sudo apt-get install python-beautifulsoup googlecl

続いて、bloggerpost.pyをダウンロードし適当な場所(例えば、~/bin)に配置する。

スクリプトbloggerpost.pyを開き、以下のオプションを自身の環境に合せて編集する。

username="my_google_user_name" #Googleのユーザ名。
orgelc="path_to_org_el" # ファイルorg.elへのパス。例えば、/usr/share/emacs/23.3/lisp/org/org.elc

emacsをバッチ・モードで実行し投稿するためのHTMLを生成している以下のラインで、org-mode 7.9.1ではHTMLの 生成に失敗するため以下のように修正する。

# 修正前
os.system("""emacs --batch --load="""+orgelc+""" --visit """+outfile+""" --funcall org-export-as-html-batch """)
# 修正後。 path_to_org_mode_dir_lispはorg-modeパッケージのlispディレクトリ。例えば、 ~/.emacs.d/elisp/org-7.9.1/lisp/
os.system("""emacs --batch --directory=path_to_org_mode_dir_lisp --load="""+orgelc+""" --visit """+outfile+""" --funcall org-export-as-html-batch""")

スクリプトbloggerpost.pyでは、Asciiでエンコードできない文字列を含む記事を投稿しようとすると、googleclの呼び出しで エンコード・エラーになる。このエラーを回避するためにgoogleclの呼び出しと呼び出し用のコマンドcommand生成処理を修正する。

if tags<>"":
    # 修正前
    command=unicode(googlecl+u' blogger post --draft -u '+username+' --blog '+blogname+' --tags "'+tags+u'" --title "'+title+u'" '+postHTML)
    # 修正後
    command=unicode(googlecl+' blogger post --config /home/taka/.googlecl/config --draft -u '+username+' --tags "'+tags+'" --title "'+title+'" '+postHTML)
else:
    # 修正前
    command=unicode(googlecl+u' blogger post --draft -u '+username+' --blog '+blogname+' --title "'+title+u'" '+postHTML)
    # 修正後
    command=unicode(googlecl+' blogger post --config /home/taka/.googlecl/config --draft -u '+username+' --title "'+title+'" '+postHTML)

# 関係のないコードを省略。

# 修正前
os.system(command)
# 修正後
os.system(command.encode('utf-8'))

上記設定で、org-modeからBloggerに記事を投稿できるようになる。org-modeのファイルを開き、投稿したいツリーを リージョンとして選択する。ツリーが閉じられている場合は、ツリーのタイトルをリージョンとして選択。ツリーが 開いている場合は、ツリー全体を選択。選択している状態で、M-x shell-command-on-regionで、リージョンに対して bloggerpost.pyを実行する。

2012年3月21日水曜日

Slimeで日本語を使用する

slimeモードで日本語を使おうと、以下の式を評価すると、

(code-char #\あ)

エラーに遭遇。

Coding system iso-latin-1-unix not suitable for "000041(:emacs-rex (swank:interactive-eval \"(char-code #\あ)\") nil t 1)"

slimeがSwankサーバ(common lispを実行するサーバ)と通信するためのエンコーディング設定 が上手くいっていないため起きるエラー。

slimeがSwankサーバとの通信に使用するエンコーディングは、変数slime-net-coding-systemで 決定される。この変数に'utf-8-unixを設定すると無事日本語が利用できるようになる。以下のように .emacsなどでslime-net-coding-system変数を変更する。

(setq slime-net-coding-system 'utf-8-unix)

すでに、slimeモードでSwankサーバを起動している場合、上記設定の変更を有効にするには サーバ(inferior-lispプロセス)を終了して、再度起動しなおす必要がある。

参考URL:
'T: CREATE-SERVERしたSWANKに接続すると日本語の評価で切断してしまう
Common LISP users jp:SLIME

2012年3月18日日曜日

Ubuntuでclangを利用する

clangは、GCCを置き換えることを目的としたコンパイラフロント・エンド。AppleやGoogleなどの サポートを受け活発に開発が進められている。

GoogleではC++で記述されたコードベースのリファクタリングにclangを利用している という動画 Clang MapReduce – Automatic C++ Refactoring at Google Scaleを見て興味を持ったので clangを試してみる。

ubuntuでは、clangパッケージが存在するので、

apt-get install clang

で、必要なパッケージをインストール。

早速、Hello Worldをclangでコンパイル。

#include <iostream>

int main(int argc, char *argv[]) {
  std::cout << "Hello, world!" << std::endl;

  return 0;
}

clang HelloWorld.cpp

すると以下のようなエラー・メッセージが出てコンパイルに失敗。

/usr/bin/ld: /tmp/cc-sx9qR1.o: in function __cxx_global_var_init:HelloWorld.cpp(.text+0xc): error: undefined reference to 'std::ios_base::Init::~Init()'

/usr/bin/ld: /tmp/cc-sx9qR1.o: in function __cxx_global_var_init:HelloWorld.cpp(.text+0x30): error: undefined reference to 'std::ios_base::Init::Init()'
/usr/bin/ld: /tmp/cc-sx9qR1.o: in function main:HelloWorld.cpp(.text+0x65): error: undefined reference to 'std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&)'

/usr/bin/ld: /tmp/cc-sx9qR1.o: in function main:HelloWorld.cpp(.text+0x70): error: undefined reference to 'std::cout'
/usr/bin/ld: /tmp/cc-sx9qR1.o: in function main:HelloWorld.cpp(.text+0x99): error: undefined reference to 'std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)'

/usr/bin/ld: /tmp/cc-sx9qR1.o: in function main:HelloWorld.cpp(.text+0xa5): error: undefined reference to 'std::basic_ostream<char, std::char_traits<char> >::operator<<(std::basic_ostream<char, std::char_traits<char> >& (*)(std::basic_ostream<char, std::char_traits<char> >&))'

collect2: ld returned 1 exit status
clang: error: linker (via gcc) command failed with exit code 1 (use -v to see invocation)

エラー・メッセージに書かれているように-vオプションを指定して、コンパイルするも ビルド時のオプションが羅列されるだけで解決方法は見つからない。

ググってみると同じエラーに遭遇した人のブログを発見。

clangでc++を試して四苦八苦したメモ:筆者は病気シリーズ3

gccにC++ビルド用のコマンドg++があるのと同様に、clangにもC++ビルド用のclang++コマンドがあるらしい。 上記コードをclang++でビルドすると無事ビルドに成功。

無事にインストールとビルドができたので、しばらくclangで遊んでみよう。

あと、最新バージョンのclangをソースコードからビルドして試してみないと。

2012年3月7日水曜日

2012年2月5日日曜日

読書ノート: The Design and Evolution of C++


C++の生みの親Bjarne Stroustrup本人によるC++言語の進化・発展の回顧録。

Stroustrupが、何を重要と考え、どのように言語仕様を決定してきたか、様々なエピソードを交えて解説している。

第4章のC++ Language Design Rulesに書かれているC++の設計思想を読むと、C++言語が何故現在のような仕様になっているのか、C++が提供している各機能(テンプレート、仮想関数、etc)の理解の助けになる。

設計思想の1つ"Provide comprehensive support for each supported style"に従い、C++は複数のプログラミング・パラダイムをサポートできる奥の深い言語になっている。お陰でプログラマー(C++言語のユーザ&学習者)にとっては、とてもChallengingなのだけど。

2012年1月11日水曜日

Bitbucketで、レポジトリの通信プロトコル(HTTPS->SSH)を変更する

Bitbucketは、Git、Mercurialという2つの分散型バージョン管理システムをサポートするホスティング・サービス。

設定ファイル等のバージョン管理を行うために利用している。

HTTPSを利用してレポジトリのpush、pullなどを行っていたが、パスワードによる認証が面倒になったため、SSHを利用した通信に変更することにした。

BitbucketでSSHを使うに書かれている内容に従い、SSHキーをBitbucket側で設定したあと、ローカルにクローン済みのレポジトリの通信プロトコルを変更することに。

Using the SSHProtocol with bitbucketに、BitbucketでSSHを利用する場合のURL形式が記載されている。

ローカル・レポジトリのルート下に、.hgディレクトリがあり、その中の設定ファイルhgrcを編集する。ローカルのレポジトリは、HTTPSでクローンしたため、hgrcのdefaultパスには、HTTPS用のURLが記載されている。

[paths]
default = https://user_name@bitbucket.org/user_name/repository_name

以下の用に、SSH用のURL形式に変更。

[paths]
default = ssh://hg@bitbucket.org/user_name/repository_name/