その数式、プログラムできますか?
この書籍を最近読み始めました。
数学的な課題を題材に、公式や定理が考案された歴史的背景や、解法を編み出した人物像と共に解説し、そしてそれを実際のコードに落とし込む場合どうなるかというのを、段階的に思考過程を示しながら、サンプルコードとともに示されています。
なかなか面白い本だと思います。
ただ、内容が自分には難しすぎて、実際にサンプルを入力しながら読み進めていかないとついて行くのがなかなか厳しい。さらに、サンプルコードはC++11を前提としており、手元のプライベートなMacbookAirには手軽に使える開発環境がありません。
気合いで標準導入されたGCCを使うとか、Objective-Cに変換しながらコーディングしてみても良いですが、書籍のサンプルコードは、せいぜい数十行で、関数も単一のものが大半です。気合いを入れたり、統合開発環境をいちいち立ち上げたりなどは少し大げさな感じです。もう少し手軽にサンプルコードを試せる環境が欲しいところです。
PythonではIPythonのようなREPLを使えば、その場その場で思い付いたコードを試す事ができます。この手軽さが理想。C++版のREPLがほしいところです。
そして有り難い事に、ClingというREPLおよびインタプリタを、CERNが公開していました。CERNは大型ハドロン衝突型加速器で有名なあのCERNです。早速導入してみます。
Clingの導入
Clingの導入は、ソースをgit cloneし、Buildする事で行います。Buildには、CERNが提供するBuildScriptを使う方法の他、CMakeやconfigure+Makeを使って手動でBuildする方法があります。<導入手順(英文)>
https://root.cern.ch/cling-build-instructions
今回は、手元のmac環境にもともとCMakeが導入されていたので、CMakeを使って手動でBuildしてみました。
英文が読める方は、手順の通り実施すれば多くの場合は問題ないかと思いますが、手動Buildでハマりました。Windowsであるのと、個人的にうっかりミスを誘う記載があり、余分な時間を使った箇所があったので、そのあたりを踏まえた手順を述べたいと思います。
なお、Clangを全てソースからビルドするので、かなり時間が掛かります。他の作業と並行するなど、時間的な余裕をもっての実施をおすすめします。
ソースのビルド
導入するディレクトリを任意の名称(仮に/Users/<login-acount名>/clingとします)で作成した後、まず、CERNのgitからソースをCloneします。リンクの手順(Manual Build)の記載に従い、下記のコマンドを実行します。<Building with CMake>
git clone http://root.cern.ch/git/llvm.git src cd src git checkout cling-patches cd tools git clone http://root.cern.ch/git/cling.git git clone http://root.cern.ch/git/clang.git cd clang git checkout cling-patches cd ..
さて、原文だと最後のcd ..で1階層上にカレントディレクトリを移動していますが、なぜこの操作が記載されているのか良くわかりません。ここは正しくは、「clangを1階層上に登る」ではなく、「最初に作ったディレクトリ配下に移動」が正しいです。ですので、もう2段上にカレントディレクトリを移動しましょう。
cd ..
cd ..
pwd (※Windowsでは単にcd)
(pwdの結果)/Users/<login-acount名>/cling
mkdir build
cd build cmake -DCMAKE_INSTALL_PREFIX=[Install Path] ..\src3行目のコマンドについて、..\src の記載箇所にちょっとした注意が必要です。
cmake -DCMAKE_INSTALL_PREFIX=[Install Path] ..\src
..\src はCloneしたソースコード相対パスを示していますが、cernのページはWindowsを前提としているので、バックスラッシュつまり日本語OSでの¥マークであり、一方macなどではバックスラッシュではなく、ただのスラッシュでなければなりません。
<macでのcmakeコマンド実行>
cmake -DCMAKE_INSTALL_PREFIX=[Install Path] ../src
最初のcmakeの処理が終わったら、以下のコマンドを順次実行していきましょう。
cmake --build . --config [Release/Debug] --target clang
cmake --build . --config [Release/Debug] --target cling
全ての手順が終わったら、ビルド後のbinディレクトリに移動して、clingコマンドを実行してみましょう。
cd bin
./cling (※Windowsでは単にcling)
****************** CLING ******************
* Type C++ code and press enter to run it *
* Type .q to exit *
*******************************************
[cling]$
clingの対話式コマンド入力モードになっていれば、導入は成功です。対話モードが不要になった時は.qと入れれば、解除されます。
Clingを使った最初の操作
Clingで導入されたClangはC++11対応という事なので、lamdaがつかえます。lamda式のコードとともに簡単な操作を行ってみます。必要に応じてclingコマンドを実行し対話モードにしてください。
./cling (※Windowsでは単にcling)
****************** CLING ******************
* Type C++ code and press enter to run it *
* Type .q to exit *
*******************************************
[cling]$ #include <stdio.h>
[cling]$ auto f = []{printf("Hello, CLing\n"); };
[cling]$ f()
Hello, CLingREPL風に、includeからlamdaで記載された関数の定義と、その実行まで順次対話的に入力していきます。入力ミスによるエラーがあっても、行を確定した時点でフィードバックがあるので、再度入力しなおせば、最終的には実行が成功する事になります。
サンプルの実行
書籍「その数式、プログラムできますか?」から、足し算のみによってかけ算を実現する「エジプト乗法」というアルゴリズムのコードをサンプルとして、入力から実行までを行ってみます。下記のようなコードを入力してみます。 (コードは実際の書籍からアレンジしてます)
コードを入力し、実行してみましょう。auto odd = [](int n)-> bool { return n & 0x1; }
auto half = [](int n)-> int { return n >> 1; }
int mult_acc4(int r, int n, int a) {
while (true) {
if (odd(n)) {
r = r + a;
if (n == 1) return r;
}
n = half(n);
a = a + a;
}
}
int multiply4(int n, int a) {
while (!odd(n)) {
a = a + a;
n = half(n);
}
if (n == 1) return a;
return mult_acc4(a, half(n -1), a + a);
}
なお、途中出てくる.rawInputというのは、複数行からなる関数などを書く場合につかいます。行毎にコンパイルしないようにclingに指示するコマンドです。
./cling (※Windowsでは単にcling)
****************** CLING ******************
* Type C++ code and press enter to run it *
* Type .q to exit *
*******************************************
[cling]$ auto odd = [](int n)-> bool { return n & 0x1; } ((lambda) &) @0x108afcb30 [cling]$ auto half = [](int n)-> int { return n >> 1; } ((lambda) &) @0x108afcbb0
[cling]$ .rawInput Using raw input [cling]! int mult_acc4(int r, int n, int a) { [cling]! ? while (true) { [cling]! ? if (odd(n)) { [cling]! ? r = r + a; [cling]! ? if (n == 1) return r; [cling]! ? } [cling]! ? n = half(n); [cling]! ? a = a + a; [cling]! ? } [cling]! ? }
[cling]! int multiply4(int n, int a) { [cling]! ? while (!odd(n)) { [cling]! ? a = a + a; [cling]! ? n = half(n); [cling]! ? } [cling]! ? if (n == 1) return a; [cling]! ? return mult_acc4(a, half(n -1), a + a); [cling]! ? } [cling]! .rawInput Not using raw input
[cling]$ multiply4(6,80) (int) 480
[cling]$ multiply4(78,80) (int) 6240
無事、実行できました。Enjoy!