note
	description: "Prime number properties"
	library: "Free implementation of ELKS library"
	status: "See notice at end of class."
	legal: "See notice at end of class."
	names: primes
	date: "$Date: 2018-10-03 13:41:17 +0000 (Wed, 03 Oct 2018) $"
	revision: "$Revision: 102260 $"

class 
	PRIMES

inherit
	COUNTABLE_SEQUENCE [INTEGER_32]
		rename
			has as is_prime
		redefine
			is_prime
		end

	ITERATION_CURSOR [INTEGER_32]

create 
	default_create

feature -- Access

	Smallest_prime: INTEGER_32 = 2

	Smallest_odd_prime: INTEGER_32 = 3

	higher_prime (n: INTEGER_32): INTEGER_32
			-- Lowest prime greater than or equal to n
		do
			if n <= Smallest_prime then
				Result := Smallest_prime
			else
				check
						n > Smallest_prime
				end
				from
					if n \\ Smallest_prime = 0 then
						Result := n + 1
					else
						Result := n
					end
				until
					is_prime (Result)
				loop
					Result := Result + Smallest_prime
				end
			end
		ensure
			instance_free: class
		end

	lower_prime (n: INTEGER_32): INTEGER_32
			-- Greatest prime lower than or equal to n
		require
			argument_big_enough: n >= Smallest_prime
		do
			if n = Smallest_prime then
				Result := Smallest_prime
			else
				from
					if n \\ Smallest_prime = 0 then
						Result := n - 1
					else
						Result := n
					end
				until
					is_prime (Result)
				loop
					Result := Result - Smallest_prime
				end
			end
		ensure
			instance_free: class
		end

	all_lower_primes (n: INTEGER_32): ARRAY [BOOLEAN]
			-- Array of n boolean values, where the
			-- value at index i is true if and only if
			-- i is prime.
		local
			i, j: INTEGER_32
		do
			from
				create Result.make_filled (False, 1, n)
				i := 3
			until
				i > n
			loop
				Result.put (True, i)
				i := i + Smallest_prime
			end
			if n >= Smallest_prime then
				Result.put (True, Smallest_prime)
			end
			from
				i := Smallest_odd_prime
			until
				i * i > n
			loop
				if Result.item (i) then
					from
						j := i * i
					until
						j > n
					loop
						Result.put (False, j)
						j := j + Smallest_prime * i
					end
				end
				i := i + Smallest_prime
			end
		ensure
			instance_free: class
		end

	is_prime (n: INTEGER_32): BOOLEAN
			-- Is n a prime number?
		local
			divisor: INTEGER_32
		do
			if n <= 1 then
				Result := False
			elseif n = Smallest_prime then
				Result := True
			elseif n \\ Smallest_prime /= 0 then
				from
					divisor := Smallest_odd_prime
				until
					(n \\ divisor = 0) or else (divisor * divisor >= n)
				loop
					divisor := divisor + Smallest_prime
				end
				if divisor * divisor > n then
					Result := True
				end
			end
		ensure then
			instance_free: class
		end

	i_th (i: INTEGER_32): INTEGER_32
			-- The i-th prime number
		local
			candidates: ARRAY [BOOLEAN]
			found: INTEGER_32
			l_values: like Internal_precomputed_primes
		do
			l_values := Internal_precomputed_primes
			if l_values /= Void and then i <= l_values.upper then
				Result := l_values.item (i)
			else
				candidates := all_lower_primes (approximated_i_th (i))
				from
					Result := 2
					found := 1
				variant
						i * i - Result
				until
					found = i
				loop
					Result := Result + 1
					if candidates.item (Result) then
						found := found + 1
					end
				end
			end
		ensure then
			instance_free: class
		end
	
feature -- Iteration

	new_cursor: PRIMES
			-- Fresh cursor associated with current structure
		do
			create Result;
			Result.start
		ensure then
			instance_free: class
		end
	
feature {NONE} -- Implementation

	Precomputed_primes_count: INTEGER_32 = 200
			-- Number of precomputed prime numbers.

	Internal_precomputed_primes: ARRAY [INTEGER_32]
			-- First Precomputed_primes_count prime numbers.
		local
			candidates: ARRAY [BOOLEAN]
			i, pos: INTEGER_32
		once
			from
				candidates := all_lower_primes (approximated_i_th (Precomputed_primes_count))
				create Result.make_filled (0, 1, Precomputed_primes_count)
				pos := 1
				i := 1
			until
				pos > Precomputed_primes_count
			loop
				if candidates.item (i) then
					Result.put (i, pos)
					pos := pos + 1
				end
				i := i + 1
			end
		ensure
			instance_free: class
			internal_precomputed_primes_not_void: Result /= Void
			lower_valid: Result.lower = 1
			upper_valid: Result.upper = Precomputed_primes_count
		end

	approximated_i_th (n: INTEGER_32): INTEGER_32
			-- Approximation of n-th prime number.
		require
			n_positive: n > 0
		local
			l_double_math: DOUBLE_MATH
			ln_n, ln_ln_n: REAL_64
		do
			if n >= 13 then
				create l_double_math
				ln_n := l_double_math.log (n.to_double)
				ln_ln_n := l_double_math.log (ln_n)
				Result := (n.to_double * (ln_n + ln_ln_n - 1.to_double + 1.8 * ln_ln_n / ln_n)).truncated_to_integer
			else
				Result := n * n
			end
		ensure
			instance_free: class
			approximation_valid: i_th (n) <= Result
		end
	
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 PRIMES

Generated by ISE EiffelStudio