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

Subject: Re: [xsl] Random number generator that returns numbers from a normal probability distribution and with a specified standard deviation?
From: "Roger L Costello costello@xxxxxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
Date: Fri, 5 Jun 2020 18:35:16 -0000
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@xxxxxxxxxxxx
<xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
Sent: Tuesday, June 2, 2020 9:48 AM
To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
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].B  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@xxxxxxxxx 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 ()

Current Thread