Code to generate Gaussian (normally distributed) random numbers in Ruby

后端 未结 4 723
夕颜
夕颜 2021-02-01 03:32

What is some code to generate normally distributed random numbers in ruby?

(Note: I answered my own question, but I\'ll wait a few days before accepting to see if anyone

相关标签:
4条回答
  • 2021-02-01 04:00

    Python's random.gauss() and Boost's normal_distribution both use the Box-Muller transform, so that should be good enough for Ruby too.

    def gaussian(mean, stddev, rand)
      theta = 2 * Math::PI * rand.call
      rho = Math.sqrt(-2 * Math.log(1 - rand.call))
      scale = stddev * rho
      x = mean + scale * Math.cos(theta)
      y = mean + scale * Math.sin(theta)
      return x, y
    end
    

    The method can be wrapped up in a class that returns the samples one by one.

    class RandomGaussian
      def initialize(mean, stddev, rand_helper = lambda { Kernel.rand })
        @rand_helper = rand_helper
        @mean = mean
        @stddev = stddev
        @valid = false
        @next = 0
      end
    
      def rand
        if @valid then
          @valid = false
          return @next
        else
          @valid = true
          x, y = self.class.gaussian(@mean, @stddev, @rand_helper)
          @next = y
          return x
        end
      end
    
      private
      def self.gaussian(mean, stddev, rand)
        theta = 2 * Math::PI * rand.call
        rho = Math.sqrt(-2 * Math.log(1 - rand.call))
        scale = stddev * rho
        x = mean + scale * Math.cos(theta)
        y = mean + scale * Math.sin(theta)
        return x, y
      end
    end
    

    CC0 (CC0)

    To the extent possible under law, antonakos has waived all copyright and related or neighboring rights to the RandomGaussian Ruby class. This work is published from: Denmark.


    The license statement does not mean I care about this code. On the contrary, I don't use the code, I haven't tested it, and I don't program in Ruby.

    0 讨论(0)
  • 2021-02-01 04:03

    Another option, this one using the distribution gem, written by one of the SciRuby fellows.

    It is a little simpler to use, I think.

    require 'distribution'
    normal = Distribution::Normal.rng(1)
    norm_distribution = 1_000.times.map {normal.call}
    
    0 讨论(0)
  • 2021-02-01 04:11

    The original question asked for code, but the author's followup comment implied an interest in using existing libraries. I was interested in the same, and my searches turned up these two ruby gems:

    gsl - "Ruby interface to the GNU Scientific Library" (requires you to install GSL). The calling sequence for normally distributed random numbers with mean = 0 and a given standard deviation is

     rng = GSL::Rng.alloc
     rng.gaussian(sd)      # a single random sample
     rng.gaussian(sd, 100) # 100 random samples
    

    rubystats - "a port of the statistics libraries from PHPMath" (pure ruby). The calling sequence for normally distributed random numbers with a given mean and standard deviation is

     gen = Rubystats::NormalDistribution.new(mean, sd)
     gen.rng               # a single random sample
     gen.rng(100)          # 100 random samples
    
    0 讨论(0)
  • 2021-02-01 04:11

    +1 on @antonakos's answer. Here's the implementation of Box-Muller that I've been using; it's essentially identical but slightly tighter code:

    class RandomGaussian
      def initialize(mean = 0.0, sd = 1.0, rng = lambda { Kernel.rand })
        @mean, @sd, @rng = mean, sd, rng
        @compute_next_pair = false
      end
    
      def rand
        if (@compute_next_pair = !@compute_next_pair)
          # Compute a pair of random values with normal distribution.
          # See http://en.wikipedia.org/wiki/Box-Muller_transform
          theta = 2 * Math::PI * @rng.call
          scale = @sd * Math.sqrt(-2 * Math.log(1 - @rng.call))
          @g1 = @mean + scale * Math.sin(theta)
          @g0 = @mean + scale * Math.cos(theta)
        else
          @g1
        end
      end
    end
    

    Of course, if you really cared about speed, you should implement the Ziggurat Algorithm :).

    0 讨论(0)
提交回复
热议问题