- ベストアンサー
乱数のライブラリについて
- PHP5.2.4を使用して乱数のライブラリを作成する際のフォルダの構造やクラスの分け方、メンバについてアドバイスを求めています。
- 具体的には、Libraryフォルダ内にRandomフォルダを作成し、その中にAbstract.php(各クラスで共通の処理)、Integer.php(整数の乱数)、Decimal.php(小数の乱数)、NormalDistribution.php(正規分布の乱数)のクラスを配置する構成を考えています。
- また、Random.phpというファイルにはどのようなクラスを書けば良いか、このファイルが必要なのかも教えていただきたいです。
- みんなの回答 (3)
- 専門家の回答
質問者が選んだベストアンサー
うーん、 <?php class Library_Random{ public static function factory($type){ $className = 'Library_Random_' . $type; $classPath = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'Random' . DIRECTORY_SEPARATOR . $type . '.php'; if(class_exists($className)) return new $className(); if(file_exists($classPath)){ require_once $classPath; if(class_exists($className)){ $instance = new $className(); return $instance; }else{ throw new Exception('Class Not Found'); } }else{ throw new Exception('File Not Found'); } } } ?> とか、ファクトリークラスにしてしまって、 <?php require_once 'Library/Random.php'; $random = Library_Random::factory('NormalDistribution'); $random->setSeed($seed); foreach($random as $val){ //Library_Random_AbstractにIteratorでも実装してやって //foreachで気の済むまでランダムを生成させ続けることが出来るようにしたりとか? } ?> $decimalPlaceは、初期値持たせちゃって、カスタマイズ必要な人が、インスタンス生成後に セッターメソッド叩くようにすれば良いのではないでしょうか。
その他の回答 (2)
- hogehoge78
- ベストアンサー率80% (433/539)
小数点のランダム、に関しては、私は不勉強でアルゴリズムとかはわからないんですが、 return (float) rand(0, 10000) . "." . sprintf("%08s", rand(0, 99999999)); とかみたいな、ランダムでとった値を文字列で表現してから型変換してリターンというのではまずいですか? メソッドに関しては、メソッドチェーンとかすればセッターでセットして、値を出力する、というのもまぁそんなに苦じゃないのかなと思ったんですが、 <?php $res = $r->set($nu, $sigma)->get(); ?> みたいな感じで。単純にsetとするのかそれぞれの値をsetXXとか分けるのかはまた考えるとして。
お礼
ご回答ありがとうございます。 なるほど、メソッドチェーンを使えば良さそうですね。 小数の方は、それだと例えば最小が-3.5で最大が1.2の乱数を取得したい場合に おそらくそのやり方だと、整数の部分がrand(-3, 1)で仮に1が取得できた時に 小数の部分がもし2より大きな値だと範囲外(例えば1.5とか)になってしまうんです。 なので整数部分が-2から0の間なら小数部分はなんでもかまわないのですが、 そこらへんを工夫すればでなんとかきるんじゃないかなぁと思ってるんですけど(かなりめんどくさいですが^^) なので最初に提示したように10乗のやりかたを試みたわけです。 ただ知りたかったのはライブラリの構造などでしたので、大変参考になりました。 ありがとうございます。
- hogehoge78
- ベストアンサー率80% (433/539)
Iteratorについては、今回のランダムな値を出すライブラリではさほど意味を成さないですね。 ちょっと面白いかと思っただけで、深い意味はないです。 Iteratorの実装については、 http://jp2.php.net/Iterator こちらです。 具体的にどういうときに便利か、といえば、fopen関数などのラッパークラスを作ったりしたときに <?php $file = new MyFile('filename.csv', 'r'); foreach($file as $line){ //foreachで1行ずつ取り出せる } $file->close(); ?> とか出来ると記述がシンプルになって良いかなと。 コンストラクタの引数に関しては、 >(逆に分かり難くはなりますが・・・) とおっしゃるとおりで、分かりづらくなります。 特に同じような動作をするライブラリなのであれば、インターフェイスは統一させたほうが使いやすいかなと。 話は変わりますが、参考資料として、 Zend_Http_Clientなどを見てもらうと何かヒントがもらえるかも。 Zend_Http_Clientはアダプタとして、cURLを使うとか普通にfsockopen使うとか、proxyをかました接続をするとか切り替えられます。 でもソレはそれぞれを自分でnewしてインスタンスを生成するのではなくて、 <?php $uri = 'https://example.com'; $config = array( 'adapter' => 'Zend_Http_Client_Adapter_Curl', 'curloptions' => array( CURLOPT_RETURNTRANSFER => 1, CURLOPT_SSL_VERIFYHOST => 1, CURLOPT_SSL_VERIFYPEER => 1, CURLOPT_CAPATH => 'path', CURLOPT_CAINFO => 'path/to/ca.pem', CURLOPT_SSLCERT => 'path/to/client.pem', CURLOPT_SSLCERTPASSWD => 'password', ), ); $client = new Zend_Http_Client($uri, $config); //※以前別の質問に回答したものをコピペしてきました。 ?> というように、 親となるクラスに、配列で使用するクラスの名前とプロパティを渡してやると、ソレを使った動作を行うようになります。 いかがでしょう。
お礼
ご回答ありがとうございます。 なるほど、このランダムクラスの場合だとZend_Http_Client_Adapter_Interfaceに相当するのが Library_Random_Interface(またはLibrary_Random_Atapter_Interface)というわけですよね? [Library_Random_Interface.php] interface Library_Random_Interface { public function setConfig($config = array()); public function next();// 引数なし } ただどうなんでしょう、next()に引数なしにすれば統一感があるのですが、 例えばこれは整数の乱数の例えなのですが、やっぱり $random = Library_Random::factory('Integer'); $random->setSeed($seed); $random->next(1,5); $random->next(10,20); というふうに引数を指定できた方がこのクラスの場合だとなんとなく良さげな感じがするんです。 なので引数なしのnext()とは別にそれぞれのアダプターでnext($min,$max)とかnext($mu,$sigma)とか追加すればいいんでしょうか? そもそもLibrary_Random_Decimal(小数を含む乱数)は乱数を取得すること自体に無理があるような気がしてて 初めは例えば最小が-3.5と最大が1.2の乱数を取得したいなぁと思ったことがきっかけで、 正規分布の乱数もあるしその他にもありそうなのでアダプターした方がいいのかなぁと思って 一応「小数を含む乱数」ということで分類したのですが、案外それが難しかったりします。 簡単に思いつくやり方(それがほんとに乱数と定義できるかは分かりませんが・・・)は最初に示したように まず取得したい分10乗してそれをrand(10乗したmin, 10乗したmax)、そして最後にかけた分を割ると。 でもこれだと整数部分が大きい数(例えば10000000.232034234)とかだと桁あふれするので無理っぽいんですよね・・・ Library_Random_Decimal(小数を含む乱数)に関しては別にどうしても実現したいってわけでもないので できなきゃ別にいいのですが、もしhogehoge78にアイデアがあれば教えていただけないでしょか?
補足
すいません・・呼び捨てになってました・・・ hogehoge78→hogehoge78さん
お礼
ご回答ありがとうございます。 すいません、お題で間違っていた部分があったので少し訂正しました。 [Integer.php] class Library_Random_Integer extends Library_Random_abstract { public function __construct() { } public function Next($min, $max) { return rand($min, $max); } // 0から1までの小数の乱数を返す public function NextDouble($min, $max) // 整数担当のクラスなのにこれを設けるのはどうかと思いますが・・・ { return $this->Next(0, 2147483647) * (1.0 / 2147483647.0); } } [Decimal.php] class Library_Random_Decimal extends Library_Random_abstract { protected $_decimalPlace = 0; public function __construct() { } public function setDecimalPlace($decimalPlace) { $this->_decimalPlace = $decimalPlace; return $this; } public function next($min, $max) { // どうもうまくいってないようなので、とにかく小数を含む値を返すということで^^ } } [NormalDistribution.php] class Library_Random_NormalDistribution extends Library_Random_abstract { public function __construct() { } public function next($mu, $sigma) { $r = new Library_Random_Integer(); $alpha = $r->NextDouble(); $beta = $r->NextDouble() * pi() * 2; $boxMuller1 = sqrt(-2 * log($alpha)); $boxMuller2 = sin($beta); return $sigma * ($boxMuller1 * $boxMuller2) + $mu; } } 使用例 $r = new Library_Random_NormalDistribution(); $r->setSeed(time()); print $r->next(1000, 500); 質問があるのですが、今回のは__constructに引数を指定しない形にしたのですが、 そもそも__constructにはあまり引数を与えない方がクラス的にはいいのでしょうか? 自分なんかは、クラスをインスタンス化する時についでに指定したい値も追加できたら 便利というか楽(逆に分かり難くはなりますが・・・)だなぁと思ったりするのですが。 あと >Library_Random_AbstractにIterator とのことですが、これを実装するメリットのようなものは何なのでしょうか? $r->next($min, $max); ではなくてIteratorを使うことのメリットというか実装も含めてよく分からないので、 もしよろしければ何か1つ実例を示して頂けないでしょうか? よろしくお願いします。