PostgreSQLで疑似乱数

レンタル鯖で使える(≒環境を選ばない)疑似乱数の発生プログラムを考える上で、これまでは「特定の言語のネイティブ表現だけで疑似乱数アルゴリズムを実装する」方向で検討してきた訳だが、風呂に入ってだらだら考えたら別の遣り方が見えてきたので、試しに実験してみた。
いきなりMTはつらいので、まずは線形合同法で。

レンタル鯖に、この場合はPostgreSQLがインストールされ、使える状態にあるとする。

lcg_id, name, lcg_a, lcg_b, lcg_m, last_num, seedの六つのカラムを持つテーブルを作る。
それぞれ、シーケンス型のID,、サイコロにつける名前、線形合同法のAとBとM、最後に返した値(初期値は0)、種の六種。
これに、適当に線形合同法に則ったレコードを追加する。ひとつのレコードが一つのサイコロに該当する。

INSERT INTO lcg ( name, lcg_a, lcg_b, lcg_m, last_num, seed ) VALUES ( "sample", 51, 79, 65536, 0, 0 );

それから、関数を作る。

CREATE FUNCTION lcg_next ( varchar )
RETURNS integer
AS 'UPDATE lcg SET last_num = mod ( last_num * lcg_a + lcg_b , lcg_m ) WHERE name = $1; SELECT last_num FROM lcg WHERE name = $1;'
LANGUAGE 'SQL';

これで準備完了。
後は、

SELECT lcg_next('sample');

を実行する度に、線形合同法による疑似乱数が返される。

感想

RDBMを使ってメルセンヌ・ツイスターの実装って、頑張ればできそう。

PostgreSQLで疑似乱数

レンタル鯖で使える(≒環境を選ばない)疑似乱数の発生プログラムを考える上で、これまでは「特定の言語のネイティブ表現だけで疑似乱数アルゴリズムを実装する」方向で検討してきた訳だが、風呂に入ってだらだら考えたら別の遣り方が見えてきたので、試しに実験してみた。
いきなりMTはつらいので、まずは線形合同法で。

レンタル鯖に、この場合はPostgreSQLがインストールされ、使える状態にあるとする。

lcg_id, name, lcg_a, lcg_b, lcg_m, last_num, seedの六つのカラムを持つテーブルを作る。
それぞれ、シーケンス型のID,、サイコロにつける名前、線形合同法のAとBとM、最後に返した値(初期値は0)、種の六種。
これに、適当に線形合同法に則ったレコードを追加する。ひとつのレコードが一つのサイコロに該当する。

INSERT INTO lcg ( name, lcg_a, lcg_b, lcg_m, last_num, seed ) VALUES ( "sample", 51, 79, 65536, 0, 0 );

それから、関数を作る。

CREATE FUNCTION lcg_next ( varchar )
RETURNS integer
AS 'UPDATE lcg SET last_num = mod ( last_num * lcg_a + lcg_b , lcg_m ) WHERE name = $1; SELECT last_num FROM lcg WHERE name = $1;'
LANGUAGE 'SQL';

これで準備完了。
後は、

SELECT lcg_next('sample');

を実行する度に、線形合同法による疑似乱数が返される。

感想

RDBMを使ってメルセンヌ・ツイスターの実装って、頑張ればできそう。

PostgreSQLで疑似乱数

レンタル鯖で使える(≒環境を選ばない)疑似乱数の発生プログラムを考える上で、これまでは「特定の言語のネイティブ表現だけで疑似乱数アルゴリズムを実装する」方向で検討してきた訳だが、風呂に入ってだらだら考えたら別の遣り方が見えてきたので、試しに実験してみた。
いきなりMTはつらいので、まずは線形合同法で。

レンタル鯖に、この場合はPostgreSQLがインストールされ、使える状態にあるとする。

lcg_id, name, lcg_a, lcg_b, lcg_m, last_num, seedの六つのカラムを持つテーブルを作る。
それぞれ、シーケンス型のID,、サイコロにつける名前、線形合同法のAとBとM、最後に返した値(初期値は0)、種の六種。
これに、適当に線形合同法に則ったレコードを追加する。ひとつのレコードが一つのサイコロに該当する。

INSERT INTO lcg ( name, lcg_a, lcg_b, lcg_m, last_num, seed ) VALUES ( "sample", 51, 79, 65536, 0, 0 );

それから、関数を作る。

CREATE FUNCTION lcg_next ( varchar )
RETURNS integer
AS 'UPDATE lcg SET last_num = mod ( last_num * lcg_a + lcg_b , lcg_m ) WHERE name = $1; SELECT last_num FROM lcg WHERE name = $1;'
LANGUAGE 'SQL';

これで準備完了。
後は、

SELECT lcg_next('sample');

を実行する度に、線形合同法による疑似乱数が返される。

感想

RDBMを使ってメルセンヌ・ツイスターの実装って、頑張ればできそう。

最近の愚痴

私的に作っているWeb上のデータベースがあるが、そのデータベースのレスポンスが激しく遅くてストレスが溜まる。
原因は多分野放図に(俺が)拡張したプログラムと、鯖の他のユーザーがなんかやってることにあるんだろうが、それでもストレスが溜まることは確か。
しかしPerlにそもそもそういうカリカリにチューニングした速さを求めるのも何だかなあと言う昔からの格言が思い出されて何も言えなくなったり。
ただまあ、SELECTやINSERTはともかく、DELETEを行う際にさらに遅くなるのは、俺のせいじゃないような気もする。

最近の愚痴

私的に作っているWeb上のデータベースがあるが、そのデータベースのレスポンスが激しく遅くてストレスが溜まる。
原因は多分野放図に(俺が)拡張したプログラムと、鯖の他のユーザーがなんかやってることにあるんだろうが、それでもストレスが溜まることは確か。
しかしPerlにそもそもそういうカリカリにチューニングした速さを求めるのも何だかなあと言う昔からの格言が思い出されて何も言えなくなったり。
ただまあ、SELECTやINSERTはともかく、DELETEを行う際にさらに遅くなるのは、俺のせいじゃないような気もする。

最近の愚痴

私的に作っているWeb上のデータベースがあるが、そのデータベースのレスポンスが激しく遅くてストレスが溜まる。
原因は多分野放図に(俺が)拡張したプログラムと、鯖の他のユーザーがなんかやってることにあるんだろうが、それでもストレスが溜まることは確か。
しかしPerlにそもそもそういうカリカリにチューニングした速さを求めるのも何だかなあと言う昔からの格言が思い出されて何も言えなくなったり。
ただまあ、SELECTやINSERTはともかく、DELETEを行う際にさらに遅くなるのは、俺のせいじゃないような気もする。

ユーザー・スキーマ・テーブル・カラム

テーブルのカラム名とデータ型を、SQLを使って動的に取得する。 - 永字八法の続き。面倒なので、VIEWにしてしまおうと思う。

SELECT pg_user.usename AS "owner", pg_namespace.nspname AS "schema", pg_class.relname AS "table", pg_attribute.attname AS "column", pg_type.typname AS "type", pg_attribute.attlen AS length
   FROM pg_namespace, pg_class, pg_attribute, pg_type, pg_user
  WHERE pg_user.usesysid = pg_namespace.nspowner AND pg_namespace.oid = pg_class.relnamespace AND pg_class.relkind = 'r'::"char" AND pg_class.oid = pg_attribute.attrelid AND pg_attribute.atttypid = pg_type.oid AND (pg_attribute.atttypid < 26::oid OR pg_attribute.atttypid > 29::oid)
  ORDER BY pg_namespace.nspowner, pg_namespace.nspname, pg_class.relname;

上記のSQLをVIEWにすると幸せかも。