- RcppはRの(関数を作ったりするときに使う)パッケージでC++を使うためのパッケージ
- WindowsでRを使っており、ちょっと前作業も必要なので、冬休みくらいに、時間があるときに向いている
- こちらで書かれているように「むっちゃ速い」ということなので、試してみよう
- むっちゃ速いというサイトのソースは、コピーペースト-readyではないので、その本家のサイト(こちら)のソースを使ってみる
- 「Cってどんな感じ?」と試したのが数年前(3日間とか?)、C++っていいよ、と言われて試したこともないけど、その程度の知識でも使えるようになるか、やってみよう
- その他参考(こちらやこちら→と思ったら、後者は読めないサイトでした…)
f <- function(n, x=1) for (i in 1:n) x=1/(1+x)
g <- function(n, x=1) for (i in 1:n) x=(1/(1+x))
h <- function(n, x=1) for (i in 1:n) x=(1+x)^(-1)
j <- function(n, x=1) for (i in 1:n) x={1/{1+x}}
k <- function(n, x=1) for (i in 1:n) x=1/{1+x}
install.packages("Rcpp")
install.packages("inline")
library(Rcpp)
library(inline)
l <- cxxfunction(signature(ns="integer", xs="numeric"),
'int n = as<int>(ns); double x=as<double>(xs);
for (int i=0; i<n; i++) x=1/(1+x);
return wrap(x); ',
plugin="Rcpp")
- これをコピーペーストしただけでは、次のようなエラーが出る
g++: not found
g++: not found CRAN windows
- "コンパイルできない"まずは、コンパイル問題を解決しよう。gccがないとのこと、次のようなキーワードでウェブ検索するとこんなサイトに行きつく
- Rの64bit版と32bit版とでコンパイラに違いがあって、それに伴うトラブルもあるようだ(64ビット版のR x64-2.14.1ではだめだったがR 2.14.1 (32bit版)ではうまく行った)
- 以下のように解決する方法もあるが、こちらに書いたように、Rtoolsを使って解決することもできる
- その中で必要とされているMinGWとMSYSで検索すると、それぞれが、コンパイラなどの一括ダウンロードセットのようなものであることがわかる
- こちらを参考にしてインストールしてみる
-
- こんな画面が出て、ハイライトしているところを書き換えるわけだけれど、「初心に戻って」考えると、こういうときに悩むのは、『本当に書き換えても大丈夫なのか』ということ
- というわけで、エクスプローラで拡張子を表示させるという設定変更にも抵抗がある人向けの説明を書こう
- まず、ハイライト部分をすべてハイライトしてあることを確認した上で、コピーしてテキストエディタにペーストする
- 中身がよく観察できる環境にした上で、「さて、パスを通すとは、どうすればいいか」をよく眺める。良く眺める理由は、いざとなったら、自分の責任でもとに戻せるため
- ';'で継ぎ足し、継ぎ足しをした構成になっていることを自分の眼で確認したら、あとは、継ぎ足すべき文字列を決める
- さきほどインストールしたMinGWは"C:\MinGW"に入ったのですが、それを確認した上で、そこの"bin"フォルダを確認しつつ、その中も見ておきます
-
-
- このフォルダをしていすればよいので、次のように書き換わります
...;C:\MinGW\bin;C:\msys\1.0\bin
- こうしたうえで、コマンドプロンプトを立ち上げなおして、"gcc"とかのコマンドを打つと、今度は、(コンパイルされるべきファイルを渡していないので、エラーメッセージは出ますが)"gcc"というコマンド自体は認識されていることがわかります
- さて、念のためRを再起動して、もう一度、以下を回すと、今度は動きます
l <- cxxfunction(signature(ns="integer", xs="numeric"),
'int n = as<int>(ns); double x=as<double>(xs);
for (int i=0; i<n; i++) x=1/(1+x);
return wrap(x); ',
plugin="Rcpp")
> l
An object of class "CFunc"
function (ns, xs)
.Primitive(".Call")(<pointer: 0x66781290>, ns, xs)
<environment: 0x09809ec8>
Slot "code":
[1] "\n// includes from the plugin\n\n#include <Rcpp.h>\n\n\n#ifndef BEGIN_RCPP\n#define BEGIN_RCPP\n#endif\n\n#ifndef END_RCPP\n#define END_RCPP\n#endif\n\nusing namespace Rcpp;\n\n\n// user includes\n\n\n// declarations\nextern \"C\" {\nSEXP filea6034c539e9( SEXP ns, SEXP xs) ;\n}\n\n// definition\n\nSEXP filea6034c539e9( SEXP ns, SEXP xs ){\nBEGIN_RCPP\nint n = as<int>(ns); double x=as<double>(xs);\n for (int i=0; i<n; i++) x=1/(1+x);\n return wrap(x); \nEND_RCPP\n}\n\n\n"
- Rcppパッケージ、inlineパッケージはうまく動いたようなので、次に進みます
library(rbenchmark)
N <- 1e6
benchmark(f(N, 1), g(N, 1), h(N, 1), j(N, 1), k(N, 1), l(N, 1),
columns=c("test", "replications", "elapsed", "relative"),
order="relative", replications=10)
- benchmark()の出力を見ると、何をする関数なのかはわかる
- 複数の関数に繰り返し処理をさせて、所要時間の測定と、相対的な速さを「速い順」に出す関数だ
> benchmark(f(N, 1), g(N, 1), h(N, 1), j(N, 1), k(N, 1), l(N, 1),
+ columns=c("test", "replications", "elapsed", "relative"),
+ order="relative", replications=10)
test replications elapsed relative
6 l(N, 1) 10 0.29 1.00000
1 f(N, 1) 10 9.22 31.79310
4 j(N, 1) 10 10.73 37.00000
2 g(N, 1) 10 11.11 38.31034
3 h(N, 1) 10 13.34 46.00000
5 k(N, 1) 10 22.73 78.37931
- 思ったより手早く、終わった。年末の雑事をしながら、実質2時間の作業か。これなら、タイムパフォーマンスは悪くない
- 後は、次の部分を書くことが億劫でなくなるだけ
l <- cxxfunction(signature(ns="integer", xs="numeric"),
'int n = as<int>(ns); double x=as<double>(xs);
for (int i=0; i<n; i++) x=1/(1+x);
return wrap(x); ',
plugin="Rcpp")