! longint.h - support for signed and unsigned 4 byte integers in Inform. ! ! Mainly by Chris Hall - c@pobox.co.uk. ! Signed integer support by Francis Irving - francis@pobox.co.uk. ! 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: ! ab 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: ! ab 1 ! a==b 0); ! Works for unsigned longs only. [LongUnsignCompare a b; if(a->00) return(-1); if(a->0>b->0) rtrue; if(a->11) return(-1); if(a->1>b->1) rtrue; if(a->22) return(-1); if(a->2>b->2) rtrue; if(a->33) 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); ];