First random number after setSeed in Java always similar

后端 未结 3 876
无人共我
无人共我 2020-12-29 19:05

To give some context, I have been writing a basic Perlin noise implementation in Java, and when it came to implementing seeding, I had encountered a bug that I couldn\'t exp

3条回答
  •  小鲜肉
    小鲜肉 (楼主)
    2020-12-29 19:49

    Move your setSeed out of the loop. Java's PRNG is a linear congruential generator, so seeding it with sequential values is guaranteed to give results that are correlated across iterations of the loop.

    ADDENDUM

    I dashed that off before running out the door to a meeting, and now have time to illustrate what I was saying above.

    I've written a little Ruby script which implements Schrage's portable prime modulus multiplicative linear congruential generator. I instantiate two copies of the LCG, both seeded with a value of 1. However, in each iteration of the output loop I reseed the second one based on the loop index. Here's the code:

    # Implementation of a Linear Congruential Generator (LCG)
    class LCG
      attr_reader :state
      M = (1 << 31) - 1    # Modulus = 2**31 - 1, which is prime
    
      # constructor requires setting a seed value to use as initial state
      def initialize(seed)
        reseed(seed)
      end
    
      # users can explicitly reset the seed.
      def reseed(seed)
        @state = seed.to_i
      end
    
      # Schrage's portable prime modulus multiplicative LCG
      def value
        @state = 16807 * @state % M
        # return the generated integer value AND its U(0,1) mapping as an array
        [@state, @state.to_f / M]
      end
    end
    
    if __FILE__ == $0
      # create two instances of LCG, both initially seeded with 1
      mylcg1 = LCG.new(1)
      mylcg2 = LCG.new(1)
      puts "   default progression     manual reseeding"
      10.times do |n|
        mylcg2.reseed(1 + n)  # explicitly reseed 2nd LCG based on loop index
        printf "%d %11d %f %11d %f\n", n, *mylcg1.value, *mylcg2.value
      end
    end
    

    and here's the output it produces:

       default progression     manual reseeding
    0       16807 0.000008       16807 0.000008
    1   282475249 0.131538       33614 0.000016
    2  1622650073 0.755605       50421 0.000023
    3   984943658 0.458650       67228 0.000031
    4  1144108930 0.532767       84035 0.000039
    5   470211272 0.218959      100842 0.000047
    6   101027544 0.047045      117649 0.000055
    7  1457850878 0.678865      134456 0.000063
    8  1458777923 0.679296      151263 0.000070
    9  2007237709 0.934693      168070 0.000078
    

    The columns are iteration number followed by the underlying integer generated by the LCG and the result when scaled to the range (0,1). The left set of columns show the natural progression of the LCG when allowed to proceed on its own, while the right set show what happens when you reseed on each iteration.

提交回复
热议问题