LARA

;;; primes.el --- prime number support for Emacs Lisp library code
 
;; Copyright (C) 1999
;;        Free Software Foundation, Inc.
 
;; This file is part of GNU Emacs.
 
;; GNU Emacs is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.
 
;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.
 
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING.  If not, write to the
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.
 
;; Author: Nelson H. F. Beebe <beebe@math.utah.edu>
;; Maintainer: Nelson H. F. Beebe <beebe@math.utah.edu>
;; Created: 27 February 1999
;; Version: 1.00
;; Keywords: prime numbers, primality testing
 
;; This file is part of GNU Emacs.
 
;;; Commentary:
 
;; A prime number is any integer greater than one which has no exact
;; integer divisors other than one and itself.
;;
;; Prime numbers have increasingly important practical applications
;; in cryptography, and are also useful in hashing, besides being of
;; fundamental importance in number theory.
;;
;; This is a small collection of functions for:
;;
;;	* testing integers for primality,
;;	* generating nearby primes,
;;	* finding the n-th prime,
;;	* generating lists of primes in a given range,
;;	* factoring a number into a product of primes,
;;	* finding the greatest common divisor of two numbers, and
;;	* finding the least common multiple of two numbers.
;;
;; The functions provided are:
;;
;;	(gcd n m)			[cost: O((12(ln 2)/pi^2)ln n)]
;;	(lcm n m)			[cost: O((12(ln 2)/pi^2)ln n)]
;;	(next-prime n)			[cost: O(sqrt(N))]
;;	(nth-prime n)			[cost: O(N*sqrt(N))]
;;	(prev-prime n)			[cost: O(sqrt(N))]
;;	(prime-factors n)		[cost: O(N)]
;;	(prime-p n)			[cost: O(sqrt(N))]
;;	(primes-between from to)	[cost: O((to - from + 1)*sqrt(N))]
;;	(this-or-next-prime n)		[cost: O(sqrt(N))]
;;	(this-or-prev-prime n)		[cost: O(sqrt(N))]
;;
;; The modest collection of functions here is likely to grow, and
;; perhaps may even be improved algorithmically.  The core of most of
;; these functions is the primality test, (prime-p N), whose running
;; time is O(sqrt(N)), which becomes excessive for large N.  Note that
;; sqrt(N) == 2^{(lg N)/2}, where lg N, the base-2 logarithm of N, is
;; the number of bits in N.  Thus O(sqrt(N)) means O(2^(bits in N)),
;; or O(10^(digits in N)).  That is, the running time increases
;; EXPONENTIALLY in the number of digits of N.
;;
;; Because knowledge of the cost of these functions may be critical to
;; the caller, each function's documentation string ends with a
;; bracketed cost estimate as a final paragraph.
;;
;; Faster algorithms capable of dealing with larger integers are
;; known.  For example, Maple V Release 5 (1997) implements a
;; probabilistic function, isprime(n), that is
;;
;;	``very probably'' prime - see Knuth ``The art of computer
;;	programming'', Vol 2, 2nd edition, Section 4.5.4, Algorithm P
;;	for a reference and H. Reisel, ``Prime numbers and computer
;;	methods for factorization''. No counter example is known and
;;	it has been conjectured that such a counter example must be
;;	hundreds of digits long.
;;
;; Robert Sedgewick also promises a fast prime test in Part 5 of his
;; book ``Algorithms in C'', not yet published at the time of writing
;; this in March 1999.
;;
;; Three algorithms for probabilistic primality tests for large
;; numbers are discussed in Bruce Schneier, ``Applied Cryptography'',
;; (Wiley, 1994, ISBN 0-471-59756-2), pp. 213--216.
;;
;; Other key references, described in more detail in the Emacs Lisp
;; Manual chapter for this library, include
;;
;;	Leonard M. Adleman, Algorithmic Number Theory --- The
;;	Complexity Contribution, Proc. 35th IEEE Symposium on the
;;	Foundations of Computer Science (FOCS'94), Shafi Goldwasser
;;	(Ed.), IEEE Computer Society Press (Silver Spring, MD),
;;	pp. 88--113, 1994, ISBN 0-8186-6582-3, ISSN 0272-5428.
;;
;;	Eric Bach and Jeffrey Shallit, Algorithmic Number Theory.
;;	Volume I: Efficient Algorithms, MIT Press (Cambridge, MA),
;;	1996, ISBN 0-262-02405-5.
;;
;;	Ronald L. Graham, Donald E. Knuth and Oren Patashnik, Concrete
;;	Mathematics, Addison-Wesley, Reading, MA, USA, 1989, ISBN
;;	0-201-14236-8.
;;
;;	Donald E. Knuth, Fundamental algorithms, The Art of Computer
;;	Programming, Volume 1, Third edition, Addison-Wesley (Reading,
;;	MA), 1997, ISBN 0-201-89683-4.
;;
;;	Donald E. Knuth, Seminumerical algorithms, The Art of Computer
;;	Programming, Volume 2, Third edition, Addison-Wesley (Reading,
;;	MA), 1997, ISBN 0-201-89684-2.
;;
;;	Steven S. Skiena, The Algorithm Design Manual, Springer-Verlag
;;	(New York, NY), 1998, ISBN 0-387-94860-0.
;;
;;; Code:
 
(provide 'primes)
 
 
(defconst primes-version "1.00"
  "Version number of primes library.")
 
 
(defconst primes-date "[27-Feb-1999]"
  "Revision date of primes library.")
 
 
(defun gcd (m n)
  "Return the Greatest Common Divisor of integers M and N, or nil if
they are invalid.
 
\[cost: O((12(ln 2)/pi^2)ln max(M,N)) == O(0.8427659... max(M,N))]"
  ;; For details of this 2300-year algorithm due to Euclid, see, e.g.
  ;; Ronald L. Graham, Donald E. Knuth and Oren Patashnik, ``Concrete
  ;; Mathematics'' (Addison-Wesley, Reading, MA, USA, 1989, ISBN
  ;; 0-201-14236-8), pp. 103--104.
  ;;
  ;; The complexity analysis is surprisingly difficult; see Donald
  ;; E. Knuth, ``Seminumerical algorithms, The Art of Computer
  ;; Programming, Volume 2'', third edition (Addison-Wesley, Reading,
  ;; MA, USA, 1997, ISBN 0-201-89684-2), pp. 356--373.
 
  (if (and (integerp m) (integerp n))	; check for integer args
      (progn
	(setq m (abs m))		; argument sign does not matter for gcd, so
	(setq n (abs n))		; force positive for the algorithm below
	(cond
	 ((and (= m 0) (= n 0)) 0)	; gcd(0,0) ==> 0 by definition, for convenience
	 ((and (= m 0) (> n 0)) n)	; gcd(0,n) ==> n
	 ((and (> m 0) (= n 0)) m)	; gcd(m,0) ==> m
	 ((and (> m n) (> n 0)) (gcd n m)) ; reinvoke with reversed arguments
	 (t (gcd (% n m) m))))		; else reduce recursively
    nil))				; non-integer args: invalid
 
 
(defun lcm (m n)
  "Return the Least Common Multiple of integers M and N, or nil if
they are invalid, or the result is not representable (e.g., the
product M*N overflows).
 
\[cost: O((12(ln 2)/pi^2)ln max(M,N)) == O(0.8427659... max(M,N))]"
  (cond
   ((and (integerp m) (integerp n))	; check for integer args
    (let ((mn) (the-gcd) (the-lcm))
      (if (or (= m 0) (= n 0))		; fast special case: lcm(0,anything) == 0
	  0
	;; else compute lcm from (m * n) / gcd(m,n)
	;;
	;; Problem: GNU Emacs Lisp integer multiply does not detect or
	;; trap overflow, which is a real possibility here, and it lacks
	;; a double-length integer type to represent the product m * n.
	;; Since the lcm may still be representable, we do the
	;; intermediate computation in (double-precision)
	;; floating-point, which is still not quite large enough to
	;; represent all products of Emacs 28-bit integers stored in
	;; 32-bit words, then convert back to integer results.  The
	;; floor function will signal an error if the result is not
	;; representable.  To try to avoid that, we first check that the
	;; equality gcd * lcm = m * n is satisfied, and only if it is,
	;; do we invoke floor.
	;;
	;; TO DO: find better algorithm without these undesirable
	;; properties.
	(setq m (abs m))		; argument sign does not matter for lcm, so
	(setq n (abs n))		; force positive for the algorithm below
	(setq the-gcd (gcd m n))
	(setq mn (* (float m) (float n)))
	(setq the-lcm (/ mn the-gcd))
	(if (= (* the-gcd the-lcm) mn)	; then got correct answer
	    (floor the-lcm)
	  nil))))			; else out-of-range or invalid
    (t nil)))				; non-integer args: invalid
 
 
(defun prime-factors (n)
  "Return a list of prime factors of N.
 
If N is prime, there are no factors, except the trivial one of N itself,
so the return value is the list (N).  Thus, if (length (prime-factors N))
is 1, N is prime.
 
Otherwise, if N is not an integer greater than 1, the return value is
nil, equivalent to an empty list.
 
\[cost: O(N)]"
  (interactive)
  (let ((result-list nil)
	(n-original n))
    (if (and (integerp n) (> n 1))
	(let ((limit (/ n 2))
	      (divisor 2))
	  (while (<= divisor limit)
	    ;; To correctly handle factors of multiplicity > 1, we must
	    ;; be careful to advance the divisor only when it is not a
	    ;; factor!  When n is replaced by n/divisor, we can reset
	    ;; limit, but only to n/2, not to n.  Consider
	    ;; (prime-factors 15): the first factor found is 3, which
	    ;; reduces n to 5, which will be the next prime factor
	    ;; found, but would be lost if we reset limit to 5/2 == 2.
	    ;;
	    ;; If this divisor is rejected, as long as it is greater
	    ;; than 2, and thus, odd, we can step it by 2, halving the
	    ;; number of loop iterations.
	    (if (= 0 (% n divisor))
		(setq n (/ n divisor)
		      limit n
		      result-list (append result-list (list divisor)))
	      (if (= divisor 2)
		  (setq divisor 3)
		(setq divisor (+ divisor 2)))))
	  ;; If we end the while loop with an empty result-list, then
	  ;; the input N was prime, so set result-list to a one-element
	  ;; list:
	  (if (null result-list)
	      (setq result-list (list n-original)))))
    result-list))
 
 
(defun prime-p (n)
  "Return N if it is a prime number, else nil.
 
Because Emacs integers are usually more limited in size than the host
word size would suggest, e.g.,
 
	\[-2^{27}, 2^{27} - 1] == [-134217728, 134217727]
 
on a 32-bit machine, avoid passing excessively large integers to this
function, otherwise you may experience this failure:
 
	\(next-prime 134217689)
	Arithmetic domain error: \"sqrt\", -134217728.0
 
While you may be able to use larger integers on some 64-bit machines,
the required run time for this function is then likely to be excessive.
 
\[cost: O(sqrt(N))]"
  (interactive)
  (if (integerp n)
      (cond ((< n 2) nil)		;there are no primes below 2
	    ((= n 2) 2)			;special case for the only even prime
	    ((= 0 (% n 2)) nil)		;there are no other even primes
	    (t (catch 'RESULT		;else we have a positive odd candidate value
		 (let ((limit (floor (sqrt n)))
		       (divisor 2))
		   (while (<= divisor limit)
		     (if (= 0 (% n divisor))
			 (throw 'RESULT nil))
		     (setq divisor (1+ divisor)))
		   n))))
    nil))
 
 
(defun next-prime (n)
  "Return the next prime number after N, or else nil.
 
\[cost: O(sqrt(N))]"
  (if (integerp n)
    (cond
     ((> n 1)
      (let* ((k (if (= 0 (% n 2));start k at next odd number after n
		    (1+ n)
		  (+ n 2))))
	(while (not (prime-p k)) ;and loop upward over odd numbers
	  (setq k (+ k 2)))
	k))
     (t 2))
    nil))
 
 
(defun nth-prime (n)
  "Return the N-th prime number, or else nil.
 
The first prime number is 2.
 
\[cost: O(N*sqrt(N))]"
  (if (integerp n)
      (cond
       ((<= n 0) nil)			;non-positive args are invalid
       ((= n 1) 2)			;special case: only even prime
       (t (let ((k 1))			;n > 1, so test only odd values 3, 5, ...
	    (while (> n 1)
	      (setq k (+ k 2))
	      (if (prime-p k)		;count down each prime found
		  (setq n (1- n))))
	    k)))			;at loop exit, k is the desired nth-prime
    nil))
 
 
(defun prev-prime (n)
  "Return the prime number before (i.e., less than) N, or else nil.
 
\[cost: O(sqrt(N))]"
  (if (integerp n)
      (cond ((<= n 2) nil)		;invalid: there are no primes before 2
	    ((= n 3) 2)			;special case: 2 is the only even prime
	    (t				;n > 3
	     (let* ((k (if (= 0 (% n 2)) ;start k at prev odd number before n
			   (1- n)
			 (- n 2))))
	       (while (not (prime-p k))	;and loop downward over odd numbers
		 (setq k (- k 2)))
	       k)))
    nil))
 
 
(defun primes-between (from to)
  "Return a list of prime numbers between FROM and TO, inclusive, else nil.
 
\[cost: O((to - from + 1)*sqrt(N)/2)]"
  (if (and (integerp from) (integerp to))
      (let ((k)
	    (primes '()))
	(if (and (<= from 2) (<= 2 to))	;handle special case of only even prime
	    (setq primes '(2)))
	(setq k 3)
	;; k is now odd, so we can loop over odd numbers only
	(while (<= k to)
	  (if (prime-p k)
	      (setq primes (append primes (list k))))
	  (setq k (+ k 2)))
	primes)				;final successful list
    nil))				;else invalid arguments
 
 
(defsubst this-or-next-prime (n)
  "Return N if it is prime, else return the next prime number after N,
else nil in N is invalid.
 
\[cost: O(sqrt(N))]"
  (or (prime-p n)
      (next-prime n)))
 
 
(defsubst this-or-prev-prime (n)
  "Return N if it is prime, else return the prime number before
(i.e., less than) N.
 
\[cost: O(sqrt(N))]"
  (or (prime-p n)
      (prev-prime n)))
 
;;; primes.el ends here
 
;; Illustration
(defun show-some-primes (file) "Show some prime numbers." (interactive "p")
  (princ (primes-between 1 100))
)