|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T m
Length: 7001 (0x1b59) Types: TextFile Names: »mf_arith.c«
└─⟦060c9c824⟧ Bits:30007080 DKUUG TeX 2/12/89 └─⟦this⟧ »./tex82/cmf/MFlib/mf_arith.c«
#ifndef lint static char RCSid[] = "$Header: mf_arith.c,v 1.0 86/01/31 14:59:11 richards Released $"; #endif /* * mf_arith.c -- optimized arithmetic routines for UNIX METAFONT 84 * * These functions account for a significant percentage of the processing * time used by METAFONT, and have been recoded in assembly language for * some classes of machines. * * User BEWARE! These codings make assumptions as to how the Pascal * compiler passes arguments to external subroutines, which should not * be ignored if you take this code to a different environment than * it was originally designed and tested on! You have been warned! * * function makefraction(p, q: integer): fraction; * { Calculate the function floor( (p * 2^28) / q + 0.5 ) } * { if both p and q are positive. If not, then the value } * { of makefraction is calculated as though both *were* } * { positive, then the result sign adjusted. } * { (e.g. makefraction ALWAYS rounds away from zero) } * { In case of an overflow, return the largest possible } * { value (2^32-1) with the correct sign, and set global } * { variable "aritherror" to 1. Note that -2^32 is } * { considered to be an illegal product for this type of } * { arithmetic! } * * function takefraction(f: fraction; q: integer): integer; * { Calculate the function floor( (p * q) / 2^28 + 0.5 ) } * { takefraction() rounds in a similar manner as } * { makefraction() above. } * */ #define EXTERN extern #include "../mfd.h" extern boolean aritherror; /* to be set on overflow */ #define EL_GORDO 0x7fffffff /* 2^31-1 */ #define FRACTION_ONE 0x10000000 /* 2^28 */ #define FRACTION_HALF 0x08000000 /* 2^27 */ #define FRACTION_FOUR 0x40000000 /* 2^30 */ #if defined(VAX4_2) || defined(VAX4_3) || defined(PYRAMID) #if defined(VAX4_2) || defined(VAX4_3) /* * DEC VAX-11 class systems running 4.2 or 4.3 BSD Unix and Berkeley PC * * In the VAX assembler code that follows, remember, REMEMBER that * a quad result addressed in Rn has most significant longword * in Rn+1, NOT Rn! */ fraction zmakefraction(p, q) integer p, q; { register r11; asm(" movl 8(ap),r0 "); /* q */ asm(" xorl3 4(ap),r0,r11 "); /* sign of prod */ asm(" jgeq Lmf1 "); asm(" mnegl r0,r0 "); /* abs(q)*sign(p) */ asm("Lmf1: "); asm(" divl2 $2,r0 "); /* div 2 (signed) */ asm(" emul 4(ap),$0x10000000,r0,r0 "); /* p*2^28+(sign(p)*(q/2)) */ asm(" ediv 8(ap),r0,r0,r1 "); /*((p*2^28)+ */ asm(" jvs Lmf2 "); /* sign(p)*(q/2))/q */ asm(" mnegl r0,r1 "); /* check for 2^32 */ asm(" jvc Lmf3 "); asm("Lmf2: "); asm(" movl $1,_aritherror "); asm(" movl $0x7fffffff,r0 "); /* EL_GORDO */ asm(" tstl r11 "); asm(" jgeq Lmf3 "); asm(" mnegl r0,r0 "); asm("Lmf3: "); asm(" ret "); } integer ztakefraction(q, f) integer q; fraction f; { register r11; asm(" movl $0x8000000,r0 "); /* 2^27 */ asm(" xorl3 4(ap),8(ap),r11 "); /* sign of prod */ asm(" jgeq Ltf1 "); asm(" mnegl r0,r0 "); /* 2^27*sgn(prod) */ asm("Ltf1: "); asm(" emul 4(ap),8(ap),r0,r0 "); /* q*f+sgn(prod)*2^27 */ asm(" ediv $0x10000000,r0,r0,r1 "); /* div 2^28 (signed!) */ asm(" jvs Ltf2 "); asm(" mnegl r0,r1 "); /* check for -2^32 */ asm(" jvc Ltf3 "); asm("Ltf2: "); asm(" movl $1,_aritherror "); asm(" movl $0x7fffffff,r0 "); /* EL_GORDO */ asm(" tstl r11 "); asm(" jgeq Ltf3 "); asm(" mnegl r0,r0 "); asm("Ltf3: "); asm(" ret "); } #endif VAX #if defined(PYRAMID) /* * Pyramid 90x class of machines, running Pyramid's PASCAL */ fraction zmakefraction(p, q) integer p, q; { asm(" movw $0,lr0 "); /* high word of 64 bit accum */ asm(" mabsw pr0,lr1 "); /* lr1 = abs(p) */ asm(" mabsw pr1,lr2 "); /* lr2 = abs(q) */ asm(" ashll $29,lr0 "); /* lr0'lr1 = abs(p)*2^29 */ asm(" addw lr2,lr1 "); /* abs(p)*2^29 + abs(q) */ asm(" addwc $0,lr0 "); asm(" ashrl $1,lr0 "); /* (abs(p)*2^28 + abs(q/2)) */ asm(" ediv lr2,lr0 "); /* (abs(p)*2^28 / abs(q)) + .5 */ asm(" bvc L1 "); asm(" movw $1,_aritherror "); asm(" movw $0x7fffffff,lr0 "); /* EL_GORDO */ asm("L1: "); asm(" xorw pr0,pr1 "); /* determine sign of result */ asm(" blt L2 "); asm(" movw lr0,pr0 "); asm(" ret "); asm("L2: "); asm(" mnegw lr0,pr0 "); /* negative */ asm(" ret "); } integer ztakefraction(q, f) integer q; fraction f; { asm(" movw $0,lr0 "); /* high word of 64 bit accum */ asm(" mabsw pr0,lr1 "); /* lr1 = abs(q) */ asm(" mabsw pr1,lr2 "); /* lr2 = abs(f) */ asm(" emul lr2,lr0 "); /* lr0'lr1 = abs(q) * abs(f) */ asm(" addw $0x08000000,lr1 "); /* (abs(q)*abs(f))+2^27 */ asm(" addwc $0,lr0 "); asm(" ashll $4,lr0 "); /* lr0=(abs(q)*abs(f))/2^28 + .5 */ asm(" bvc L3 "); asm(" movw $1,_aritherror "); asm(" movw $0x7fffffff,lr0 "); /* EL_GORDO */ asm("L3: "); asm(" xorw pr0,pr1 "); /* construct sign of product */ asm(" blt L4 "); asm(" movw lr0,pr0 "); asm(" ret "); asm("L4: "); asm(" mnegw lr0,pr0 "); /* negative */ asm(" ret "); } #endif PYRAMID #else /* * Generic Routines for other machine classes: * * essentially a verbatim copy of the WEB * routines, with the hope that the C compiler * may do better than the Pascal on code quality. */ fraction zmakefraction(p, q) register integer p, q; { int negative; register int be_careful; register fraction f; int n; if (p < 0) { negative = 1; p = -p; } else negative = 0; if (q < 0) { negative = !negative; q = -q; } n = p / q; p = p % q; if (n >= 8) { aritherror = true; return (negative? -EL_GORDO : EL_GORDO); } n = (n-1)*FRACTION_ONE; f = 1; do { be_careful = p - q; p = be_careful + p; if (p >= 0) { f = f + f + 1; } else { f <<= 1; p += q; } } while (f < FRACTION_ONE); be_careful = p - q; if ((be_careful + p) >= 0) f += 1; return (negative? -(f+n) : (f+n)); } integer ztakefraction(q, f) register integer q; register fraction f; { int n, negative; register int p, be_careful; if (f < 0) { negative = 1; f = -f; } else negative = 0; if (q < 0) { negative = !negative; q = -q; } if (f < FRACTION_ONE) n = 0; else { n = f / FRACTION_ONE; f = f % FRACTION_ONE; if (q < (EL_GORDO / n)) n = n * q; else { aritherror = true; n = EL_GORDO; } } f += FRACTION_ONE; p = FRACTION_HALF; if (q < FRACTION_FOUR) do { if (f & 0x1) p = (p+q) >> 1; else p >>= 1; f >>= 1; } while (f > 1); else do { if (f & 0x1) p = p + ((q-p) >> 1); else p >>= 1; f >>= 1; } while (f > 1); be_careful = n - EL_GORDO; if ((be_careful + p) > 0) { aritherror = true; n = EL_GORDO - p; } return(negative? -(n+p) : (n+p)); } #endif VAX4_2