xsl-list
[Top] [All Lists]

Re: [xsl] Random number generator that returns numbers from a normal probability distribution and with a specified standard deviation?

2020-06-05 13:35:24
Thank you Mary for your XQuery implementation. I converted Mary's XQuery to 
XSLT. Below is my XSLT implementation of a random number generator that returns 
numbers in a normal distribution with a specified mean and specified standard 
deviation.  /Roger
-------------------------------------------------------
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; 
    xmlns:xs="http://www.w3.org/2001/XMLSchema";
    xmlns:random="random-number-generator-with-normal-distribution"
    xmlns:math="http://exslt.org/math";
    extension-element-prefixes="math"
    exclude-result-prefixes="#all"
    version="2.0">
    
    <!--  
        Returns $length random numbers. The random numbers form 
        a normal distribution (i.e., bell-shaped curve) and are 
        centered around $mean with a standard deviation of $stddev.
        
        Algorithm used: the polar variant of the Box-Muller algorithm.
        
        Thanks to Mary Holstege for showing me how to implement this.
    -->
    <xsl:function name="random:sequence" as="xs:double*">
        <xsl:param name="length" as="xs:integer" />
        <xsl:param name="mean" as="xs:double" />
        <xsl:param name="stddev" as="xs:double" />
        
        <xsl:for-each select="1 to $length">
            <xsl:sequence select="random:normal($mean, $stddev)" />
        </xsl:for-each>
        
    </xsl:function>
    
    <xsl:function name="random:normal" as="xs:double">
        <xsl:param name="mean" as="xs:double" />
        <xsl:param name="stddev" as="xs:double" />
        
        <xsl:sequence select="$mean + random:gauss() * $stddev" />
        
    </xsl:function>
    
    <xsl:function name="random:gauss" as="xs:double">
        
        <xsl:variable name="u" select="2 * math:random() - 1" as="xs:double" />
        <xsl:variable name="v" select="2 * math:random() - 1" as="xs:double" />
        <xsl:variable name="r" select="$u * $u + $v * $v" as="xs:double" />
        
        <xsl:choose>
            <xsl:when test="($r = 0) or ($r >= 1)">
                <xsl:sequence select="random:gauss()" />
            </xsl:when>
            <xsl:otherwise>
                <xsl:variable name="c" select="math:sqrt(-2 * math:log($r) div 
$r)" as="xs:double" />
                <xsl:sequence select="$u * $c" />
            </xsl:otherwise>
        </xsl:choose>
        
    </xsl:function>
    
    <!-- ****************************** -->
    <!--    Test the above functions    -->
    <!-- ****************************** -->
    
    <xsl:template match="/">
        
        <!-- 
            Get one million random numbers, normally distributed, 
            with mean 0.5 and standard deviation 0.3 
        -->
        <xsl:variable name="random-numbers" as="xs:double*">
            <xsl:sequence select="random:sequence(1000000, 0.5, 0.3)" />
        </xsl:variable>
        
        <xsl:text>Percentage of the random numbers in the range: mean 
plus/minus one standard deviation = </xsl:text>
        <xsl:sequence select="count(for $j in $random-numbers return if (($j ge 
0.2) and ($j le 0.8)) then $j else ()) div 1000000" />
<xsl:text>
</xsl:text> 
        
        <xsl:text>Percentage of the random numbers in the range: mean 
plus/minus two standard deviations = </xsl:text>
        <xsl:sequence select="count(for $j in $random-numbers return if (($j ge 
-0.1) and ($j le 1.1)) then $j else ()) div 1000000" />
<xsl:text>
</xsl:text> 
        
        <!-- 
            Divide up the range 0 to 1 into 100 intervals and 
            count the number of random numbers in each interval. 
        -->
        <xsl:for-each select="1 to 100">
            <xsl:variable name="i" select="." />
            <xsl:variable name="lo" select="($i - 1) div 100" />
            <xsl:variable name="hi" select="$i div 100" />
            <xsl:sequence select="$i" /><xsl:text>. </xsl:text>
            <xsl:sequence select="count(for $j in $random-numbers return if 
(($j >= $lo) and ($j &lt; $hi)) then $j else ())" />
<xsl:text>
</xsl:text> 
        </xsl:for-each>
        
        <!-- Show the random numbers -->
        <xsl:sequence select="$random-numbers" />
    </xsl:template>
    
</xsl:stylesheet>
-------------------------------------------------------

From: Mary Holstege holstege(_at_)mathling(_dot_)com 
<xsl-list-service(_at_)lists(_dot_)mulberrytech(_dot_)com> 
Sent: Tuesday, June 2, 2020 9:48 AM
To: xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com
Subject: [EXT] Re: [xsl] Random number generator that returns numbers from 
anormal probability distribution and with a specified standard deviation?

I have an XQuery function that does it. It depends on an underlying function 
(here rand:uniform) to give uniform numbers in [0,1].  Most "random" functions 
will give you uniformly distributed random numbers; if your platform doesn't 
have one, you'll have to concoct your own pseudo-random function
This is the polar variant of the Box-Muller algorithm
(: 
 : normal()
 : Return random normally distributed data.
 : 
 : $mean: Mean of range of values
 : $std: Standard deviation of range of values
 :)
declare function rand:normal(
  $mean as xs:double,
  $std as xs:double
) as xs:double
{
  $mean + rand:gauss() * $std
};

(: 
 : gauss()
 : Return random normally distributed data between 0 and 1
 : A service function used by normal() 
 :)
declare %private function rand:gauss() as xs:double
{
  let $u as xs:double := 2 * rand:uniform(0,1) - 1
  let $v as xs:double := 2 * rand:uniform(0,1) - 1
  let $r := $u * $u + $v * $v
  return (
    if ($r = 0 or $r >= 1) then rand:gauss()
    else (
      let $c as xs:double := math:sqrt(-2 * math:log($r) div $r)
      return $u * $c
    )
  )
};


On 5/31/20 10:37 AM, Roger L Costello mailto:costello(_at_)mitre(_dot_)org 
wrote:
Hi Folks,

I need a random number generator that returns numbers from a normal probability 
distribution, centered around zero, and with standard deviation that can be 
specified. Has anyone created such a thing? 

I am using XSLT/XPath 2.0

/Roger
http://www.mulberrytech.com/xsl/xsl-list 
http://lists.mulberrytech.com/unsub/xsl-list/673357 () 
--~----------------------------------------------------------------
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
EasyUnsubscribe: http://lists.mulberrytech.com/unsub/xsl-list/1167547
or by email: xsl-list-unsub(_at_)lists(_dot_)mulberrytech(_dot_)com
--~--

<Prev in Thread] Current Thread [Next in Thread>