for i in [0 ... n]
for j in [0 ... n]
sum = 0
for k in [0 ... n]
sum += xs[i][k] * ys[k][j]
sum
m = module.exports = (n, xs, ys) ->
for i in [0 ... n]
for j in [0 ... n]
sum = 0
for k in [0 ... n]
sum += xs[i][k] * ys[k][j]
sum
v8: v8::Object Class Reference
何も情報が無い値は大体、v8::Value
だから、
- v8配列への変換
v8::Array::Cast(_)
- v8配列へのアクセス
v8::Array::Get(int, v8::Value)
- intからv8数値への変換
v8::Number::New(int)
でもdoubleとかからならともかく、
int -> v8::Number
は結構暗黙的にやってくれる(本当)
20分くらいで今勉強したけど、結構スムーズに書けて嬉しいな。
sugar/sugar.cc
より、上の3重ループ相当箇所
for (int i=0; i < n; ++i) {
Local<Array> line = Array::New(n);
for (int j=0; j < n; ++j) {
double sum = 0;
for (int k=0; k < n; ++k) {
double x = Local<Array>::Cast(xs->Get(Number::New(i)))->Get(Number::New(k))->NumberValue();
double y = Local<Array>::Cast(ys->Get(Number::New(k)))->Get(Number::New(j))->NumberValue();
sum += x * y;
}
line->Set(Number::New(j), Number::New(sum));
}
ret->Set(Number::New(i), line);
}
配列アクセスのたびにキャストしてたので、これはやばい。 普通に考えて、v8世界の値からのキャストは遅いに決まってる。
cd sugar
node-gyp configure build
常識として、必要な値は予めキャストして、
int n = args[0]->NumberValue();
Local<Array> xs0 = Local<Array>::Cast(args[1]);
Local<Array> ys0 = Local<Array>::Cast(args[2]);
int xs[n][n];
int ys[n][n];
for (int i=0; i<n; ++i) {
for (int j=0; j<n; ++j) {
xs[i][j] = Local<Array>::Cast(xs0->Get(i))->Get(j)->NumberValue();
ys[i][j] = Local<Array>::Cast(ys0->Get(i))->Get(j)->NumberValue();
}
}
誰がどう見てもC++
for (int i=0; i<n; ++i) {
Local<Array> line = Array::New(n);
for (int j=0; j<n; ++j) {
double sum = 0;
for (int k=0; k<n; ++k) {
sum += xs[i][k] * ys[k][j];
}
line->Set(j, Number::New(sum));
}
ret->Set(i, line);
}
cd milk
node-gyp configure build
coffee ./test.coffee
n を変えて一回だけ計算させてみる。
n | 2 | 4 | 10 | 100 | 200 | 300 |
---|---|---|---|---|---|---|
black | 0 | 0 | 0 | 38 | 276 | 1033 |
sugar | 0 | 0 | 0 | 280 | 2296 | 8589 |
milk | 0 | 0 | 0 | 3 | 17 | 48 |
単位は ms
うん。って感じだ