DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T m

⟦378645a98⟧ TextFile

    Length: 6992 (0x1b50)
    Types: TextFile
    Names: »mf_arith.BSD4_n.c«

Derivation

└─⟦060c9c824⟧ Bits:30007080 DKUUG TeX 2/12/89
    └─⟦this⟧ »./tex82/Unsupported/MFpxl/mflib/mf_arith.BSD4_n.c« 
└─⟦52210d11f⟧ Bits:30007239 EUUGD2: TeX 3 1992-12
    └─⟦beba6c409⟧ »unix3.0/Unsupported.tar.Z« 
        └─⟦25c524ae4⟧ 
            └─⟦this⟧ »Unsupported/MFpxl/mflib/mf_arith.BSD4_n.c« 

TextFile

#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.				}
 *
 */

#include "h00vars.h"
#include "mftypes.h"

extern	bool	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 makefraction(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 takefraction(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 makefraction(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 takefraction(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 makefraction(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 takefraction(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