Mailing List Archive: 49091 messages
  • Home
  • Script library
  • AltME Archive
  • Mailing list
  • Articles Index
  • Site search
 

[REBOL] Re: Speed testing prime functions..

From: joel:neely:fedex at: 28-Nov-2001 13:16

Hi, James, (Telecommuting from home with sinus infection, but can't resist the good ol' primes... ;-) James Marsden wrote:
> Hi to all the prime lovers out there :) > > Could someone give me some feedback on the fastest way to implement prime > checks in Rebol - > > Currently I use: > > prime?: func [p /local c v][ > v: true > for c 2 (p - 1) 1 [ > if p // c = 0 [v: false break] > ] > v > ] >
A few suggestions right off (ASSUMING THAT ALL CANDIDATES ARE >= 2): 1) The local word V is superfluous, as follows: prime?: func [p /local c] [ for c 2 (p - 1) 1 [ if p // c = 0 [return false] ] true ] 2) After testing 2, there's no point in checking for any other even divisors, as follows: prime?: func [p /local c] [ if p // 2 <> 0 [ for c 3 (p - 1) 2 [ if p // c = 0 [return false] ] return true ] ] Note the trick that IF yields NONE if its condition is false. That return value counts as false for primality. 3) Consider the fact that a divisor less than the square root of a number gives a quotient that is greater than the square root. Therefore, there's no point in continuing after passing the square root of the candidate, as follows: prime?: func [p /local c] [ if p // 2 <> 0 [ c: 3 while [c * c <= p] [ if p // c = 0 [return false] c: c + 2 ] return true ] ] Hint: try a before-and-after with a larger prime, such as 1000003 to see the difference. 4) After testing 3, there's no point in checking for any other multiples of 3. This one gets a bit obscure-looking, as we don't want any superfluous division. Consider the odds: 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 ... XX XX XX XX xx where multiples of 3 are x-ed out, and notice that we can step from 5 alternately by 2 and 4 to get the ones that are left. prime?: func [p /local c s] [ if p // 2 <> 0 [ if p = 3 [return true] ;; below only works for >= 5 if p // 3 <> 0 [ c: 5 s: 4 while [c * c <= p] [ if p // c = 0 [return false] c: c + s: 6 - s ] return true ] ] ] Of course, the more we hack up the function for these kinds of optimizations, the larger our candidate has to be to provide a real payback on the bulkier code. One last hack (left as an exercise for the reader... ;-) is to save all primes previously found, and use only known primes as trial divisors. Of course the candidate list must be extended with new trial divisors whenever it is not long enough, but only saving the prime ones (hint: recursion). This *OBVIOUSLY* requires that the function be used many times within a single session to pay off the setup costs. HTH! -jn- -- ; sub REBOL {}; sub head ($) {@_[0]} REBOL [] # despam: func [e] [replace replace/all e ":" "." "#" "@"] ; sub despam {my ($e) = @_; $e =~ tr/:#/.@/; return "\n$e"} print head reverse despam "moc:xedef#yleen:leoj" ;