XQuery1.0中的线性同余生成器

时间:2017-12-29 01:26:38

标签: xquery

我使用线性相关方法在XQUERY 1.0中编写了(伪)随机数生成器。它有效,但很慢。帮助我改进代码:

xquery version "1.0";
(:pseudorandom number generator using Linear Congruential Method (LCM). The number generated will be less than $m :)
declare namespace mg = "https://www.linkedin.com/in/maria-kedzierski-36088513b/";
declare variable $m:= 32768; (: select $m to be power of 2 :)
declare variable $a:= 25173;  (: $a=1+4k, where k is an integer and  $a < $m :)
declare variable $c:= 13849; (: $c is relative prime to $m and $c < $m  :)
declare variable $x0:= 16384; (: $X0 < $m :)
declare function mg:random($num as xs:integer) as xs:integer {
 if ($num = 1) then (($a * $x0 + $c) mod $m) else (($a * mg:random($num - 1) + $c) mod $m) };

for $i in (1 to 100) return mg:random($i)

1 个答案:

答案 0 :(得分:1)

当我在MarkLogic中分析代码执行时,大部分时间花在重新计算已经生成的数字上。利用地图,您可以缓存这些计算值。

以下是使用MarkLogic map functions XQuery 1.0-ml 转换。它将转换时间从16ms减少到1ms。

xquery version "1.0-ml";
(:pseudorandom number generator using Linear Congruential Method (LCM). The number generated will be less than $m :)
declare namespace mg = "https://www.linkedin.com/in/maria-kedzierski-36088513b/";
declare variable $m:= 32768; (: select $m to be power of 2 :)
declare variable $a:= 25173;  (: $a=1+4k, where k is an integer and  $a < $m :)
declare variable $c:= 13849; (: $c is relative prime to $m and $c < $m  :)
declare variable $x0:= 16384; (: $X0 < $m :)

declare variable $cache := map:new();

declare function mg:random($num as xs:integer) as xs:integer {
 let $key := xs:string($num)
 let $cached-value := map:get($cache, $key)
 return
   if ($cached-value) then
    $cached-value
   else
     let $random-value :=
       if ($num = 1) then 
        ($a * $x0 + $c) mod $m
       else 
        ($a * mg:random($num - 1) + $c) mod $m
     return
       (
         $random-value,
         map:put($cache, $key, $random-value)
       )
 };

for $i in (1 to 100) 
return mg:random($i)

下面是使用标准地图的纯XQuery 3.1模块。尽管MarkLogic具有许多3.x语言功能,但它尚不允许标准map constructors的语法。当我在eXist中分析这个模块时,它实际上将时间从57ms增加到151ms:

xquery version "3.1";
(:pseudorandom number generator using Linear Congruential Method (LCM). The number generated will be less than $m :)
declare namespace mg = "https://www.linkedin.com/in/maria-kedzierski-36088513b/";
declare variable $m:= 32768; (: select $m to be power of 2 :)
declare variable $a:= 25173;  (: $a=1+4k, where k is an integer and  $a < $m :)
declare variable $c:= 13849; (: $c is relative prime to $m and $c < $m  :)
declare variable $x0:= 16384; (: $X0 < $m :)
declare variable $cache := map {}; 
declare function mg:random($num as xs:integer) as xs:integer {
  let $key := xs:string($num)
  let $cached-value := map:get($cache, $key)
  return
   if ($cached-value) then
     $cached-value
   else
     let $random-value :=
       if ($num = 1) then 
        ($a * $x0 + $c) mod $m
       else 
        ($a * mg:random($num - 1) + $c) mod $m
     return 
      ( 
        $random-value,
        map:put($cache, $key, $random-value)
      )[1]
 };

for $i in (1 to 100) 
return mg:random($i)