The Normal (or Gaussian) distribution is a frequently used distribution in statistics. While most programming languages provide a uniformly distributed random number generator, one can derive normally distributed random numbers from a uniform generator.



The task

 Take a uniform random number generator and create a large (you decide how large) set of numbers that follow a normal (Gaussian) distribution. Calculate the dataset's mean and standard deviation, and show a histogram of the data.
 Mention any native language support for the generation of normally distributed random numbers.


Reference

 You may refer to code in Statistics/Basic if available.


Procedure.f randomf(resolution = 2147483647)
  ProcedureReturn Random(resolution) / resolution
EndProcedure
 
Procedure.f normalDist() ;Box Muller method
   ProcedureReturn Sqr(-2 * Log(randomf())) * Cos(2 * #PI * randomf())
EndProcedure
 
Procedure sample(n, nBins = 50)
  Protected i, maxBinValue, binNumber
  Protected.f d, mean, sum, sumSq, mx, mn, range
 
  Dim dat.f(n)
  For i = 1 To n
    dat(i) = normalDist()
  Next
 
  ;show mean, standard deviation, find max & min.
  mx  = -1000
  mn  =  1000
  sum = 0
  sumSq = 0
  For i = 1 To n
    d = dat(i)
    If d > mx: mx = d: EndIf
    If d < mn: mn = d: EndIf
    sum + d
    sumSq + d * d
  Next
 
  PrintN(Str(n) + " data terms used.")
  PrintN("Largest term was " + StrF(mx) + " & smallest was " + StrF(mn))
  mean = sum / n
  PrintN("Mean = " + StrF(mean))
  PrintN("Stddev = " + StrF((sumSq / n) - Sqr(mean * mean)))
 
  ;show histogram
  range = mx - mn
  Dim bins(nBins)
  For i = 1 To n
    binNumber = Int(nBins * (dat(i) - mn) / range)
    bins(binNumber) + 1
  Next
 
  maxBinValue = 1
  For i = 0 To nBins
    If bins(i) > maxBinValue
      maxBinValue = bins(i)
    EndIf
  Next
 
  #normalizedMaxValue = 70
  For binNumber = 0 To nBins
    tickMarks = Round(bins(binNumber) * #normalizedMaxValue / maxBinValue, #PB_Round_Nearest)
    PrintN(ReplaceString(Space(tickMarks), " ", "#"))
  Next
  PrintN("")
EndProcedure
 
If OpenConsole()
  sample(100000)
 
  Print(#CRLF$ + #CRLF$ + "Press ENTER to exit"): Input()
  CloseConsole()
EndIf