Algomath- c Library   Release 1.0.5   03.2000
-------------------   -------------   -------

Algomath is a portable Arithmetic C Library.
All routines have been thoroughly optimised for speed and efficiency,
while at the same time portable C. However optional
fast assembly language alternatives for prime numbers time-critical
routines are also included, particularly for the popular Intel 80x86
range of processors. There is no problem to exclude this code,
-(see COMPILING AND USING ALGOMATH)-

The library is tested with DJGPP v2 C-compiler and the
pgcc-2.90.23 compiler. Under CYGNUS the egcs-2.91.57 compiler.
Under VISUALC.
Although it should work on any other system.

Download the latest release at:
http://www2.vo.lu/homepages/armand/index.html
               
You are free to do anything you desire with this code,
as long as you give credit where credit is due...

For criticism, fixes, suggestions, enhancements, send email to:

Armand Turpel: armandt@unforgettable.com

Patrick Dostert: patrick.dostert@cie.etat.lu
who helped in optimizing this library


INDEX
-----

     1.FILES IN THIS ARCHIVE
	 2.COMPILING AND USING ALGOMATH
     3.DESCRIPTION OF THE FUNCTIONS
     4.HISTORY
     5.LEGAL AND OTHER STUFF


FILES IN THIS ARCHIVE:
----------------------

algomath.h				
	headerfile
makefile				
	DJGPP makefile
src/*.*					
	library source code
assembly/src/isprime.asm
	isPrime() assembler source code (nasm)
assembly/obj/isprime.o				
	object code of isPrime()(coff format)
assembly/obj/isprime.obj
	isprime.obj	object code of isPrime()(windows object format)
Readme.txt	
	this file


COMPILING AND USING ALGOMATH:
-----------------------------

Under DJGPP, CYGNUS and VISUALC there should be no problem to compile algomath.

Under VISUALC add the following files to your lib project:
	-all files from the /src directory
	-algomath.h
	-assembly/obj/isprime.obj
	
For DJGPP or CYGNUS:
	If you have PGCC installed change in the makefile:
		#PGCC = 1
		 to
		PGCC = 1 
	If you have EGCS (on a pentium) installed change in the makefile:
		#EGCS = 1
		 to
		EGCS = 1 
	Otherwise disable these two variables:
		#PGCC = 1
		#EGCS = 1
		
	If you dont want to include the assembly
	function(s) in the library,	disable in the makefile:
		ASSEMBLY = 1
		 to
		#ASSEMBLY = 1
	In order also change in the algomath.h header file:
		#define USE_ISPRIME_ASM
		 to
		/*#define USE_ISPRIME_ASM*/

Change to the folder were you have unzip algomath and run make.
After compiling copy lib/libalgo.a to the djgpp/cygnus lib path
and algomath.h to the djgpp/cygnus include path.
To use Algomath, #include <algomath.h> and link with libalgo.a
Example command line: gcc foobar.c -o foobar.exe -lalgo	


DESCRIPTION OF THE FUNCTIONS:
-----------------------------

#######################
### Initial Rutines ###
#######################

int am_init()
-------------
	The function return 0 if there isn't enough memory else 1.
	You !! MUST !! introduce this function once in your code before you
	use any	function.


void am_exit()
-------------
    if you dont need any more the algomath functions in your code, you
    should call this function. It free some memory that algomath use.
  

#######################
### Numbers Rutines ###
#######################

int am_numlength(int n)
-----------------------
	returns the number of digits of a number.
	am_numlength( 65364785 ) return 8


int am_sumdigits(int n)
-----------------------
     returns the sum of the digits of the number n
     am_sumdigits( 5732 ) returns 17


int am_sumdigitsalt(int n)
--------------------------
     returns the alternating sum of the digits of the number n
     even digitplaces are substracted, odd digitplaces are added
     am_sumdigitsalt( 5732 ) return 1 because 2-3+7-5


int am_extract(int n, int x)
----------------------------
     returns the digit x you want to extract from a number n.
     a negative number will return a negative result.
     if n > 999999999 then the function return n.

     am_extract( 648761, 3) return 7
     am_extract( 648761, 5) return 4
     0's before the number (00323443) are also considered.
     am_extract( 8761, 6) return 0

     if x is negative, the function convert it to positive.
     if x > 9 then only the last digit is considered.
     ex: x=17 so x=7


int am_replace(int n, int d1, int d2)
-----------------------------------
     returns the modified number were n is the
     number to modify, d1 is the digit place to modify and
     d2 the digit to put in.
     if n > 999999999 then the function return n.
     if d1 or d2 is negative, the function convert it to positive.
     if d1 or d2 >9 then only the last digit is considered.
     ex: d1=36 so d1=6

     am_replace( 47321, 4, 2) return 42321
     am_replace( 47321, 2, 9) return 47391
     0's before the number (00323443) are also considered.
     am_replace( 8761, 6, 2) return 208761


int am_swap(int n, int d1, int d2)
----------------------------------
     return the modified number were n is the number to modify,
     d1 the digit place to swap with the d2 digit place.
     if d1 or d2 is negative, the function convert it to positive.
     if d1 or d2 >9 then only the last digit is considered.
     ex: d1=36 so d1=6
     if n > 999999999 then the function return n.

     am_swap( 123456 , 2, 4) return 125436
     am_swap( 123456 , 6, 1) return 623451
     0's before the number (00323443) are also considered.
     am_swap( 8761, 6, 2) return 608701
         

int am_rotate(int n, int x, int p)
----------------------------------
     rotates the digits of a number n, x times, in base 10.
	 p is number of digits to rotate.
     if p >9 then only the last digit is considered.
     if n > 999999999 then the function return n.

     am_rotate(543210,2,5) returns 105432 ( rotate right if x > 0 )
     am_rotate(543210,-2,5) returns 321054 ( rotate left  if x < 0 )

	 if p > length of the number n then zeros befor the number 
     will be included in the rotation process.
     00543210 = 7 digits

     am_rotate(543210,2,7) returns 54321000 ( rotate right if x > 0 )
     am_rotate(543210,-2,7) returns 10005432 ( rotate left  if x < 0 )

     if p < length of the number n then only the first p digits
     of the number n will be rotated.

     am_rotate(543210,2,3) returns 543102 ( rotate right if x > 0 )
     am_rotate(543210,-2,3) returns 543021 ( rotate left  if x < 0 )


int am_sort( int n)
-------------------
     " sorts " the digits of a number n
     am_sort( 57834 ) returns 34578
     if n > 999999999 then the function return n.


##########################
### Arithmetic Rutines ###
##########################

int am_sumdivisor(int n)
------------------------
     returns the sum of all possible divisors of the number n,
     n not included
	 am_sumdivisors( 20 ) returns 22 ( = 1 + 2 + 4 + 5 + 10 )


int am_gcd(int a, int b)
------------------------
     returns the " greatest common divisor " of two numbers a and b
	 am_gcd( 123698745, 147896325) returns 45

int am_hailstone(int n)
-----------------------
	This function allows you to investigate hailstone numbers:
	if n == odd then it return n*3+1
	if n== even then it return n/2
	call this function until it return 1.
	if n is negative <0 then the result is also negative.
	if the result is bigger than int or n=0, it return 0 (failure).
	n=77671 is the first number that return 0.
	if you want to investigate all big numbers,I recommend you to use the
	c/c++ miracl library:
	ftp://ftp.compapp.dcu.ie/pub/crypto/miracl.zip

	ex.:
	
	n=25267;
	while(n!=1){
		n=am_hailstone(n);
			if(n==0){
				printf("n is to big\n");
				exit();
			}
		printf("%d\n",n);
	}
	
#############################
### Prime Numbers Rutines ###
#############################

int am_isprime(int n)
---------------------
     returns 1 if n is prime else 0
     negative numbers n are also accepted. 

int am_prime_ba(int t, int x)
-----------------------------
	If x<0 then the function return the next prime number "befor" the number t.
	If x>0 then the function return the next prime number "after" the number t.
	If x==0 then the function return t
	If t is negative then the result will also be negative.
	
int *am_primes_array(int n, int x)
----------------------------------
     create x prime numbers from a given number n, and return the
     pointer address. return 0 if there isnt enough memory.
     if n is negative then the primes are also negative.

     ex:
     int *pointer , c=0;

     if((pointer = am_primes_array(4, 3)) == NULL)
         printf("not enough memory\n");

     while( *(pointer+c)){
			printf("%d\n",*(pointer+c));
            c++;
        } 
 
     return *(pointer+0)=5 *(pointer+1)=7 *(pointer+2)=11
     *(pointer+3)=0 !! last variable is always 0 !!

     WARNING!!!!!!!
     --------------
     If you dont need any more the prime_array result you should free
	 the pointer allocation(s):
     free ( pointer );

     take a look at the following code:

     for(x=0;x<100000;x++){
         pointer=am_prime_array(x, 1000); 
         /*do some stuff*/
      }

     this allocate 100000*1000 int memory!!!!
     so the correct code should be:

     for(x=0;x<100000;x++){
         pointer=am_prime_array(x, 1000); 
         /*do some stuff*/
         free(pointer);
      }


int *am_primes_between(int n1, int n2, int *p)
--------------------------------------
     create prime numbers between two given number n1 and n2, and
     return the pointer address. Store in p the number of primes found.
     return 0 if there isnt enough memory.
     if n1 or n2 = negative then the function convert it to positive.
     It dosen't matter whether n1>n2 or n1<n2. 
     
     ex:
     int *pointer, p, c=0;

     if((pointer = am_primes_between(4, 15, &p)) == NULL)
         printf("not enough memory\n");

     while( *(pointer+c)){
			printf("%d\n",*(pointer+c));
            c++;
        } 
     
     printf("%d primes found\n", p); print out how many primes found.

     print out: 5 7 11 13
     *(pointer+4)=0 !! last last variable is always 0 !!

     See WARNING!!!! in am_primes_array()


int *am_factorize(int n, int *factors)
--------------------------------------
     facrorize a number n and return the pointer address were you
     can find the result. factors contains the number of
     how many factors found. return 0 if there isnt enough memory.
     negative numbers n are also accepted. 

	 pointer = am_factorize( 20 , &factors) returns:
       factors = 3
       *(pointer+0)=2, *(pointer+1)=2, *(pointer+2) = 5
       *(pointer+3) = 0 !! last variable is always 0 !!

     ex:

     int *pointer;
     int factors, x = 0;

     if((pointer = am_factorize( 20, &factors ))==NULL){
         printf("not enough memory\n");
         exit(0);
       }
     printf("how many factors found: %d\n",factors);
     while(*(pointer+x)){
         printf("%d\n",*(pointer+x);
         x++;
      }
     
     See WARNING!!!! in am_primes_array()


int am_goldbach(int n,int *d1, int *d2)
 --------------------------------------
    "--'strong' Goldbach's Conjecture
        The Conjecture is, "Every even integer >= 4 is the sum of
        two primes.--"
     Return 0 if n not even else 1.
     n is the even number to test.
     after calling the function, d1 contain the smallest possible prime
     and d2 the second greater prime. if n is negative then d1 and d2 are
     also negative.

     ex:

     int d1,d2,r,n=16;

     r = am_goldbach( 16, &d1, &d2);
     printf("%d = %d + %d\n",n,d1,d2);


int am_isPrime(unsigned int testnumber)
------------------------------
	This is the assembly implementation of am_isprime(int n).
	returns 1 if testnumber is prime else 0
	(optimized by Patrick Dostert: patrick.dostert@cie.etat.lu)

    If algomath is compiled with #define AM_ISPRIME_ASM
    then algomath use this function for every prime operation.
    But you can include this function as stand alone in your code.
    declare first: extern int am_isPrime(unsigned int);
    and link isprime.o to your program.

-----------------------------------------------------------------------

HISTORY:
--------

Algomath 
0.9 beta  first release 12.1997
0.91 beta bugfix release 3.1998
0.92 beta bugfix release 3.1998
0.93 beta reviewed and add int am_goldbach(int a,int *p) 4.1998
1.00 beta rewrite of the prime related routines (better performance) 10.1998
1.0.1 beta rewrite of the prime related routines
		am_primearray(1,1000000,array)
1.0.2 beta optimized am_primearray()
1.0.3 beta add am_prime_init
1.0.4 complete rewrite the most part of the functions.  11.1999
      fixed some bugs.
      NEW functions:
                    am_exit()
                    am_isPrime() 
                    am_numlength()
                    am_swap()
                    am_replace()
                    am_extract()
                    am_primes_between()
1.0.5 Tested under CYGNUS and VISUALC
		therefor making some change in the makefile
		add am_isprimeba(int n, int x)
		add am_hailstone(int n)
		

LEGAL AND OTHER STUFF:
----------------------

Pentium is a (registered) trademark of Intel, http://www.intel.com
DJGPP is the MSDOS-port of the famous GNU-C compiler, http://www.delorie.com
MSDOS is a (registered) trademark of Microsoft, http://www.microsoft.com
for info on GNU software see http://www.gnu.org


------------------------------------------------------------------------------

  Luxembourg, 11.1999,
  Armand Turpel