home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Gold Fish 2
/
goldfish_vol2_cd1.bin
/
files
/
dev
/
lang
/
umbscheme
/
src
/
fixnum.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-11-29
|
10KB
|
640 lines
/* fixnum.c -- UMB Scheme, implementation of specific fixnum procedures.
UMB Scheme Interpreter $Revision: 2.12 $
Copyright (C) 1988, 1991 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 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>
/* Predicates. */
Boolean Is_Fixnum_Zero()
{
return ( Get_Number_Fixnum_Value(Top(1)) == 0 );
}
Boolean Is_Fixnum_Positive()
{
return ( Get_Number_Fixnum_Value(Top(1)) > 0);
}
Boolean Is_Fixnum_Negative()
{
return ( Get_Number_Fixnum_Value(Top(1)) < 0 );
}
Boolean Is_Fixnum_Odd()
{
return ( Get_Number_Fixnum_Value(Top(1)) % 2 != 0 );
}
Boolean Is_Fixnum_Even()
{
return ( Get_Number_Fixnum_Value(Top(1)) % 2 == 0 );
}
Boolean Is_Fixnum_Exact()
{
return TRUE;
}
Boolean Is_Fixnum_Inexact()
{
return FALSE;
}
/* Comparisons. */
Boolean Fixnum_Less_Than()
{
return ( Get_Number_Fixnum_Value(Top(2)) <
Get_Number_Fixnum_Value(Top(1)) );
}
Boolean Fixnum_Greater_Than()
{
return ( Get_Number_Fixnum_Value(Top(2)) >
Get_Number_Fixnum_Value(Top(1)) );
}
Boolean Fixnum_Equal()
{
return ( Get_Number_Fixnum_Value(Top(2)) ==
Get_Number_Fixnum_Value(Top(1)));
}
Boolean Fixnum_Less_Than_Or_Equal()
{
return ( Get_Number_Fixnum_Value(Top(2)) <=
Get_Number_Fixnum_Value(Top(1)));
}
Boolean Fixnum_Greater_Than_Or_Equal()
{
return ( Get_Number_Fixnum_Value(Top(2)) >=
Get_Number_Fixnum_Value(Top(1)));
}
/* Arithmetic. */
Public void Fixnum_Add()
{
Integer result = ( Get_Number_Fixnum_Value(Top(2)) +
Get_Number_Fixnum_Value(Top(1)) );
if (abs(result) >= RADIX)
{
Make_Small_Bignum(result);
}
else
{
Make_Fixnum_Number( (Short) result);
}
}
Public void Fixnum_Subtract()
{
Integer result = ( Get_Number_Fixnum_Value(Top(2)) -
Get_Number_Fixnum_Value(Top(1)) );
if (abs(result) >= RADIX)
{
Make_Small_Bignum(result);
}
else
{
Make_Fixnum_Number( (Short) result);
}
}
Public void Fixnum_Multiply()
{
Integer result = ( Get_Number_Fixnum_Value(Top(2)) *
Get_Number_Fixnum_Value(Top(1)) );
if (abs(result) >= RADIX)
{
Make_Small_Bignum(result);
}
else
{
Make_Fixnum_Number( (Short) result);
}
}
Public void Fixnum_Divide()
{
Integer remainder = Get_Number_Fixnum_Value(Top(2)) %
Get_Number_Fixnum_Value(Top(1));
if (remainder)
{
Make_Rational_Number();
}
else
{
Make_Fixnum_Number( (Short) (Get_Number_Fixnum_Value(Top(2)) /
Get_Number_Fixnum_Value(Top(1))));
}
}
Public void Fixnum_Quotient()
{
Make_Fixnum_Number( (Short) ( Get_Number_Fixnum_Value(Top(2)) /
Get_Number_Fixnum_Value(Top(1)) ) );
}
Public void Fixnum_Remainder()
{
Make_Fixnum_Number( (Short) ( Get_Number_Fixnum_Value(Top(2)) %
Get_Number_Fixnum_Value(Top(1)) ) );
}
Public void Fixnum_Modulo()
{
Short dividend = Get_Number_Fixnum_Value(Top(2));
Short divisor = Get_Number_Fixnum_Value(Top(1));
Integer remainder = dividend % divisor;
if( (divisor*dividend) >= 0 )
{
Make_Fixnum_Number( (Short) remainder );
}
else
{
Make_Fixnum_Number( (Short) (remainder + divisor) );
}
}
Public void Fixnum_Negate()
{
Value_Register = Copy_Object(Top(1), Fixnum_Size);
Get_Number_Fixnum_Value(Value_Register) =
- Get_Number_Fixnum_Value(Value_Register);
}
Public void Fixnum_Abs()
{
if (Is_Fixnum_Negative())
{
Fixnum_Negate();
}
else
{
Value_Register = Top(1);
}
}
Public void Fixnum_Numerator()
{
Value_Register = Top(1);
}
Public void Fixnum_Denominator()
{
Make_Fixnum_Number(1);
}
Public void Fixnum_Rationalize()
{
Error("Rationalize makes no sense on fixnums");
}
Public void Fixnum_Max()
{
Make_Fixnum_Number(
(Get_Number_Fixnum_Value(Top(2)) > Get_Number_Fixnum_Value(Top(1))
? Get_Number_Fixnum_Value(Top(2))
: Get_Number_Fixnum_Value(Top(1))) );
}
Public void Fixnum_Min()
{
Make_Fixnum_Number(
(Get_Number_Fixnum_Value(Top(2)) < Get_Number_Fixnum_Value(Top(1))
? Get_Number_Fixnum_Value(Top(2))
: Get_Number_Fixnum_Value(Top(1))) );
}
Public void Fixnum_GCD()
{
/* make arguments positive since GCD is always positive */
Push(Top(2));
Fixnum_Abs();
Replace( 1 , Value_Register );
Push(Top(2));
Fixnum_Abs();
Replace( 1 , Value_Register );
while (! Is_Fixnum_Zero() )
{
Fixnum_Remainder();
Top(2) = Top(1);
Top(1) = Value_Register;
}
Value_Register = Top(2);
Pop(2);
}
Public void Fixnum_LCM()
{
/* LCM(a,b) = (a*b)/GCD(a,b) */
Fixnum_Multiply();
Push(Value_Register);
Push(Top(3));
Push(Top(3));
Fixnum_GCD();
Push(Value_Register);
Top(2) = Top(4);
Number_Divide();
Push(Value_Register);
Number_Abs();
Pop(5);
}
Public void Fixnum_Floor()
{
Value_Register = Top(1);
}
Public void Fixnum_Ceiling()
{
Value_Register = Top(1);
}
Public void Fixnum_Truncate()
{
Value_Register = Top(1);
}
Public void Fixnum_Round()
{
Value_Register = Top(1);
}
Public void Fixnum_Sqrt()
{
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 Fixnum_Exp()
{
Promote(1, REAL_LEVEL);
Make_Real_Number( exp (Get_Number_Real_Value(Top(1))) );
}
Public void Fixnum_Log()
{
if(Get_Number_Fixnum_Value(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 Fixnum_Expt()
{
Push( Top(2) );
Is_Number_Zero();
Pop(1);
if((Value_Register == The_True_Object) &&
(Get_Number_Fixnum_Value(Top(1)) < 0))
{
Error("Domain error for expt");
}
else if (Get_Number_Fixnum_Value(Top(1)) >= 0 )
{
Integer index = Get_Number_Fixnum_Value( Top(1) );
Make_Fixnum_Number( 1 );
while (index--)
{
Push( Top(2) );
Push( Value_Register );
Number_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 Fixnum_Sin()
{
Promote(1, REAL_LEVEL);
Make_Real_Number( sin (Get_Number_Real_Value(Top(1))) );
}
Public void Fixnum_Cos()
{
Promote(1, REAL_LEVEL);
Make_Real_Number( cos (Get_Number_Real_Value(Top(1))) );
}
Public void Fixnum_Tan()
{
Promote(1, REAL_LEVEL);
Make_Real_Number( tan (Get_Number_Real_Value(Top(1))) );
}
Public void Fixnum_Asin()
{
if( (Get_Number_Fixnum_Value(Top(1)) < -1) ||
(Get_Number_Fixnum_Value(Top(1)) > 1) )
{
Error("Argument to asin must lie between -1 and 1, inclusive");
}
Promote(1, REAL_LEVEL);
Make_Real_Number( asin (Get_Number_Real_Value(Top(1))) );
}
Public void Fixnum_Acos()
{
if( (Get_Number_Fixnum_Value(Top(1)) < -1) ||
(Get_Number_Fixnum_Value(Top(1)) > 1) )
{
Error("Argument to acos must lie between -1 and 1, inclusive");
}
Promote(1, REAL_LEVEL);
Make_Real_Number( acos (Get_Number_Real_Value(Top(1))) );
}
Public void Fixnum_Atan()
{
Promote(1, REAL_LEVEL);
Make_Real_Number( atan (Get_Number_Real_Value(Top(1))) );
}
Public void Fixnum_Atan2()
{
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 Fixnum_Exact_To_Inexact()
{
Make_Real_Number( (double) Get_Number_Fixnum_Value( Top(1) ) );
}
Public void Fixnum_Inexact_To_Exact()
{
Value_Register = Top(1);
}
Public void Fixnum_To_String()
{
Character fixed_string[MAX_CHARS_PER_INT];
Integer radix = Number_To_Integer( Top(1) );
Integer value = Get_Number_Fixnum_Value( Top(2) );
switch ( radix )
{
case 2:
case 8:
case 16:
Make_Constant_String(
Integer_To_Cstring( value , fixed_string , radix , 0 ) );
return;
case 10:
sprintf(fixed_string, "%d", value );
Make_Constant_String( fixed_string );
return;
default:
Display_Error( "Unknown radix : " , Top(1) );
}
}
Public void Fixnum_Make_Rectangular()
{
Make_Complex_Number( (Double) Get_Number_Fixnum_Value(Top(2)),
(Double) Get_Number_Fixnum_Value(Top(1)));
}
Public void Fixnum_Make_Polar()
{
Double mag = Get_Number_Real_Value(Top(2));
Double ang = Get_Number_Real_Value(Top(1));
Make_Complex_Number( (mag) * cos(ang) , (mag) * sin(ang) );
}
Public void Fixnum_Real_Part()
{
Value_Register = Top(1);
}
Public void Fixnum_Imaginary_Part()
{
Make_Fixnum_Number(0);
}
Public void Fixnum_Magnitude()
{
Fixnum_Abs();
}
Public void Fixnum_Angle()
{
Make_Fixnum_Number(0);
}