Home Manual Packages Global Index Keywords Quick Reference |
    /*
       GCD.I
       GCD, LCM, and prime factorization routines.

       $Id$
     */
    /*    Copyright (c) 1995.  The Regents of the University of California.
                        All rights reserved.  */

    func gcd (a, b)
    /* DOCUMENT gcd(a,b)
         returns the GCD (greatest common divisor) of A and B, which must
         be one of the integer data types.  A and B may be conformable

         arrays; the semantics of the gcd call are the same as any other
         binary operation.  Uses Euclid's celebrated algorithm.
         The absolute values of A and B are taken before the operation
         commences; if either A or B is 0, the return value will be 0.

       SEE ALSO: lcm, is_prime, factorize
     */
    {
      a= abs(a);
      b= abs(b);
      c= min(a, b);
      a= max(a, b);
      b= c;          /* simplifies c=0 case */

      if (dimsof(a)(1)) {
        /* array case */

        for (list=where(c) ; numberof(list) ; list=where(c)) {
          b(list)= bl= c(list);
          c(list)= a(list) % bl;
          a(list)= bl;
        }

      } else {

        /* scalar case can be less baroque */
        while (c) {
          b= c;
          c= a % b;
          a= b;
        }
      }

      return b;
    }

    func lcm (a, b)
    /* DOCUMENT lcm(a,b)
         returns the LCM (least common multiple) of A and B, which must
         be one of the integer data types.  A and B may be conformable

         arrays; the semantics of the lcm call are the same as any other
         binary operation.
         The absolute values of A and B are taken before the operation
         commences; if either A or B is 0, the return value will be 0.

       SEE ALSO: gcd, is_prime, factorize
     */
    {
      d= gcd(a, b);
      /* two potential problems: zero divide and overflow - handle the
         first but not the second */
      return abs(a*b)/(d+!d);
    }

    func is_prime (x)
    /* DOCUMENT is_prime(x)

         return non-zero if and only if X (which must be a scalar integer)
         is prime.  May return a false positive if X is greater than about
         3e9, since at most 20000 candidate factors are checked.
         The absolute value of X is taken first; zero is not prime, but 1 is.

       SEE ALSO: gcd, lcm, factorize
     */
    {
      x= long(abs(x));
      if (x<2) return x==1;

      /* make a list of factors which includes 2, 3, and all larger

         odd numbers not divisible by 3 less or equal to sqrt(x) */

      top= min(long((sqrt(x)+8.)/3.+0.5), 20000);

      factors= ((3*indgen(2:top))/2)*2 - 7;
      factors(1:2)= [2,3];
      return allof(x%factors);
    }

    func factorize (x)
    /* DOCUMENT factorize(x)
         return list of prime factors of X and their powers as an n-by-2

         array.  May include a large non-prime factor if X exceeds 3e9.

         In any event, product(result(,1)^result(,2)) will equal abs(X).

         X must be a scalar integer type.

       SEE ALSO: gcd, lcm, is_prime
     */
    {
      x= long(abs(x));
      if (x<2) return [[x],[1]];

      /* first get rid of any prime factors less than 102 */
      primes= [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,
    	   71,73,79,83,89,97,101];
      primes= primes(where(!(x%primes)));

      powers= _fact_extract(primes, x);   /* returns "deflated" x */

      if (x>1) {

        /* large prime factors require a less direct approach */

        top= min(long((sqrt(x)+2.)/3.+0.5), 20000);
        if (top>=35) {
          /* trial divisors are all odd numbers 103 or greater which are

    	 not divisible by three and do not exceed sqrt(x) */

          trial= ((3*indgen(35:top))/2)*2 - 1;
          /* discard all trial divisors which do not divide x */
          trial= trial(where(!(x%trial)));

          /* the smallest remaining divisor must be prime - remove it and
    	 all its subsequent multiples to find the next prime divisor
    	 and so on until the list contains only primes */
          list= trial;

          for (n=0 ; numberof(trial) ; ++n) {
    	list(n+1)= trial(1);
    	trial= trial(where(trial%trial(1)));
          }
          if (n) {
    	trial= list(1:n);
    	grow, primes, trial;

    	grow, powers, _fact_extract(trial,x);
          }
        }
        if (x>1) {
          grow, primes, [x];
          grow, powers, [1];
        }
      }

      return [primes, powers];
    }

    func _fact_extract (primes, &x)
    {
      if (is_void(primes)) return [];
      /* first get largest power of each prime less than or equal x */

      powers= long(log(x)/log(primes)+1.e-6);
      factors= gcd(primes^powers, x);

      x/= long(exp(sum(log(factors)))+0.5);

      return long(log(factors)/log(primes)+0.5);
    }