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 < $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
--~--