download original
# -*- ruby -*-
# some random number generators
# equally distributed random numbers between 0 and 1
$standardRand = proc { rand }
# gaussian random numbers, mean 0, std. deviation 1
# uses "Box-Muller transformation", see http://www.taygeta.com/random/gaussian.html
$gaussRand =
proc {
begin
x1 = 2.0 * rand - 1.0;
x2 = 2.0 * rand - 1.0;
w = x1 * x1 + x2 * x2;
end until ( w < 1.0 );
w = Math.sqrt( (-2.0 * Math.log( w ) ) / w );
x1 * w;
}
# return a generator that "cuts" the output numbers of generator rand
# to fit into (lowerBound, upperBound)
def boundedRand(rand, lowerBound, upperBound)
proc {
begin
r=rand.call()
end until (r>lowerBound) and (r<upperBound)
r
}
end
# return a generator that adds shift to the
# output numbers of generator rand
def shiftedRand(rand, shift)
proc {
rand.call() + shift
}
end
# return a generator that multiplies the
# output numbers of generator rand by scale
def scaledRand(rand, scale)
proc {
rand.call() * scale
}
end
# unify two generators rand1 and rand2, with "preference"
# of rand1 given by rand1amount (0..1)
def unionRand(rand1, rand2, rand1amount)
proc {
r = rand
if r<rand1amount
then rand1.call
else rand2.call
end
}
end
# add two generators rand1 and rand2
def sumRand(rand1, rand2)
proc {
rand1.call + rand2.call
}
end
# generate and return histogram of generator rand
# output format [[x1,y1],[x2,y2],...,[xn,yn]]
def calcRandHistogram2(rand, lowerBound, upperBound, nSections=100, nRuns=10000)
bRand = boundedRand(rand, lowerBound, upperBound)
sectionWidth = (upperBound - lowerBound) / nSections
result = Array.new(nSections) {|i| [lowerBound + i*sectionWidth, 0]}
nRuns.times { |i|
r = bRand.call
result[(r-lowerBound)/sectionWidth][1] += 1
}
result
end
def getRandMeanAndStdDev(rand, nRuns=1000)
sum = 0.0; sqSum = 0.0
nRuns.times {
r = rand.call
sum += r
sqSum += r * r
}
mean = sum / nRuns
stdDev = Math.sqrt(sqSum / nRuns - mean * mean)
[mean, stdDev]
end
def getRandMean(rand, nRuns=1000)
getRandMeanAndStdDev(rand,nRuns)[0]
end
def getRandStdDev(rand, nRuns=1000)
getRandMeanAndStdDev(rand,nRuns)[1]
end
def getRandVariance(rand, nRuns=1000)
stddev = getRandMeanAndStdDev(rand,nRuns)[1]
stddev * stddev
end
# generate and return histogram of generator rand
# output format [[x1,x2,...,xn],[y1,y2,...yn]] (suitable for plotRandHistogram)
def calcRandHistogram(rand, lowerBound, upperBound, nSections=100, nRuns=10000)
bRand = boundedRand(rand, lowerBound, upperBound)
sectionWidth = (upperBound - lowerBound) / nSections
xs = (0...nSections).collect {|i| lowerBound + i*sectionWidth}
ys = [0]*nSections
nRuns.times { |i|
r = bRand.call
ys[(r-lowerBound)/sectionWidth] += 1
}
[xs,ys]
end
# plot histgram as generated by calcRandHistogram
# requires Ruby Gnuplot
def plotRandHistogram(hist,out=nil)
require 'gplot/Gnuplot'
include Gnuplot
xs,ys = hist
plot = Plot.new(out)
plot.title("random number generator histogram")
plot.xlabel("domain")
plot.ylabel("amount")
plot.draw(ArrayDataSet.new(ys, "with"=>"point 3 3", "title"=>nil, "xgrid"=>xs))
end
if __FILE__ == $0
myrand=unionRand(shiftedRand(scaledRand($standardRand,5.0),
-2.0),
shiftedRand(scaledRand($gaussRand,0.7),
1.0),
0.5)
plotRandHistogram(calcRandHistogram(myrand,-4.0,4.0), (ARGV[0] or nil))
end
############################
$quadRand =
proc {
(2.0 * rand - 1.0) * (2.0 * rand - 1.0)
}
def calcExactQuadRandHistogram(lowerBound, upperBound, nSections=100, nRuns=10000)
def P(x,dx)
0.5*(dx-Math.log(x+dx)*(x+dx)+x*Math.log(x))
end
sectionWidth = (upperBound - lowerBound) / nSections
xs = (0...nSections).collect {|i| lowerBound + i*sectionWidth}
ys = (0...nSections).collect {|i|
x = lowerBound + i*sectionWidth
if x.abs>1.0
0.0
else
if x.abs<1e-7
nRuns * P(1e-4,sectionWidth)
else
if x>0.0
nRuns * P(x,sectionWidth)
else
nRuns * P(-x,sectionWidth)
end
end
end
}
[xs,ys]
end
back to math
(C) 1998-2017 Olaf Klischat <olaf.klischat@gmail.com>