186 lines
		
	
	
	
		
			4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			186 lines
		
	
	
	
		
			4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
  (c) copyright 1988 by the Vrije Universiteit, Amsterdam, The Netherlands.
 | 
						|
  See the copyright notice in the ACK home directory, in the file "Copyright".
 | 
						|
*/
 | 
						|
 | 
						|
/* $Header$ */
 | 
						|
 | 
						|
/*
 | 
						|
#define	PRT_EXT
 | 
						|
#define	PRT_ALL
 | 
						|
	DIVIDE EXTENDED FORMAT
 | 
						|
*/
 | 
						|
 | 
						|
#include "FP_bias.h"
 | 
						|
#include "FP_trap.h"
 | 
						|
#include "FP_types.h"
 | 
						|
 | 
						|
/*
 | 
						|
	November 15, 1984
 | 
						|
 | 
						|
	This is a routine to do the work.
 | 
						|
	It is based on the partial products method
 | 
						|
	and makes no use possible machine instructions
 | 
						|
	to divide (hardware dividers).	It is intended
 | 
						|
	that it be rewritten to do so, but expedieancy
 | 
						|
	requires that something be written NOW - and
 | 
						|
	this is it.
 | 
						|
*/
 | 
						|
/********************************************************/
 | 
						|
 | 
						|
div_ext(e1,e2)
 | 
						|
EXTEND	*e1,*e2;
 | 
						|
{
 | 
						|
			short	count;
 | 
						|
			short	error = 0;
 | 
						|
			unsigned long	result[2];
 | 
						|
	register	unsigned long	*lp;
 | 
						|
 | 
						|
#ifdef	PRT_EXT
 | 
						|
	fprintf("stderr:start div_ext:\n");
 | 
						|
	prt_ext("dividend:",e1);
 | 
						|
	prt_ext("divisor :",e2);
 | 
						|
#endif
 | 
						|
	if ((e1->m1 | e1->m2) == 0) {	/* 0 / anything == 0 */
 | 
						|
		e1->exp = 0;	/* make sure */
 | 
						|
		return;
 | 
						|
	}
 | 
						|
	/*
 | 
						|
	 * numbers are right shifted one bit to make sure
 | 
						|
	 * that m1 is quaranteed to be larger if its
 | 
						|
	 * maximum bit is set
 | 
						|
	 */
 | 
						|
	b64_sft(&e1->m1,1);	/* 64 bit shift right */
 | 
						|
	b64_sft(&e2->m1,1);	/* 64 bit shift right */
 | 
						|
	e1->exp++;
 | 
						|
	e2->exp++;
 | 
						|
	/*	check for underflow, divide by zero, etc	*/
 | 
						|
	e1->sign ^= e2->sign;
 | 
						|
	e1->exp -= e2->exp;
 | 
						|
	e1->exp += 2;		/* bias correction	*/
 | 
						|
	if (e1->exp < EXT_MIN)	{
 | 
						|
		error++;
 | 
						|
#ifdef	PRT_EXT
 | 
						|
		prt_ext("DIV_EXT UNDERFLOW",e1);
 | 
						|
#endif	PRT_EXT
 | 
						|
		trap(EFUNFL);	/* underflow */
 | 
						|
		e1->exp = EXT_MIN;
 | 
						|
		e1->m1 = e1->m2 = 0L;
 | 
						|
	}
 | 
						|
	if ((e2->m1 | e2->m2) == 0) {
 | 
						|
		error++;
 | 
						|
#ifdef	PRT_EXT
 | 
						|
		prt_ext("DIV_EXT DIV 0.0",e2);
 | 
						|
#endif	PRT_EXT
 | 
						|
		trap(EFDIVZ);
 | 
						|
		e1->m1 = e1->m2 = 0L;
 | 
						|
		e1->exp = EXT_MAX;
 | 
						|
	}
 | 
						|
	if (error)
 | 
						|
		return;
 | 
						|
 | 
						|
		/* do division of mantissas	*/
 | 
						|
		/* uses partial product method	*/
 | 
						|
		/* init control variables	*/
 | 
						|
 | 
						|
	count = 64;
 | 
						|
	lp = result;	/* result[0] == high word	*/
 | 
						|
			/* result[0] == low  word	*/
 | 
						|
	*lp++ = 0L;		/* high word	*/
 | 
						|
	*lp-- = 0L;		/* low word	*/
 | 
						|
 | 
						|
		/* partial product division loop */
 | 
						|
 | 
						|
	while (count--)	{
 | 
						|
		/* first left shift result 1 bit	*/
 | 
						|
		/* this is ALWAYS done			*/
 | 
						|
 | 
						|
		b64_sft(result,-1);
 | 
						|
 | 
						|
		/* compare dividend and divisor		*/
 | 
						|
		/* if dividend >= divisor add a bit	*/
 | 
						|
		/* and subtract divisior from dividend	*/
 | 
						|
#ifdef	PRT_ALL
 | 
						|
	prt_ext("dividend:",e1);
 | 
						|
	prt_ext("divisor :",e2);
 | 
						|
#endif
 | 
						|
 | 
						|
		if ( (e1->m1 < e2->m1) ||
 | 
						|
			((e1->m1 == e2->m1) && (e1->m2 < e2->m2) ))
 | 
						|
			;	/* null statement */
 | 
						|
				/* i.e., don't add or subtract */
 | 
						|
		else	{
 | 
						|
			result[1]++;	/* ADD	*/
 | 
						|
			if (e2->m2 > e1->m2)
 | 
						|
				e1->m1 -= 1;	/* carry in */
 | 
						|
			e1->m1 -= e2->m1;	/* do SUBTRACTION */
 | 
						|
			e1->m2 -= e2->m2;	/*    SUBTRACTION */
 | 
						|
#ifdef	PRT_ALL
 | 
						|
	prt_ext("result  :",e1);
 | 
						|
#endif
 | 
						|
		}
 | 
						|
#ifdef	PRT_ALL
 | 
						|
	fprintf(stderr,"div_ext %d %08X%08X\n\n",64-count,
 | 
						|
		result[0],result[1]);
 | 
						|
	fflush(stderr);
 | 
						|
#endif
 | 
						|
 | 
						|
		/*	shift dividend left one bit OR	*/
 | 
						|
		/*	IF it equals ZERO we can break out	*/
 | 
						|
		/*	of the loop, but still must shift	*/
 | 
						|
		/*	the quotient the remaining count bits	*/
 | 
						|
		/* NB	save the results of this test in error	*/
 | 
						|
		/*	if not zero, then the result is inexact. */
 | 
						|
		/* 	this would be reported in IEEE standard	*/
 | 
						|
 | 
						|
		/*	lp points to dividend			*/
 | 
						|
		lp = &e1->m1;
 | 
						|
 | 
						|
		error = ((*lp | *(lp+1)) != 0L) ? 1 : 0;
 | 
						|
		if (error)	{	/* more work */
 | 
						|
			/*	assume max bit == 0 (see above)	*/
 | 
						|
			b64_sft(&e1->m1,-1);
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
		else
 | 
						|
			break;	/* leave loop	*/
 | 
						|
	}	/* end of divide by subtraction loop	*/
 | 
						|
 | 
						|
	/*	DISPLAY RESULTS FOR DEBUGGING		*/
 | 
						|
#ifdef	PRT_ALL
 | 
						|
	prt_ext("dividend:",e1);
 | 
						|
	prt_ext("divisor :",e2);
 | 
						|
	fprintf(stderr,"div_ext %d %08X%08X\n",64-count,
 | 
						|
		result[0],result[1]);
 | 
						|
#endif
 | 
						|
 | 
						|
	if (count > 0)	{
 | 
						|
		lp = result;
 | 
						|
		if (count > 31) {	/* move to higher word */
 | 
						|
			*lp = *(lp+1);
 | 
						|
			count -= 32;
 | 
						|
			*(lp+1) = 0L;	/* clear low word	*/
 | 
						|
		}
 | 
						|
		if (*lp)
 | 
						|
			*lp <<= count;	/* shift rest of way	*/
 | 
						|
		lp++;	/*  == &result[1]	*/
 | 
						|
		if (*lp) {
 | 
						|
			result[0] |= (*lp >> 32-count);
 | 
						|
			*lp <<= count;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	/*
 | 
						|
	if (error)
 | 
						|
		INEXACT();
 | 
						|
	*/
 | 
						|
	e1->m1 = result[0];
 | 
						|
	e1->m2 = result[1];
 | 
						|
#ifdef	PRT_EXT
 | 
						|
	prt_ext("result  :",e1);
 | 
						|
#endif
 | 
						|
	nrm_ext(e1);
 | 
						|
#ifdef	PRT_EXT
 | 
						|
	prt_ext("after nrm:",e1);
 | 
						|
	/*sleep(4);*/
 | 
						|
#endif
 | 
						|
}
 |