# mruby-random mruby-random is an mrbgem that provides pseudo-random number generation facilities for mruby. ## Features - Provides `Kernel#rand` method for generating pseudo-random numbers. - Supports generating random numbers within a specific range. - Allows setting a seed for reproducible random number sequences using `Kernel#srand`. ## Global Random Number Generation ### Generating a random number To generate a pseudo-random floating-point number between 0.0 (inclusive) and 1.0 (exclusive): ```ruby r = rand p r # => 0.31415926535 ``` To generate a pseudo-random integer number between 0 (inclusive) and a given maximum integer (exclusive): ```ruby r = rand(100) p r # => 42 ``` To generate a pseudo-random integer within a given `Range`: ```ruby r = rand(10..20) # or rand(10...20) p r # => 15 (e.g., between 10 and 20, or 10 and 19) ``` ### Seeding the random number generator To initialize the pseudo-random number generator with a specific seed: ```ruby srand(12345) p rand(100) # => 81 p rand(100) # => 81 (if you re-seed with srand(12345) again) # Using the same seed will produce the same sequence of random numbers srand(12345) p rand(100) # => 81 srand(12345) p rand(100) # => 81 ``` ## The `Random` Class Besides the global `Kernel#rand` and `Kernel#srand` methods, `mruby-random` also provides a `Random` class for managing separate random number generators. ### Creating an Instance You can create a new instance of the `Random` class with a system-generated seed: ```ruby rng = Random.new p rng.rand(100) ``` Or you can provide a specific seed: ```ruby rng = Random.new(12345) p rng.rand(100) # => 81 ``` ### Instance Methods #### `rand` The `rand` instance method behaves similarly to `Kernel#rand`, but operates on the specific `Random` instance. - Called with no arguments, it returns a pseudo-random floating-point number between 0.0 (inclusive) and 1.0 (exclusive). ```ruby rng = Random.new p rng.rand # => 0.123456789 ``` - Called with an integer `max` argument, it returns a pseudo-random integer between 0 (inclusive) and `max` (exclusive). ```ruby rng = Random.new p rng.rand(50) # => 23 ``` - Called with a `Range` argument (`min..max` or `min...max`), it returns a pseudo-random integer within that range (inclusive of `min`, and inclusive or exclusive of `max` depending on the range type). ```ruby rng = Random.new p rng.rand(10..20) # => 15 (between 10 and 20, inclusive) p rng.rand(10...20) # => 12 (between 10 and 19, inclusive) ``` #### `srand` The `srand` instance method is used to seed the specific `Random` instance. It allows you to re-initialize the random number generator for that instance with a specific seed, making its sequence of generated numbers predictable. ```ruby rng = Random.new(111) p rng.rand(1000) # => 100 p rng.rand(1000) # => 283 rng.srand(111) # Re-seed the same instance p rng.rand(1000) # => 100 (sequence repeats for this instance) rng2 = Random.new(111) # A different instance with the same seed p rng2.rand(1000) # => 100 ``` It is important to note that `Random#srand` is an alias for `Random#initialize`. Re-seeding an existing `Random` object will reset its internal state. #### `bytes(n)` The `bytes` method returns a string containing `n` pseudo-random bytes. ```ruby rng = Random.new p rng.bytes(5) # => "\xAB\xCD\xEF\x12\x34" (example output) ``` ### Class Methods (Using the Default Generator) The `Random` class also provides class methods that operate on a global, default random number generator. This is the same generator used by `Kernel#rand` and `Kernel#srand`. #### `Random.rand` This method is equivalent to `Kernel.rand` (or simply `rand`). - With no arguments, returns a float between 0.0 and 1.0 (exclusive of 1.0): ```ruby p Random.rand # => 0.7654321 ``` - With an integer `max` argument, returns an integer between 0 and `max` (exclusive of `max`): ```ruby p Random.rand(10) # => 7 ``` - With a `Range` argument, returns an integer within the range: ```ruby p Random.rand(50..60) # => 53 ``` #### `Random.srand(seed)` This method is equivalent to `Kernel.srand(seed)` (or simply `srand(seed)`). It seeds the global default random number generator. ```ruby Random.srand(123) p Random.rand(100) # => 13 p rand(100) # => 80 (uses the same seeded generator) Random.srand(123) p Random.rand(100) # => 13 (sequence repeats) ``` #### `Random.bytes(n)` This method returns a string containing `n` pseudo-random bytes, generated by the global default random number generator. ```ruby p Random.bytes(3) # => "\xDE\xAD\xBE" (example output) ``` ## Array Methods `mruby-random` extends the `Array` class with methods for shuffling elements and sampling random elements. These methods can optionally accept a `Random` instance to use a specific random number generator. ### `shuffle` The `shuffle` method returns a _new_ array with the elements of the original array in a random order. ```ruby a = [1, 2, 3, 4, 5] p a.shuffle # => [3, 1, 5, 2, 4] (example output) p a # => [1, 2, 3, 4, 5] (original array is unchanged) ``` You can provide a specific `Random` instance using the `random:` keyword argument. This is useful for reproducible shuffling. ```ruby rng = Random.new(123) a = [1, 2, 3, 4, 5] p a.shuffle(random: rng) # => [1, 5, 3, 2, 4] (example output, will be consistent with seed 123) rng2 = Random.new(123) # Same seed p a.shuffle(random: rng2) # => [1, 5, 3, 2, 4] (same shuffled order) ``` ### `shuffle!` The `shuffle!` method shuffles the elements of the array in-place. It modifies the original array. ```ruby a = [1, 2, 3, 4, 5] p a.shuffle! # => [4, 2, 1, 5, 3] (example output) p a # => [4, 2, 1, 5, 3] (original array is modified) ``` Similarly to `shuffle`, you can provide a specific `Random` instance using the `random:` keyword argument. ```ruby rng = Random.new(456) a = [:a, :b, :c, :d, :e] p a.shuffle!(random: rng) # => [:c, :a, :e, :d, :b] (example output, consistent with seed 456) p a # => [:c, :a, :e, :d, :b] (original array is modified) ``` ### `sample` The `sample` method chooses one or more random elements from the array. - When called with no arguments, it returns a single random element from the array. If the array is empty, it returns `nil`. ```ruby a = ["apple", "banana", "cherry", "date"] p a.sample # => "cherry" (example output) empty_array = [] p empty_array.sample # => nil ``` - When called with an integer `n` as an argument, it returns a new array containing `n` unique random elements from the original array. If the array does not have enough unique elements, it returns all elements in a shuffled order. If the array is empty, it returns an empty array. ```ruby a = ["apple", "banana", "cherry", "date", "elderberry"] p a.sample(3) # => ["date", "apple", "banana"] (example output) p a.sample(10) # => ["banana", "elderberry", "apple", "date", "cherry"] (all elements, shuffled) empty_array = [] p empty_array.sample(3) # => [] ``` - You can provide a specific `Random` instance using the `random:` keyword argument for both forms of `sample`. ```ruby rng = Random.new(789) a = [10, 20, 30, 40, 50] p a.sample(random: rng) # => 30 (example output, consistent with seed 789) rng_b = Random.new(789) # Re-initialize with the same seed for predictable multi-sampling p a.sample(2, random: rng_b) # => [30, 50] (example output) ``` ## Algorithm The `mruby-random` mrbgem primarily utilizes the **xoshiro128++ 1.0** algorithm for pseudo-random number generation. In certain 32-bit configurations (specifically when `MRB_INT32` is defined and `MRB_64BIT` is not), a different algorithm, **XORSHIFT96**, might be employed. ## License The `mruby-random` mrbgem is released under the MIT License. See the [LICENSE](LICENSE) file for details.