Name | Executed | Routines | % | Executed | Lines | % | Unexecuted |
/home/matt/eu/rds/include/std/primes.e | 3 | 3 | 100.00% | 62 | 65 | 95.38% | 3 |
Routine | Executed | Lines | Unexecuted | |
calc_primes() | 40 | 42 | 95.24% | 2 |
prime_list() | 8 | 9 | 88.89% | 1 |
next_prime() | 13 | 13 | 100.00% | 0 |
# | Executed | |
1 | -- (c) Copyright - See License.txt | |
2 | -- | |
3 | namespace primes | |
4 | ||
5 | --**** | |
6 | -- == Prime Numbers | |
7 | -- **Page Contents** | |
8 | -- | |
9 | -- < | |
10 | ||
11 | include std/search.e | |
12 | ||
13 | 21 | sequence list_of_primes = {2,3} -- Initial seedings. |
14 | ||
15 | --**** | |
16 | -- === Routines | |
17 | -- | |
18 | ||
19 | --** | |
20 | -- Returns all the prime numbers below some threshold, with a cap on computation time. | |
21 | -- | |
22 | -- Parameters: | |
23 | -- # ##max_p## : an integer, the last prime returned is the next prime after or on this value. | |
24 | -- # ##time_out_p## : an atom, the maximum number of seconds that this function can run for. | |
25 | -- The default is 10 (ten) seconds. | |
26 | -- | |
27 | -- Returns: | |
28 | -- A **sequence**, made of prime numbers in increasing order. The last value is | |
29 | -- the next prime number that falls on or after the value of ##max_p##. | |
30 | -- | |
31 | -- Comments: | |
32 | -- * The returned sequence contains all the prime numbers less than its last element. | |
33 | -- | |
34 | -- * If the function times out, it may not hold all primes below ##max_p##, | |
35 | -- but only the largest ones will be absent. If the last element returned is | |
36 | -- less than ##max_p## then the function timed out. | |
37 | -- | |
38 | -- * To disable the timeout, simply give it a negative value. | |
39 | -- | |
40 | -- Example 1: | |
41 | -- | |
42 | -- ? calc_primes(1000, 5) | |
43 | -- -- On a very slow computer, you may only get all primes up to say 719. | |
44 | -- -- On a faster computer, the last element printed out will be 997. | |
45 | -- -- This call will never take longer than 5 seconds. | |
46 | -- | |
47 | -- | |
48 | -- See Also: | |
49 | -- [[:next_prime]] [[:prime_list]] | |
50 | 21 | |
51 | sequence result_ | |
52 | integer candidate_ | |
53 | integer pos_ | |
54 | atom time_out_ | |
55 | integer maxp_ | |
56 | integer maxf_ | |
57 | integer maxf_idx | |
58 | integer next_trigger | |
59 | ||
60 | -- First we check to see if we have already got the requested value. | |
61 | 21 | if max_p <= list_of_primes[$] then |
62 | 1 | pos_ = binary_search(max_p, list_of_primes) |
63 | 1 | if pos_ < 0 then |
64 | 0 | pos_ = (-pos_) + 1 |
65 | end if | |
66 | -- Already got it. | |
67 | 1 | return list_of_primes[1..pos_] |
68 | end if | |
69 | ||
70 | -- Record the largest known prime (so far) and its index. | |
71 | 20 | pos_ = length(list_of_primes) |
72 | 20 | candidate_ = list_of_primes[$] |
73 | ||
74 | -- Calculate the largest possible factor for the largest known prime, and its index. | |
75 | 20 | maxf_ = floor(power(candidate_, 0.5)) |
76 | 20 | maxf_idx = binary_search(maxf_, list_of_primes) |
77 | 20 | if maxf_idx < 0 then |
78 | 17 | maxf_idx = (-maxf_idx) |
79 | 17 | maxf_ = list_of_primes[maxf_idx] |
80 | end if | |
81 | -- Calculate what the trigger is for when we need to go to the next maximum factor value. | |
82 | 20 | next_trigger = list_of_primes[maxf_idx+1] |
83 | 20 | next_trigger *= next_trigger |
84 | ||
85 | -- Pre-allocate space for the new values. This allocates more than we will | |
86 | -- need so the return value takes a slice up to the last stored prime. | |
87 | 20 | result_ = list_of_primes & repeat(0, floor(max_p / 3.5) - length(list_of_primes)) |
88 | ||
89 | -- Calculate when we must stop running. A negative value is really equivalent | |
90 | -- to a little over three years from now. | |
91 | 20 | if time_limit_p < 0 then |
92 | 0 | time_out_ = time() + 100_000_000 |
93 | else | |
94 | 20 | time_out_ = time() + time_limit_p |
95 | end if | |
96 | ||
97 | 20 | while time_out_ >= time() label "MW" do |
98 | -- As this could run for a significant amount of time, | |
99 | -- yield to any other tasks that might be ready. | |
100 | 98758 | task_yield() |
101 | ||
102 | -- Get the next candidate value to examine. | |
103 | 98758 | candidate_ += 2 |
104 | ||
105 | -- If this is at or past the factor trigger point | |
106 | -- pluck out the next maximum factor and calculate | |
107 | -- the next trigger. | |
108 | 98758 | if candidate_ >= next_trigger then |
109 | 117 | maxf_idx += 1 |
110 | 117 | maxf_ = result_[maxf_idx] |
111 | 117 | next_trigger = result_[maxf_idx+1] |
112 | 117 | next_trigger *= next_trigger |
113 | end if | |
114 | ||
115 | -- Examine the candidate. | |
116 | 98758 | for i = 2 to pos_ do |
117 | -- If this potential factor is larger than the 'maximum' factor | |
118 | -- then we don't need to examine any more. The candidate is a prime. | |
119 | 1463812 | maxp_ = result_[i] |
120 | 1463812 | if maxp_ > maxf_ then |
121 | 18393 | exit |
122 | end if | |
123 | ||
124 | -- If it is divisible by any known prime then | |
125 | -- we go get another candidate value. | |
126 | 1445419 | if remainder(candidate_, maxp_) = 0 then |
127 | 80365 | continue "MW" |
128 | end if | |
129 | 1365054 | end for |
130 | ||
131 | -- Store it in the result, making sure that the result sequence is larger enough. | |
132 | 18393 | pos_ += 1 |
133 | 18393 | if pos_ >= length(result_) then |
134 | 14 | result_ &= repeat(0, 1000) |
135 | end if | |
136 | 18393 | result_[pos_] = candidate_ |
137 | ||
138 | -- If the value just stored is larger or equal to the requested value | |
139 | -- then we can stop running. | |
140 | 18393 | if candidate_ >= max_p then |
141 | 17 | exit |
142 | end if | |
143 | 18376 | end while |
144 | ||
145 | 20 | return result_[1..pos_] |
146 | end function | |
147 | ||
148 | ||
149 | --** | |
150 | -- Return the next prime number on or after the supplied number | |
151 | -- | |
152 | -- Parameters: | |
153 | -- # ##n## : an integer, the starting point for the search | |
154 | -- # ##fail_signal_p## : an integer, used to signal error. Defaults to -1. | |
155 | -- | |
156 | -- Returns: | |
157 | -- An **integer**, which is prime only if it took less than 1 second | |
158 | -- to determine the next prime greater or equal to ##n##. | |
159 | -- | |
160 | -- Comments: | |
161 | -- The default value of -1 will alert you about an invalid returned value, | |
162 | -- since a prime not less than ##n## is expected. However, you can pass | |
163 | -- another value for this parameter. | |
164 | -- | |
165 | -- Example 1: | |
166 | -- | |
167 | -- ? next_prime(997) | |
168 | -- -- On a very slow computer, you might get -997, but 1003 is expected. | |
169 | -- | |
170 | -- | |
171 | -- See Also: | |
172 | -- [[:calc_primes]] | |
173 | ||
174 | 74 | |
175 | integer i | |
176 | ||
177 | 74 | if n < 0 then |
178 | 1 | return fail_signal_p |
179 | end if | |
180 | 73 | if list_of_primes[$] < n then |
181 | 19 | list_of_primes = calc_primes(n,time_out_p) |
182 | end if | |
183 | 73 | if n > list_of_primes[$] then |
184 | 3 | return fail_signal_p |
185 | end if | |
186 | -- Assumes that most searches will be less than about 1000 | |
187 | 70 | if n < 1009 and 1009 <= list_of_primes[$] then |
188 | 17 | i = binary_search(n, list_of_primes, ,169) |
189 | else | |
190 | 53 | i = binary_search(n, list_of_primes) |
191 | end if | |
192 | 70 | if i < 0 then |
193 | 19 | i = (-i) |
194 | end if | |
195 | 70 | return list_of_primes[i] |
196 | ||
197 | end function | |
198 | ||
199 | --** | |
200 | -- Returns a list of prime numbers. | |
201 | -- | |
202 | -- Parameters: | |
203 | -- # ##top_prime_p## : The list will end with the prime less than or equal | |
204 | -- to this value. If this is zero, the current list calculated primes | |
205 | -- is returned. | |
206 | -- | |
207 | -- Returns: | |
208 | -- An **sequence**, a list of prime numbers from 2 to ##top_prime_p## | |
209 | -- | |
210 | -- Example 1: | |
211 | -- | |
212 | -- sequence pList = prime_list(1000) | |
213 | -- -- pList will now contain all the primes from 2 up to the largest less than or | |
214 | -- -- equal to 1000. | |
215 | -- | |
216 | -- | |
217 | -- See Also: | |
218 | -- [[:calc_primes]], [[:next_prime]] | |
219 | -- | |
220 | 9 | |
221 | integer index_ | |
222 | ||
223 | 9 | if top_prime_p <= 0 then |
224 | 8 | return list_of_primes |
225 | end if | |
226 | ||
227 | 1 | if list_of_primes[$] < top_prime_p then |
228 | 1 | list_of_primes = calc_primes(top_prime_p, 5) |
229 | end if | |
230 | ||
231 | 1 | index_ = binary_search(top_prime_p, list_of_primes) |
232 | 1 | if index_ < 0 then |
233 | 0 | index_ = - index_ |
234 | end if | |
235 | ||
236 | 1 | return list_of_primes[1 .. index_] |
237 | end function |