! longint.h - support for signed and unsigned 4 byte integers in Inform.
!
! Mainly by Chris Hall -
[email protected].
! Signed integer support by Francis Irving -
[email protected].
! Please email us with any errors, omissions or if you've
! found this code useful.
!
! For example use of this module, see longint.inf, which should be
! available from the same place you got this file.
!
! For a complete Inform program using this module see
!
http://www.meta.demon.co.uk/zbefunge.html
!
! (If you need to edit this file, note that indentations are 4 spaces
! and tabs are not used.)
!
! This source code is distributed free, but remains
! Copyright 1997-1998 Chris Hall and Francis Irving. Release 1.
System_file;
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! Functions beginning "LongSign" work on signed integers.
! Functions beginning "LongUnsign" work on unsigned integers.
! Functions beginning "Long" are generally applicable.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! Printing.
Array _LongNegTemp0->4;
Array _LongNegTemp1->4;
! Print a signed long. Use by writing "print (longsign)x;".
[longsign n;
LongSignOutputAsChars(n, LongPrintChar);
];
! Print an unsigned long. Use by writing "print (longunsign)x;".
[longunsign n;
LongUnsignOutputAsChars(n, LongPrintChar);
];
! Generalised printing.
! This takes "n" and outputs it a character at
! a time, calling function "fn". Returns the length
! in characters.
[LongSignOutputAsChars n fn
len;
len = 0;
if (LongSignIsNeg(n))
{
indirect(fn, '-');
++len;
}
LongSignAbsAssign(_LongNegTemp0, n);
len = len + LongNum4(_LongNegTemp0->0,_LongNegTemp0->1,_LongNegTemp0->2,_LongNegTemp0->3, fn);
return len;
];
! As signed version above.
[LongUnsignOutputAsChars n fn
len;
len = LongNum4(n->0,n->1,n->2,n->3, fn);
return len;
];
! Internal function.
[LongPrintChar ch;
print (char)ch;
];
! Internal function.
[LongNum4 a b c d fn
l len;
len = 0;
b=b+256*(a%10); a=a/10;
c=c+256*(b%10); b=b/10;
d=d+256*(c%10); c=c/10;
l=d%10; d=d/10;
if(a||b||c||d)
{
len = len + LongNum4(a,b,c,d, fn);
}
indirect(fn, '0'+l);
++len;
return len;
];
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! Simple testing and assigning
! Test to see if a signed long is negative.
[LongSignIsNeg a;
if ((a->0)&$80)
rtrue;
else
rfalse;
];
! Test to see if long is zero. Signed or unsigned.
[LongIsZero a;
if ((a->0 == 0) && (a->1 == 0) && (a->2 == 0) && (a->3 == 0))
rtrue;
else
rfalse;
];
! Sets values into a signed or unsigned long.
! The appropriate encoding is left up to the caller:
! 1. We store our longs in big-endian (most significant first) order.
! 2. a&$80 is non-zero for negative signed integers.
! You might want to call this with parameters (0, 0, 0, x) to
! set a value from 0 to 255. Then use LongSignNegAssign to
! make it negative.
[LongSet l a b c d; ! l=((a*256+b)*256+c)*256+d
l->0=a;
l->1=b;
l->2=c;
l->3=d;
];
! Copy either a signed or unsigned long.
[LongAssign d s; ! d=s
d->0=s->0;
d->1=s->1;
d->2=s->2;
d->3=s->3;
];
! d=-s d and s can be the same variable
[LongSignNegAssign d s
t;
LongAssign(d, s);
LongNot(d);
t=d->3+1; d->3=t%256;
t=d->2+t/256; d->2=t%256;
t=d->1+t/256; d->1=t%256;
t=d->0+t/256; d->0=t%256;
];
! d=positive part of s
[LongSignAbsAssign d s;
if (LongSignIsNeg(s))
LongSignNegAssign(d, s);
else
LongAssign(d, s);
];
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! Addition and subtraction.
! r=a+b; (r may be same variable as a or b)
! Works for signed or unsigned longs.
[LongAdd r a b
t;
t=a->3+b->3; r->3=t%256;
t=a->2+b->2+t/256; r->2=t%256;
t=a->1+b->1+t/256; r->1=t%256;
t=a->0+b->0+t/256; r->0=t%256;
];
! r=a-b; (r may be same variable as a or b)
! Works for signed or unsigned longs.
[LongSub r a b
t;
t=256+a->3-b->3; r->3=t%256;
t=256+a->2-b->2-(t<256); r->2=t%256;
t=256+a->1-b->1-(t<256); r->1=t%256;
t=256+a->0-b->0-(t<256); r->0=t%256;
];
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! Multiplication and division.
! r=a*b; (r may _not_ be same variable as a or b)
! Works for signed or unsigned longs. Note that the
! destination variable must be a different variable
! from both of the source variables.
[LongMul r a b
t;
t=(a->3%16)*(b->3%16); r->3=t%16;
t=(a->3%16)*(b->3/16)
+(a->3/16)*(b->3%16)+t/16; r->3=r->3+16*(t%16);
t=(a->3%16)*(b->2%16)
+(a->3/16)*(b->3/16)
+(a->2%16)*(b->3%16)+t/16; r->2=t%16;
t=(a->3%16)*(b->2/16)
+(a->3/16)*(b->2%16)
+(a->2%16)*(b->3/16)
+(a->2/16)*(b->3%16)+t/16; r->2=r->2+16*(t%16);
t=(a->3%16)*(b->1%16)
+(a->3/16)*(b->2/16)
+(a->2%16)*(b->2%16)
+(a->2/16)*(b->3/16)
+(a->1%16)*(b->3%16)+t/16; r->1=t%16;
t=(a->3%16)*(b->1/16)
+(a->3/16)*(b->1%16)
+(a->2%16)*(b->2/16)
+(a->2/16)*(b->2%16)
+(a->1%16)*(b->3/16)
+(a->1/16)*(b->3%16)+t/16; r->1=r->1+16*(t%16);
t=(a->3%16)*(b->0%16)
+(a->3/16)*(b->1/16)
+(a->2%16)*(b->1%16)
+(a->2/16)*(b->2/16)
+(a->1%16)*(b->2%16)
+(a->1/16)*(b->3/16)
+(a->0%16)*(b->3%16)+t/16; r->0=t%16;
t=(a->3%16)*(b->0/16)
+(a->3/16)*(b->0%16)
+(a->2%16)*(b->1/16)
+(a->2/16)*(b->1%16)+t/16;
t=(a->1%16)*(b->2/16)
+(a->1/16)*(b->2%16)
+(a->0%16)*(b->3/16)
+(a->0/16)*(b->3%16)+t; r->0=r->0+16*(t%16);
];
Array _LongDMTemp0->4;
Array _LongDMTemp1->4;
! d=a/b; m=a%b (d and m may be same variable as a or b)
! Works for unsigned longs only.
[LongUnsignDivMod d m a b
t;
! Division by zero! The user is encouraged to test for this
! himself before calling the various division functions. We
! simply force the interpreter to perform a divide by zero.
if(LongIsZero(b)){a=0;a=a/0;}
LongAssign(_LongDMTemp1,b);
LongAssign(m,a);
d->0=d->1=d->2=d->3=
_LongDMTemp0->0=_LongDMTemp0->1=_LongDMTemp0->2=0; _LongDMTemp0->3=1;
while(LongUnsignLE(_LongDMTemp1,m)){
t=LongShl(_LongDMTemp0);
if (t) break;
LongShl(_LongDMTemp1);
}
for(::){
if(LongShr(_LongDMTemp0,t)) break;
t=0;
if(~~t) LongShr(_LongDMTemp1);
if(LongUnsignLE(_LongDMTemp1,m)){
LongSub(m,m,_LongDMTemp1);
LongAdd(d,d,_LongDMTemp0);
}
}
];
Array _LongDMTemp2->4;
! r=a/b; (r may be same variable as a or b)
! Works for signed longs only.
[LongSignDiv r a b
n;
n = LongNegIndex(a, b,_LongNegTemp0,_LongNegTemp1);
LongUnsignDivMod(r,_LongDMTemp2,_LongNegTemp0,_LongNegTemp1);
LongUseNegIndex(n, r);
];
! r=a%b; (r may be same variable as a or b)
! Works for signed longs only.
[LongSignMod r a b
n;
n = LongNegIndex(a, b,_LongNegTemp0,_LongNegTemp1);
LongUnsignDivMod(_LongDMTemp2,r,_LongNegTemp0,_LongNegTemp1);
LongUseNegIndex(n, r);
];
! Internal function.
! c=abs(a), d= abs(b) if a*b is negative, return that.
[LongNegIndex a b c d;
LongSignAbsAssign(c, a);
LongSignAbsAssign(d, b);
if (LongSignIsNeg(a) ~= LongSignIsNeg(b))
rtrue;
else
rfalse;
];
! Internal function.
! if n true, let r=-r
[ LongUseNegIndex n r;
if (n)
LongSignNegAssign(r, r);
];
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! Comparison.
! Returns:
! a<b -1
! a>b 1
! a==b 0);
! Works for signed longs only.
[LongSignCompare a b;
if (LongSignIsNeg(a) && (~~LongSignIsNeg(b))) return -1;
if ((~~LongSignIsNeg(a)) && LongSignIsNeg(b)) return 1;
if (~~LongSignIsNeg(a))
{
LongSignAbsAssign(_LongNegTemp0, a);
LongSignAbsAssign(_LongNegTemp1, b);
}
else
{
! swap round if they are both negative
LongSignAbsAssign(_LongNegTemp0, b);
LongSignAbsAssign(_LongNegTemp1, a);
}
return LongUnsignCompare(_LongNegTemp0, _LongNegTemp1);
];
! Returns:
! a<b -1
! a>b 1
! a==b 0);
! Works for unsigned longs only.
[LongUnsignCompare a b;
if(a->0<b->0) return(-1);
if(a->0>b->0) rtrue;
if(a->1<b->1) return(-1);
if(a->1>b->1) rtrue;
if(a->2<b->2) return(-1);
if(a->2>b->2) rtrue;
if(a->3<b->3) return(-1);
return(a->3>b->3);
];
! Unsigned versions.
[LongUnsignLT a b; return(LongUnsignCompare(a,b)< 0);]; ! return(a< b);
[LongUnsignLE a b; return(LongUnsignCompare(a,b)<=0);]; ! return(a<=b);
[LongUnsignGT a b; return(LongUnsignCompare(a,b)> 0);]; ! return(a> b);
[LongUnsignGE a b; return(LongUnsignCompare(a,b)>=0);]; ! return(a>=b);
[LongUnsignEQ a b; return(LongUnsignCompare(a,b)==0);]; ! return(a==b);
[LongUnsignNE a b; return(LongUnsignCompare(a,b)~=0);]; ! return(a~=b);
! Signed versions.
[LongSignLT a b; return(LongSignCompare(a,b)< 0);]; ! return(a< b);
[LongSignLE a b; return(LongSignCompare(a,b)<=0);]; ! return(a<=b);
[LongSignGT a b; return(LongSignCompare(a,b)> 0);]; ! return(a> b);
[LongSignGE a b; return(LongSignCompare(a,b)>=0);]; ! return(a>=b);
[LongSignEQ a b; return(LongSignCompare(a,b)==0);]; ! return(a==b);
[LongSignNE a b; return(LongSignCompare(a,b)~=0);]; ! return(a~=b);
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! Bitwise comparisons.
! These bitwise operators aren't really signed or unsigned.
! a=(a<<1+t); return(bit lost off end);
[LongShl a t;
t=a->3*2+t; a->3=t%256;
t=a->2*2+t/256; a->2=t%256;
t=a->1*2+t/256; a->1=t%256;
t=a->0*2+t/256; a->0=t%256;
return(t/256);
];
! a=((a+(t<<32))>>1); return(bit lost off end);
[LongShr a t;
t=a->0+256*t; a->0=t/2;
t=a->1+256*(t%2); a->1=t/2;
t=a->2+256*(t%2); a->2=t/2;
t=a->3+256*(t%2); a->3=t/2;
return(t%2);
];
! a=~a, bitwise not
[LongNot a;
a->0 = ~(a->0);
a->1 = ~(a->1);
a->2 = ~(a->2);
a->3 = ~(a->3);
];