note
	description: "[
				Pseudo-random number sequence, linear congruential method
				
				This class is adapted from work in "Discrete-Event System Simulation"
				by Jerry Banks & John S. Carson, II
				Prentice-Hall International Series in
				Industrial and Systems Engineering 1984
				Example 7.12 p 266 which is from
				IMSL Scientific Subroutine Package [1978],
				written in Fortran for IBM 360/370 computers.
		
	]"
	library: "Free implementation of ELKS library"
	status: "See notice at end of class."
	legal: "See notice at end of class."
	names: random
	date: "$Date: 2018-11-14 14:55:55 +0000 (Wed, 14 Nov 2018) $"
	revision: "$Revision: 102462 $"

class 
	RANDOM

inherit
	COUNTABLE_SEQUENCE [INTEGER_32]
		redefine
			has
		end

	DOUBLE_MATH
		export
			{NONE} all
		end

	ITERATION_CURSOR [INTEGER_32]

create 
	make,
	set_seed

feature -- Initialization

	make
			-- Initialize structure using a default seed.
		do
			set_seed (Default_seed)
			start
		ensure
			seed_set: seed = Default_seed
		end

	set_seed (s: INTEGER_32)
			-- Initialize sequence using s as the seed.
		require
			non_negative: s >= 0
		do
			seed := s
			last_result := seed
			last_item := 0
		ensure
			seed_set: seed = s
		end
	
feature -- Access

	Default_seed: INTEGER_32
			-- Default value 123,457;
			-- may be redefined for a new generator.
		once
			Result := 123457
		end

	Modulus: INTEGER_32
			-- Default value 2^31 -1 = 2,147,483,647;
			-- may be redefined for a new generator.
		once
			Result := 2147483647
		end

	Multiplier: INTEGER_32
			-- Default value 7^5 = 16,807;
			-- may be redefined for a new generator.
		once
			Result := 16807
		end

	Increment: INTEGER_32
			-- Default value 0;
			-- may be redefined for a new generator.
		once
			Result := 0
		end

	seed: INTEGER_32
			-- Seed for sequence.

	next_random (n: INTEGER_32): INTEGER_32
			-- Next random number after n
			-- in pseudo-random order
		require
			in_range: (n < Modulus) and (n >= 0)
		do
			Result := randomize (n)
		ensure
			in_range: (Result < Modulus) and (Result >= 0)
		end

	has (n: INTEGER_32): BOOLEAN
			-- Will n be part of the random number sequence?
		do
			Result := (n < Modulus) and (n >= 0)
		ensure then
			only_: Result = (n < Modulus and n >= 0)
		end

	i_th (i: INTEGER_32): INTEGER_32
			-- The i-th random number
		local
			count: INTEGER_32
		do
			if i >= last_item then
				Result := last_result
				count := last_item
			else
				Result := seed
			end
			from
			until
				count = i
			loop
				Result := randomize (Result)
				count := count + 1
			end
			last_result := Result
			last_item := i
		ensure then
			in_range: (Result < Modulus) and (Result >= 0)
		end

	real_item: REAL_32
			-- The current random number as a real between 0 and 1
		do
			Result := item.to_real / Modulus.to_real
		end

	double_item: REAL_64
			-- The current random number as a double between 0 and 1
		do
			Result := item.to_double / Dmod
		end

	real_i_th (i: INTEGER_32): REAL_32
			-- The i-th random number as a real between 0 and 1
		require
			positive_argument: i > 0
		do
			Result := i_th (i).to_real / Modulus.to_real
		end

	double_i_th (i: INTEGER_32): REAL_64
			-- The i-th random number as a double between 0 and 1
		require
			positive_argument: i > 0
		do
			Result := i_th (i).to_double / Dmod
		end
	
feature -- Iteration

	new_cursor: RANDOM
			-- Fresh cursor associated with current structure
		do
			create Result.set_seed (seed);
			Result.start
		end
	
feature {NONE} -- Implementation

	randomize (xn: INTEGER_32): INTEGER_32
			-- Next item
		do
			Result := double_mod (Dmul * xn.to_double + Dinc, Dmod).truncated_to_integer
		end

	double_mod (x, m: REAL_64): REAL_64
			-- x modulo m
		do
			Result := x - (floor (x / m) * m)
		end

	last_item: INTEGER_32
			-- Last item requested

	last_result: INTEGER_32
			-- Value from last call to item

	Dmod: REAL_64
			-- Double value for modulus
		once
			Result := Modulus.to_double
		end

	Dmul: REAL_64
			-- Double value for multiplier
		once
			Result := Multiplier.to_double
		end

	Dinc: REAL_64
			-- Double value for increment
		once
			Result := Increment.to_double
		end
	
invariant
	non_negative_seed: seed >= 0
	non_negative_increment: Increment >= 0
	positive_multiplier: Multiplier > 0
	modulus_constraint: Modulus > 1

note
	copyright: "Copyright (c) 1984-2018, Eiffel Software and others"
	license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
	source: "[
		Eiffel Software
		5949 Hollister Ave., Goleta, CA 93117 USA
		Telephone 805-685-1006, Fax 805-685-6869
		Website http://www.eiffel.com
		Customer support http://support.eiffel.com
	]"

end -- class RANDOM

Generated by ISE EiffelStudio