- Io-2008-01-20で動作確認。
- IoVectorクラスをチューニング、SPLへの依存を廃止。
- ArrayAccess, Countableをimplementする代わりに独自のハンドラを実装。
- []で要素を追加できるようになった。
- RINIT_FUNCTION, RSHUTDOWN_FUNCTIONが値を返していなかったのを修正。
- 他少々。
IoState
バージョン0.4.0からPHP 5.3/6.0の名前空間をサポートしました。
名前空間はIoのPHPオブジェクトのsetNamespaceメソッドで設定、namespaceメソッドで取得できます。setNamespaceメソッドを引数なしで呼び出したり、空文字列や"::"を与えたときはルート名前空間にリセットします。PHPオブジェクトを複製することでマルチ名前空間もできます。
ns1 := PHP clone setNamespace("Zend") ns2 := PHP clone setNamespace("Hoge")
ZvalオブジェクトではUTF-8のシーケンスに変換するtoUTF8メソッドと、UTF-16のシーケンスに変換するtoUTF16メソッドを追加しました。toUTF16メソッドはPHP6でのみ使えます。
また、クラス定数やスタティックプロパティ・メソッドを扱うためのPHPClassオブジェクトを新たに設けました。PHPClassオブジェクトの実体はstdClassです。任意のクラスに対応したPHPClassオブジェクトの複製を得るにはPHPオブジェクトのclassメソッドを使います。
例えば、このPHPコードは
$dt1 = new DateTime; $dt2 = new DateTime("-1 day"); echo $dt1->format(DateTime::W3C), PHP_EOL; echo $dt2->format(DateTime::W3C), PHP_EOL;
これまでも、このように書けていましたが、
dt1 := PHP new("DateTime") dt2 := PHP new("DateTime", "-1 day") dt1 call("format", dt1 const("W3C")) println dt2 call("format", dt2 const("W3C")) println
PHPClassオブジェクトを使うと、こう書くこともできます。
dt := PHP class("DateTime") dt1 := dt new dt2 := dt new("-1 day") dt1 call("format", dt const("W3C")) println dt2 call("format", dt const("W3C")) println
# この場合はconstメソッドよりzConstメソッドを使った方が効率が良いです。
以下はPHPClassオブジェクトのメソッド(スロット)一覧です。
メソッド | 引数 | 戻り値 | 説明 |
---|---|---|---|
asString | - | Sequence | クラス名を取得する。 |
name | - | 〃 | 〃 |
new | 任意のオブジェクト × 任意の数 | Zval (新たなインスタンス) | インスタンスを生成する。 引数はコンストラクタに渡される。 |
call | Sequence (+ 任意のオブジェクト × 任意の数) | Sequence, Number, List, Map, Date (型に応じて自動変換) |
指定されたスタティックメソッドをコールする。 二番目以降の引数はメソッドに渡される。 参照を引数にとるメソッドでは、引数がZvalオブジェクトの場合だけ値が更新される。 |
const | Sequence | 〃 | クラス定数を取得する。 |
var | Sequence | 〃 | スタティックプロパティを取得する。 |
zCall | Sequence (+ 任意のオブジェクト × 任意の数) | Zval (PHPの値をそのまま格納) | 指定されたスタティックメソッドをコールする。 二番目以降の引数はメソッドに渡される。 参照を引数にとるメソッドでは、引数がZvalオブジェクトの場合だけ値が更新される。 |
zConst | Sequence | 〃 | クラス定数を取得する。 |
zVar | Sequence | 〃 | スタティックプロパティを取得する。 |
PHPClassオブジェクトの追加に伴い、Zvalオブジェクトのcall, const, varの各メソッドはレシーバのPHP変数としての型がオブジェクトでない場合はエラーとなるように仕様変更しました。
これ以外のオブジェクトの説明はバージョン0.3.0についてのエントリに書いています。
IoVector
32ビット実数のベクトル演算をするためのクラス。IoStateとは別に独立して使える。IoのVectorオブジェクトではなく、float32のUArrayのラッパー。SIMDをサポートしているため、演算が速い。
foreach文で要素に順番にアクセス、count関数で要素数をカウント、角括弧で要素へのアクセスができる。
API一覧
関数 | 説明 |
---|---|
IoVector iovector([mixed $x[, mixed $y[, mixed $z[, ...]]]]) | IoVectorオブジェクトを作成する。引数はIoVector::__construct()と同じ。 |
!マークつきのメソッドは破壊的なメソッドで、戻り値は自分自身です。
メソッド | 説明 |
---|---|
public void __construct([mixed $x[, mixed $y[, mixed $z[, ...]]]]) | コンストラクタ。各引数がIoVectorなら全要素を追加、配列なら全要素を実数として追加、それ以外は実数として追加する。 |
public string toString(void) | ベクトルの文字列表記を取得する。 |
public string __toString(void) | toString()のエイリアス。 |
public array toArray(void) | ベクトルの全要素を実数の配列として取得する。 |
public IoVector duplicate(void) | ベクトルを複製する。 |
public IoVector dup(void) | duplicate()のエイリアス。 |
public IoVector add(IoVector or float $v)! | ベクトルを加算する。引数が実数なら全要素に同じ値を加算する。 |
public IoVector subtract(IoVector or float $v))! | ベクトルを減算する。引数が実数なら全要素に同じ値を減算する。 |
public IoVector multiply(IoVector or float $v))! | ベクトルを乗算する。引数が実数なら全要素に同じ値を乗算する。 |
public IoVector divide(IoVector or float $v))! | ベクトルを除算する。引数が実数なら全要素に同じ値を除算する。 |
public IoVector sub(IoVector or float $v))! | subtract()のエイリアス。 |
public IoVector mul(IoVector or float $v))! | multiply()のエイリアス。 |
public IoVector div(IoVector or float $v))! | divide()のエイリアス。 |
public IoVector crossProduct(IoVector $v) | ベクトルの外積を求める。 |
public float dotProduct(IoVector $v) | ベクトルの内積を求める。 |
public float distanceTo(IoVector $v) | 各要素の差の2乗の和の平方根を求める。sqrt(pow($v1[0] - $v2[0], 2) + pow($v1[1] - $v2[1], 2) + ...) |
public IoVector sin(void)! | 各要素の正弦を求める。 |
public IoVector cos(void)! | 各要素の余弦を求める。 |
public IoVector tan(void)! | 各要素の正接を求める。 |
public IoVector asin(void)! | 各要素の逆正弦を求める。 |
public IoVector acos(void)! | 各要素の逆余弦を求める。 |
public IoVector atan(void)! | 各要素の逆正接を求める。 |
public IoVector sinh(void)! | 各要素の双曲線正弦を求める。 |
public IoVector cosh(void)! | 各要素の双曲線余弦を求める。 |
public IoVector tanh(void)! | 各要素の双曲線正接を求める。 |
public IoVector exp(void)! | 各要素を自然対数の底に累乗する。 |
public IoVector log(void)! | 各要素の自然対数を求める。 |
public IoVector log10(void)! | 各要素の常用対数を求める。 |
public IoVector square(void)! | 各要素の平方を求める。 |
public IoVector sqrt(void)! | 各要素の平方根を求める。 |
public IoVector ceil(void)! | 各要素の端数を切り上げる。 |
public IoVector fllor(void)! | 各要素の端数を切り捨てる。 |
public IoVector abs(void)! | 各要素の絶対値を求める。 |
public IoVector round(void)! | 各要素を四捨五入する。 |
public IoVector normalize(void)! | 各要素を各要素の2乗の和の平方根で割る。$d = sqrt($v[0]*$v[0] + $v[1]*$v[1] + ...); $v[0] /= $d; $v[1] /= $d; ... |
public bool equals(IoVector $v) | 全要素が等しいか調べる。 |
public bool isZero(void) | 全要素が0か調べる。 |
public float sum(void) | 全要素の和を求める。 |
public float product(void) | 全要素の積を求める。 |
public float max(void) | 最大値を求める。 |
public float min(void) | 最小値を求める。 |
public IoVector push(float $n)! | 末尾に値を追加する。 |
public IoVector unshift(float $n)! | 先頭に値を追加する。 |
public IoVector pop([float &$n])! | 末尾から値を取り除く。取り除いた値は$nに代入される。 |
public IoVector shift([float &$n])! | 先頭から値を取り除く。取り除いた値は$nに代入される。 |
public IoVector sort(void)! | 昇順に並び替える。 |
public IoVector range(int $start, int $size) | インデックス$startから$size個の要素のベクトルを取得する。 |
public IoVector slice(int $start, int $end) | インデックス$startからインデックス$endの直前までの要素のベクトルを取得する。 |
public IoVector copy(IoVector $v)! | 内容を置き換える。 |
public IoVector merge(IoVector $v)! | 末尾にベクトルを追加する。 |
public IoVector setSize(int $size)! | 要素数を変更する。増えた要素の値は0.0。 |
public int size(void) | 要素数を取得する。 |
使用例
マンデルブロ集合の描画によるベンチマーク結果。(参考: http://www.timestretch.com/FractalBenchmark.html)
環境は Mac OS X 10.4.11 (Core 2 Duo 2.33GHz)
ベクトル版は爆速ですね (単精度だけど)。
C gcc-4.0.1 (-O3) | 0.022 sec. | 1.00 x |
C gcc-4.0.1 (-O0) | 0.030 sec. | 1.36 x |
PHP 5.2.5 IoVector (出力バッファリングあり) | 0.121 sec. | 5.50 x |
Io 20080120 Vector | 0.214 sec. | 9.73 x |
PHP 5.2.5 IoVector (出力バッファリングなし) | 0.251 sec. | 11.41 x |
Python 2.5.1 (参考) | 2.374 sec. | 107.91 x |
PHP 5.2.5 | 3.936 sec. | 178.91 x |
Io 20080120 | 37.733 sec. | 1715.14 x |
<?php /** * IoVector version of Fractal Benchmark. * See also http://www.timestretch.com/FractalBenchmark.html */ class Mandelbrot { const MAX_ITERATIONS = 1000; static public function benchmark() { $d1 = microtime(true); self::draw(); $d2 = microtime(true); printf("\nPHP + IoVector Elapsed %f\n", $d2 - $d1); } static public function draw() { $cr = new IoVector; $ci = new IoVector; for ($y = -39; $y < 39; $y++) { $z = $y / 40.0 - 0.5; for ($x = -39; $x < 39; $x++) { $cr[] = $z; $ci[] = $x / 40.0; } } $temp = new IoVector; $temp->setSize(count($cr)); $zr = clone $temp; $zi = clone $temp; $zr2 = clone $temp; $zi2 = clone $temp; for ($i = 0; $i < self::MAX_ITERATIONS; $i++) { $temp->copy($zr)->multiply($zi); $zr2->copy($zr)->multiply($zr); $zi2->copy($zi)->multiply($zi); $zr->copy($zr2)->subtract($zi2)->add($cr); $zi->copy($temp)->multiply(2)->add($ci); } $result = $zi2->duplicate()->add($zr2); $i = 0; for ($y = -39; $y < 39; $y++) { echo "\n"; for ($x = -39; $x < 39; $x++) { echo (!is_nan($result[$i]) && $result[$i] > 0) ? '*' : ' '; $i++; } } } } if (PHP_SAPI == 'cli' && realpath($_SERVER['SCRIPT_FILENAME']) == __FILE__) { ob_start(); Mandelbrot::benchmark(); }