note
	description: "Summary description for {INTEGER_X_RANDOM}."
	author: "Colin LeMahieu"
	date: "$Date: 2011-11-11 18:13:16 +0100 (ven., 11 nov. 2011) $"
	revision: "$Revision: 87787 $"
	quote: "Letting lawyers make laws is like letting doctors make diseases. - Anonymous"

deferred class
	INTEGER_X_RANDOM

inherit
	INTEGER_X_FACILITIES
	LIMB_MANIPULATION
	SPECIAL_COMPARISON
	SPECIAL_ARITHMETIC
	SPECIAL_UTILITY

feature

	urandomb (target: READABLE_INTEGER_X; state: RANDOM_NUMBER_GENERATOR; nbits: INTEGER)
			-- Generate a uniformly distributed random integer in the range 0 to 2^`n'-1, inclusive.
			-- `state' must be initialized by calling one of the randinit functions before invoking this function.
		local
			size: INTEGER_32
		do
			size := bits_to_limbs (nbits)
			target.resize (size)
			state.randget (target.item, 0, nbits)
			size := normalize (target.item, 0, size)
			target.count := size
		ensure
			target.bits <= nbits
		end

	urandomm (target: READABLE_INTEGER_X; state: RANDOM_NUMBER_GENERATOR; n: READABLE_INTEGER_X)
			-- Generate a uniform random integer in the range 0 to n-1, inclusive.
			-- `state' must be initialized by calling one of the randinit functions before invoking this function.
		local
			rp: SPECIAL [NATURAL_32]
			rp_offset: INTEGER
			np: SPECIAL [NATURAL_32]
			np_offset: INTEGER
			nlast: INTEGER
			nbits: INTEGER
			size: INTEGER
			count: INTEGER
			pow2: BOOLEAN
			cmp_l: INTEGER
			overlap: BOOLEAN
			junk: NATURAL_32
			carry: CELL [NATURAL_32]
		do
			create carry.put (0)
			size := n.count.abs
			if size = 0 then
				(create {DIVIDE_BY_ZERO}).raise
			end
			np := n.item
			nlast := size - 1
			pow2 := pow2_p (n.item [nlast])
			if pow2 then
				from
					np := n.item
				until
					not pow2 or np_offset >= nlast
				loop
					if np [np_offset] /= 0 then
						pow2 := False
					end
					np_offset := np_offset + 1
				end
			end
			count := leading_zeros (np [nlast])
			nbits := size * limb_bits - (count) - pow2.to_integer
			if nbits = 0 then
				target.count := 0
			else
				np := n.item
				np_offset := 0
				rp := target.item
				rp_offset := 0
				if np = rp then
					overlap := True
					create np.make_filled (0, size)
					np.copy_data (n.item, 0, 0, size)
				end
				target.resize (size)
				rp := target.item
				rp [rp_offset + size - 1] := 0
				count := 80
				from
					cmp_l := 0
				until
					cmp_l < 0 or count = 0
				loop
					state.randget (rp, rp_offset, nbits)
					cmp_l := cmp (rp, rp_offset, np, np_offset, size)
					count := count - 1
				end
				if count = 0 then
					sub_n (rp, rp_offset, rp, rp_offset, np, np_offset, size, carry)
					junk := carry.item
				end
				size := normalize (rp, rp_offset, size)
				target.count := size
			end
		end
end
