/* bignum.c -- UMB Scheme, implementation of bignum numbers. 

UMB Scheme Interpreter  				$Revision: 1.1 $
Copyright (C) 1988, 1996 William R Campbell

This program 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 1, or (at your option)
any later version.

This program 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 this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

UMB Scheme was written by Bill Campbell with help from Karl Berry,
Barbara Dixey, Ira Gerstein, Mary Glaser, Kathy Hargreaves, Bill McCabe,
Long Nguyen, Susan Quina, Jeyashree Sivasubram, Bela Sohoni, John Tam 
and Thang Quoc Tran.

For additional information about UMB Scheme, contact the author:

	Bill Campbell
	Department of Mathematics and Computer Science
	University of Massachusetts at Boston
	Harbor Campus
	Boston, MA 02125

	Telephone: 617-287-6449		Internet: bill@cs.umb.edu

*/

#include "portable.h"
#include "eval.h"
#include "object.h"
#include "architecture.h"
#include "number.h"
#include "fixnum.h"
#include "bignum.h"
#include "rational.h"
#include "real.h"
#include "complex.h"
#include "steering.h"
#include "io.h"
#include <math.h>
#include <errno.h>

#include <stdlib.h>

#define Most_Significant_Digit(num) \
			(Get_Number_Digit( (num) , Get_Number_Length(num) - 1 ))


Private Short	Bignum_Compare(void);
Private	void	Delete_Leading_Zeros(Object);
Public	void	Long_Division(void);
Private	void	Normalize( void );
Private	Boolean	Numerator_Less_Than_Denominator( void );


/* REPRESENTATION */

#define MAX_DIGIT		(RADIX-1)

#define Low_16(long)		(((long) >= 0) ? (Short) ((long) % RADIX) \
					      : (-(Short) (-(long) % RADIX)))

#define High_16(long)	(((long) >= 0) ? (Short) ((long) / RADIX) \
					      : (-(Short) (-(long) / RADIX)))

#define Integer_Digit(n,i)	((Integer) Get_Number_Digit(n,i))


#define max(a,b) ((a) > (b) ? (a) : (b))
#define min(a,b) ((a) < (b) ? (a) : (b))


/* Predicates. */

Public Boolean 
Is_Bignum_Zero (void)
{
	return (Number_Sign(Top(1)) == 0);
}


Public Boolean 
Is_Bignum_Positive (void)
{
	return (Number_Sign(Top(1)) > 0);
}



Public Boolean 
Is_Bignum_Negative (void)
{
	return (Number_Sign(Top(1)) < 0);
}



Public Boolean 
Is_Bignum_Odd (void)
{
	return (! Is_Bignum_Even());
}



Public Boolean 
Is_Bignum_Even (void)
{
	return ( (Get_Number_Digits(Top(1))[0] % 2) == 0);
}



Public Boolean 
Is_Bignum_Exact (void)
{
	return( TRUE ); 
}



Public Boolean 
Is_Bignum_Inexact (void)
{
	return( FALSE );
}




/* General comparison. */

Public Boolean 
Bignum_Equal (void)
{
	return Bignum_Compare() == 0;
}



Public Boolean 
Bignum_Less_Than (void)
{
	return Bignum_Compare() < 0;
}



Public Boolean 
Bignum_Greater_Than (void)
{
	return Bignum_Compare() > 0;
}



Public Boolean 
Bignum_Less_Than_Or_Equal (void)
{
	return Bignum_Compare() <= 0;
}



Public Boolean 
Bignum_Greater_Than_Or_Equal (void)
{
	return Bignum_Compare() >= 0;
}



Private Short 
Bignum_Compare (void)
{
	Bignum_Subtract();
	return Number_Sign( Value_Register );
}




/* BIGNUM ADDITION */

Public void 
Bignum_Add (void)
{
	Integer	size1 = Get_Number_Length( Top(1) );
	Integer	size2 = Get_Number_Length( Top(2) );
	Integer newsize;
	Integer	accumulator;
	Integer index;
	Short	carry;

	Object	top1, top2;

	/* Compute number of digits in result */

	newsize = size1 > size2 ? size1+1 : size2+1;

	Make_Bignum_Number( newsize );
	top1 = Top(1);
	top2 = Top(2);

	carry = 0;
	for ( index = 0; index < newsize; index++ )
	{
		accumulator = (Integer) carry +
		    (index < size1 ? Integer_Digit( top1 , index ) : 0) +
		    (index < size2 ? Integer_Digit( top2 , index ) : 0);
		Get_Number_Digit(Value_Register, index) = Low_16( accumulator );
		carry = High_16( accumulator );
	}
	Delete_Leading_Zeros( Value_Register );
}

/* BIGNUM SUBTRACTION */


Public void 
Bignum_Subtract (void)
{
	Integer	size1 = Get_Number_Length( Top(1) );
	Integer	size2 = Get_Number_Length( Top(2) );
	Integer newsize;
	Integer	accumulator;
	Integer index;
	Short	carry;

	Object	top1, top2;

	/* Compute number of digits in result */

	newsize = size1 > size2 ? size1+1 : size2+1;

	Make_Bignum_Number( newsize );
	top1 = Top(1);
	top2 = Top(2);

	carry = 0;
	for ( index = 0; index < newsize; index++ )
	{
		accumulator = (Integer) carry -
		    (index < size1 ? Integer_Digit( top1 , index ) : 0) +
		    (index < size2 ? Integer_Digit( top2 , index ) : 0);
		Get_Number_Digit(Value_Register, index) = Low_16( accumulator );
		carry = High_16( accumulator );
	}
	Delete_Leading_Zeros( Value_Register );
}

/* BIGNUM MULTIPLICATION  */


Public void 
Bignum_Multiply (void)
{
	Integer	size1 = Get_Number_Length( Top(1) );
	Integer	size2 = Get_Number_Length( Top(2) );
	Integer newsize;
	Integer	accumulator;
	Integer index1, index2;
	Short	carry;

	Object	top1, top2;

	/* Compute number of digits in result */

	newsize = size1 + size2;

	Make_Bignum_Number( newsize );
	top1 = Top(1);
	top2 = Top(2);

	for ( index1 = 0; index1 < size1; index1 ++ )
	{
		carry = 0;
		for ( index2 = 0; index2 < size2; index2 ++ )
		{
			accumulator = (Integer) carry +
			    Integer_Digit( top1 , index1 ) *
			    Integer_Digit( top2 , index2 ) +
			    Integer_Digit( Value_Register , index1+index2 );
			Get_Number_Digit(Value_Register , index1+index2) =
			    Low_16( accumulator );
			carry = High_16( accumulator );
		}
		if ( index1 + index2 < newsize )
		{
			Get_Number_Digit(Value_Register, index1+index2) = carry;
		}
	}

	Delete_Leading_Zeros( Value_Register );
}


/* BIGNUM DIVISION. */
      
#define QUOTIENT        Top( 1 )
#define DENOMINATOR     Top( 2 )
#define NUMERATOR       Top( 3 )

Private Boolean 
Numerator_Less_Than_Denominator (void)

{
	Boolean result;

                                        /* Stack: Q, D, N, d, n...   */
        Push( Top(3) );                 /* Stack: N, Q, D, N, d, n...   */
        Bignum_Abs();
        Pop(1);                         /* Stack: Q, D, N, d, n...   */
        Push(Value_Register);           /* Stack: |N|, Q, D, N, d, n...   */
        Push( Top(3) );                 /* Stack: D, |N|, Q, D, N, d, n...   */
	result = Bignum_Less_Than(); 	/* compare |numerator| < denominator */
        Pop(2);                         /* Stack: Q, D, N, d, n...   */
	return result;
}

Private void 
Normalize (void)
        
	
        /* First justify remainder (numerator) if it's negative. Then
	justify signs for quotient and remainder based on nsign, and
	dsign. Leave quotient in Value_Register and remainder on top 
	of stack.
	*/

{
	Integer	dsign = Number_Sign( Top(4) );
	Integer	nsign = Number_Sign( Top(5) );
        
	/* Justify values for quotient and remainder
           if numerator < 0,  then 1: quotient has to be one unit less,
                                   2: remainder += denominator
        */


        if (Number_Sign( Top(3) ) < 0)    /* Stack: Q, D, N, d, n...   */
	{
		Make_Small_Bignum( -1 );
                Push( Value_Register );   /* Stack: -1, Q, D, N, d, n...   */
		Bignum_Add(); 
                Pop( 2 );                 /* Stack: D, N, d, n...   */
                Push( Value_Register );   /* Stack: Q-1, D, N, d, n...   */


                Push( Top(3) );           /* Stack: N, Q-1, D, N, d, n...   */
                Push( Top(3) );           /* Stack: D, N, Q-1, D, N, d, n... */
		Bignum_Add(); 
                Pop( 2 );                 /* Stack: Q-1, D, N, d, n...   */
                Top( 3 ) = Value_Register; /* adjusted remainder(numerator) */
	}

	/* now justify the signs for quotient and remainder */

	if ( nsign < 0 && dsign < 0) /* must reverse sign of remainder */
        {
                Make_Small_Bignum( 0 );
                Push( Value_Register );   /* Stack: 0, Q, D, N, d, n...   */
                Push( Top(4) );           /* Stack: N, 0, Q, D, N, d, n... */
		Bignum_Subtract();
                Pop( 2 );                 /* Stack: Q, D, N, d, n... */
                Top( 3 ) = Value_Register;
	}
	else if ( nsign > 0 && dsign < 0 ) /* must reverse sign of quotient */
	{
		Make_Small_Bignum( 0 );
                Push( Value_Register );   /* Stack: 0, Q, D, N, d, n... */
                Push( Top(2) );           /* Stack: Q, 0, Q, D, N, d, n... */
		Bignum_Subtract();
                Pop(3);                   /* Stack: D, N, d, n... */
                Push( Value_Register) ;   /* Stack: Q, D, N, d, n... */
	}
	else if ( nsign < 0 && dsign > 0 ) /* reverse signs for both */
	{
		Make_Small_Bignum( 0 );
                Push( Value_Register );   /* Stack: 0, Q, D, N, d, n...   */
                Push( Top(4) );           /* Stack: N, 0, Q, D, N, d, n... */
		Bignum_Subtract();
                Pop( 1 );                 /* Stack: 0, Q, D, N, d, n... */
                Top( 4 ) = Value_Register;

                Push( Top(2) );           /* Stack: Q, 0, Q, D, N, d, n... */
		Bignum_Subtract();
                Pop(3);                   /* Stack: D, N, d, n... */
                Push( Value_Register) ;   /* Stack: Q, D, N, d, n... */
	}
        Value_Register = Top( 1 );
        Pop( 2 );

}



Public void 
Bignum_Divide (void)
{
	Make_Rational_Number();
}



Public void 
Long_Division (void)
        /* Value_Register = Top(1) / Top(2)  */
        /* Push( Top(1) % Top(2) )           */

{
        Integer dsize = Get_Number_Length( Top(1) );
	Integer	nsize = Get_Number_Length( Top(2) );
	Integer	dsign = Number_Sign( Top(1) );
	Integer	nsign = Number_Sign( Top(2) );
        Integer accumulator, first_digit;
        Short   index, start_index, first_denominator_digit, carry;


	
	Push( Copy_Object( Top(2), Bignum_Size(nsize))); /* copied numerator */
	if ( nsign < 0 )  /* if numerator < 0, make it positive */    
	{
		Bignum_Abs(); 
		Pop(1);
		Push( Value_Register );
	}

	Push( Copy_Object( Top(2), Bignum_Size(dsize)));/*copied denominator */
	if ( dsign < 0 ) /* if denominator < 0, make it positive */
	{
		Bignum_Abs();
		Pop(1);
		Push( Value_Register );
	}
		
	Make_Bignum_Number( nsize );
	Push( Value_Register );			/* zero-initialized quotient */

	
        first_denominator_digit = Most_Significant_Digit( DENOMINATOR );
	
	/* Just divide their absolute values, then manipulate signs for
		quotient and remainder later */

	while (TRUE)
	{
		accumulator = 0;
                index = Get_Number_Length(NUMERATOR) - 1;
		while (abs(accumulator) < abs(first_denominator_digit) &&
                                                      index >= 0)
		{
			accumulator *= RADIX;
                        accumulator += Integer_Digit(NUMERATOR,index);
			index--;
		}

		first_digit = accumulator / first_denominator_digit;

		start_index = index + 1 - (dsize - 1);

		if (start_index < 0)
		{
                        Delete_Leading_Zeros( QUOTIENT );
                        Normalize();
			return;
		}

                Get_Number_Digit(QUOTIENT,start_index ) += Low_16(first_digit);
		
		carry = 0;

		for ( index = 0; index < dsize; index++ )
		{
			accumulator = - first_digit *
                            Get_Number_Digit(DENOMINATOR,index) +
			    carry + 
                            Get_Number_Digit(NUMERATOR,index + start_index);

                        Get_Number_Digit(NUMERATOR, index + start_index) =
			    Low_16( accumulator );
			carry = High_16( accumulator );

		}

		if (index + start_index < nsize)
		{
                        Get_Number_Digit(NUMERATOR,index+start_index) += carry;
		}

                Delete_Leading_Zeros( NUMERATOR );

                if ((start_index == 0) && Numerator_Less_Than_Denominator())
		{
                        Delete_Leading_Zeros( QUOTIENT );
                        Normalize();
			return;
		}
	}

}



Private void 
Delete_Leading_Zeros (Object num)
{
	/*
	   Leading zeros occur in two ways: an explicit leading digit of zero,
	   and a leading one (or minus one) followed by a digit of opposite
	   sign, ie "-1,5" == "-5".
	*/

	Short	index = Get_Number_Length(num) - 1;
	Integer	accumulator;
	Short	first_digit;

	while (index >= 1)
	{
		if (abs( first_digit = Get_Number_Digit(num,index) ) > 1)
			break;
		if (abs ( accumulator = first_digit * RADIX +
		    Get_Number_Digit(num,index-1) ) > MAX_DIGIT)
			break;
		else
		{
			Get_Number_Length(num) = (Integer) index;
			Get_Number_Digit(num,index-1) = Low_16( accumulator );
			index--;
		}
	}
}




Public void 
Bignum_Quotient (void)
{
	Long_Division();
	Pop(1); 	/* popping remainder from stack */
}



Public void 
Bignum_Remainder (void)
{
	Long_Division();
	Value_Register = Top(1);
	Pop(1);
}



Public void 
Bignum_Modulo (void)
{
	Integer	dsign = Number_Sign( Top(1) ); 
	Integer	nsign = Number_Sign( Top(2) );
	
	Long_Division();
	Value_Register = Top(1);

	if ( (nsign * dsign) < 0 )
        /* == "if ((nsign > 0 && dsign < 0) || (nsign < 0 && dsign > 0))"  */
	{
		Push( Top(2) ); /* denominator */
		Bignum_Add(); /* remainder + denominator */
		Pop( 1 );
	}
	
	Pop(1);
}



Public void 
Bignum_Negate (void)
{
	Integer len = Get_Number_Length( Top( 1 ) );
	Integer index;

	Value_Register = Copy_Object( Top( 1 ) , Bignum_Size( len ) );
	for ( index = 0; index < len; index++ )
	{
		Get_Number_Digit( Value_Register , index ) =
			- Get_Number_Digit( Value_Register , index );
	}
}



Public void 
Bignum_Abs (void)
{
	if (Is_Bignum_Negative())
	{
		Bignum_Negate();
	}
	else
	{
		Value_Register = Top(1);
	}
}



Public void 
Bignum_Numerator (void)
{
	Value_Register = Top(1);
}


 
Public void 
Bignum_Denominator (void)
{
	Make_Small_Bignum(1);
}


 
Public void 
Bignum_Rationalize (void)
{
	Error("Bignum_Rationalize not yet implemented!");
}


 
Public void 
Bignum_Max (void)
{
	Value_Register = Bignum_Greater_Than() ? Top(2) : Top(1);
}



Public void 
Bignum_Min (void)
{
	Value_Register = Bignum_Less_Than() ? Top(2) : Top(1);
}



Public void 
Bignum_GCD (void)
{
	/* make arguments positive since gcd is positive */

	Push( Top(2) );
	Push( Top(2) );

	Bignum_Abs();
	Replace(1, Value_Register);

	Push(Top(2));
	Bignum_Abs();
	Replace(1, Value_Register);

	while (Number_Sign(Top(1)) != 0)
	{
		Bignum_Remainder();
		Top(2) = Top(1);
		Top(1) = Value_Register;
	}

	Value_Register = Top(2);
	
	Pop(3);
}


 
Public void 
Bignum_LCM (void)
{
	/* LCM(a,b) = (a*b)/GCD(a,b)  */
	
	Bignum_Multiply();
	Push(Value_Register);

	Push(Top(3));
	Push(Top(3));

	Bignum_GCD();
	Push(Value_Register);

	Top(2) = Top(4);
	Number_Divide();

	Push(Value_Register);
	Number_Abs();

	Pop(5);
}


 

Public void 
Bignum_Floor (void)
{
	Value_Register = Top(1);
}


 
Public void 
Bignum_Ceiling (void)
{
	Value_Register = Top(1);
}


 
Public void 
Bignum_Truncate (void)
{
	Value_Register = Top(1);
}


 
Public void 
Bignum_Round (void)
{
	Value_Register = Top(1);
}




Public void 
Bignum_Sqrt (void)
{
	Promote(1, REAL_LEVEL);
	
	if( Get_Number_Real_Value(Top(1)) < 0 )
	{
		Make_Complex_Number( (Double) 0.0 ,
				     sqrt( - Get_Number_Real_Value(Top(1))) );
        }
	else
	{
		Make_Real_Number( sqrt (Get_Number_Real_Value(Top(1))) );
	}
}


 
Public void 
Bignum_Exp (void)
{
	Promote(1, REAL_LEVEL);

	Make_Real_Number( exp (Get_Number_Real_Value(Top(1))) );
}


 
Public void 
Bignum_Log (void)
{
	if(Number_Sign(Top(1)) <= 0)
	{
		Error("Argument of log must be positive");
	}


	Promote(1, REAL_LEVEL);

	Make_Real_Number( log (Get_Number_Real_Value(Top(1))) );
}


 
Public void 
Bignum_Expt (void)
{
	Push( Top(2) );
	Is_Number_Negative();
	Pop(1);

	if( (Number_Sign(Top(1)) == 0) && (Value_Register == The_True_Object) )
	{

		Error("Domain error for expt");
	}

	else if (Number_Sign(Top(1)) >= 0)
	{
		Make_Small_Bignum( 1 ); /* running total (initially = 1) */

		while ( Number_Sign(Top(1)) > 0 )
		{
			Push( Value_Register );		/* running total */

			Push( Top(2) );
			Make_Small_Bignum( 1 );
			Push( Value_Register );
			Number_Subtract();
			Pop(2);
			Replace(2,Value_Register);	/* exponent -= 1 */

			Push( Top(3) );			/* total *= mantissa */
			Bignum_Multiply();
			Pop( 2 );
		}
	}
	else
	{
		/* Negative Exponent */

		Promote(1, REAL_LEVEL);
		Promote(2, REAL_LEVEL);

		Make_Real_Number( pow ( (Get_Number_Real_Value(Top(2))),
				(Get_Number_Real_Value(Top(1))) ) );
	}
}



 
Public void 
Bignum_Sin (void)
{
	Promote(1, REAL_LEVEL);

	Make_Real_Number( sin (Get_Number_Real_Value(Top(1))) );
}


 
Public void 
Bignum_Cos (void)
{
	Promote(1, REAL_LEVEL);

	Make_Real_Number( cos (Get_Number_Real_Value(Top(1))) );
}


 
Public void 
Bignum_Tan (void)
{
	Promote(1, REAL_LEVEL);

	Make_Real_Number( tan (Get_Number_Real_Value(Top(1))) );
}


 
Public void 
Bignum_Asin (void)
{
	Error("Argument of asin must lie between -1 and 1, inclusive");
}


 
Public void 
Bignum_Acos (void)
{
	Error("Argument of acos must lie between -1 and 1, inclusive");
}


 
Public void 
Bignum_Atan (void)
{
	Promote(1, REAL_LEVEL);

	Make_Real_Number( atan (Get_Number_Real_Value(Top(1))) );
}


 
Public void 
Bignum_Atan2 (void)
{
	Promote(1, REAL_LEVEL);
	Promote(2, REAL_LEVEL);

	Make_Real_Number( atan2 (Get_Number_Real_Value(Top(2)), 
					Get_Number_Real_Value(Top(1))) );
}


 
 
/* Transfer functions */


Public void 
Bignum_Exact_To_Inexact (void)
{
	Promote( 1 , REAL_LEVEL );
	Value_Register = Top(1);
}


 
Public void 
Bignum_Inexact_To_Exact (void)
{
	Value_Register = Top(1);
}

/* BIGNUM TO STRING */

Public void 
Bignum_To_String (void)

{
	Import void String_Append(void);

	Integer	high, low;
	Object	remainder;
	Character partial_string[MAX_CHARS_PER_INT];
	Integer	radix = Number_To_Integer( Top(1) );
	Integer print_radix = 0;
	Object	num = Top(2) ;

	switch ( Get_Number_Length( num ) )
	{
	case 0:
		sprintf( partial_string , "%d" , 0 );
		Make_Constant_String( partial_string );
		return;

	case 1:
		if ( radix == 10 )
		{
			sprintf( partial_string, "%d", Get_Number_Digit(num,0));
			Make_Constant_String( partial_string );
		}
		else
		{
			Make_Constant_String(
			   Integer_To_Cstring( Get_Number_Digit(num,0), 
						partial_string, radix, 0) );
		}
		return;
		
	case 2:
		if ( radix == 10 )
		{
			sprintf( partial_string , "%d" ,
		    		Get_Number_Digit(num,1) * RADIX +
		    		Get_Number_Digit(num,0));
			Make_Constant_String( partial_string );
		}
		else
		{
			Make_Constant_String(
			    Integer_To_Cstring((Integer)
					       Get_Number_Digit(num,1) * RADIX +
					       Get_Number_Digit(num,0), 
						partial_string, radix, 0) );
		}
		return;

	default:
		print_radix =	radix == 2  ? 16 :
				radix == 8  ? 4096 :
				radix == 10 ? 10000 :
				radix == 16 ? 65536 : 10000;

		Make_Constant_String( "" );
		Push( Value_Register );
		Push( Top( 3 ) ); 
		do {
			Integer_To_Bignum( print_radix );
			Push( Value_Register );
			Long_Division();
			remainder = Top(1);
			Pop(3); /* remainder, print_radix and dividend */
			high = Get_Number_Length( remainder ) == 2
			    ? Get_Number_Digit( remainder , 1)
			    : 0;
			low = Get_Number_Digit( remainder , 0 );

			Push( Value_Register );	/* new dividend = quotient */
			
			Make_Constant_String( 
				Integer_To_Cstring( abs(high * RADIX + low),
						    partial_string, radix, 4) );
			Push( Value_Register );
			Push( Top( 3 ) );
			String_Append(); Pop( 2 );
			Replace( 2 , Value_Register );	
		} while ( Get_Number_Length( Top( 1 ) ) > 2);
		
		Integer_To_Number( radix );
		Push( Value_Register );
		Number_To_String(); Pop( 2 );
		Push( Value_Register );
		Push( Top( 2 ) );
		String_Append(); Pop( 3 );
	}
}

Public void 
Bignum_Make_Rectangular (void)
{
	Promote(2, REAL_LEVEL);
	Promote(1, REAL_LEVEL);

	Make_Complex_Number( Get_Number_Real_Value(Top(2)),
				Get_Number_Real_Value(Top(1)) );

}


 
Public void 
Bignum_Make_Polar (void)

#define MAG Get_Number_Real_Value(Top(2))
#define ANG Get_Number_Real_Value(Top(1))

{
	Promote( 2, REAL_LEVEL);
	Promote( 1, REAL_LEVEL);

	Make_Complex_Number( (MAG) * cos(ANG) , (MAG) * sin(ANG) );

}

#undef MAG
#undef ANG


 
Public void 
Bignum_Real_Part (void)
{
	Value_Register = Top(1);
}


 
Public void 
Bignum_Imaginary_Part (void)
{
	Make_Real_Number(0.0);
}


 
Public void 
Bignum_Magnitude (void)
{
	Bignum_Abs();
}

 

Public void 
Bignum_Angle (void)
{
	Make_Real_Number(0.0);
}


 
 

/* OTHER CONVERSIONS INVOLVING BIGNUMS */


Public void 
Make_Small_Bignum (Integer num)
{
	Integer_To_Bignum( num );
}



Public Integer 
Bignum_To_Integer (Object num)
{
	switch (Get_Number_Length(num))
	{
	case 0:
		return( 0 );

	case 1:
		return( Integer_Digit(num,0) );

	case 2:
		return( Integer_Digit(num,1) * RADIX + Integer_Digit(num,0) );

	default:
		Display_Error("Implementation Restriction; integer too large:", 
				num);
		return( 0 );
	}
}



Public void 
Integer_To_Bignum (Integer num)
{
	if (num == 0)
	{
		Make_Bignum_Number(1);
	}
	else if (abs(num) < RADIX)
	{
		Make_Bignum_Number(1);
		Get_Number_Digit(Value_Register,0) = num;
	}
	else
	{
		Make_Bignum_Number(2);
		Get_Number_Digit(Value_Register,0) = Low_16(num);
		Get_Number_Digit(Value_Register,1) = High_16(num);
	}
}
 


/* Bignum Diagnostics */

/*

Private void Shownum( title , num )

	String title;
	Object num ;
{
	if ( Is_String(num) )
	{
		printf( "%s: <string \"%s\">" , title , Get_String_Value(num));
		return;
	}

	if ( Is_Number( num ) && Get_Number_Tower_Position(num) == REAL_LEVEL )
	{
		printf( "%s: <real %f>" , title , Get_Number_Real_Value(num));
		return;
	}
	if ( ! Is_Number(num) || Get_Number_Tower_Position(num) != BIGNUM_LEVEL)
	{
		printf( "%s: <NOT A BIGNUM>" , title );
	}
	else
	{
		Integer index;
		Integer len = Get_Number_Length(num);

		printf( "%s: { %d:" , title ,  len );
		for ( index = 0; index < len; index ++ )
		{
			printf( " %d" , Get_Number_Digit(num,index) );
		}

		printf( "}" );
	}
}
*/
