xref: /openbsd-src/sys/arch/hppa/spmath/dfrem.c (revision c2feb25228e11b3c285a2d9400475896f2dd1562)
1*c2feb252Smickey /*	$OpenBSD: dfrem.c,v 1.5 2002/05/07 22:19:30 mickey Exp $	*/
28a472b3eSmickey /*
3*c2feb252Smickey   (c) Copyright 1986 HEWLETT-PACKARD COMPANY
4*c2feb252Smickey   To anyone who acknowledges that this file is provided "AS IS"
5*c2feb252Smickey   without any express or implied warranty:
6*c2feb252Smickey       permission to use, copy, modify, and distribute this file
7*c2feb252Smickey   for any purpose is hereby granted without fee, provided that
8*c2feb252Smickey   the above copyright notice and this notice appears in all
9*c2feb252Smickey   copies, and that the name of Hewlett-Packard Company not be
10*c2feb252Smickey   used in advertising or publicity pertaining to distribution
11*c2feb252Smickey   of the software without specific, written prior permission.
12*c2feb252Smickey   Hewlett-Packard Company makes no representations about the
13*c2feb252Smickey   suitability of this software for any purpose.
148a472b3eSmickey */
15*c2feb252Smickey /* @(#)dfrem.c: Revision: 1.7.88.1 Date: 93/12/07 15:05:43 */
168a472b3eSmickey 
17*c2feb252Smickey #include "float.h"
18*c2feb252Smickey #include "dbl_float.h"
198a472b3eSmickey 
208a472b3eSmickey /*
218a472b3eSmickey  *  Double Precision Floating-point Remainder
228a472b3eSmickey  */
23b94afd46Smickey int
dbl_frem(srcptr1,srcptr2,dstptr,status)248a472b3eSmickey dbl_frem(srcptr1,srcptr2,dstptr,status)
258a472b3eSmickey 	dbl_floating_point *srcptr1, *srcptr2, *dstptr;
268a472b3eSmickey 	unsigned int *status;
278a472b3eSmickey {
288a472b3eSmickey 	register unsigned int opnd1p1, opnd1p2, opnd2p1, opnd2p2;
298a472b3eSmickey 	register unsigned int resultp1, resultp2;
308a472b3eSmickey 	register int opnd1_exponent, opnd2_exponent, dest_exponent, stepcount;
31628bbdd4Smickey 	register int roundup = FALSE;
328a472b3eSmickey 
338a472b3eSmickey 	Dbl_copyfromptr(srcptr1,opnd1p1,opnd1p2);
348a472b3eSmickey 	Dbl_copyfromptr(srcptr2,opnd2p1,opnd2p2);
358a472b3eSmickey 	/*
368a472b3eSmickey 	 * check first operand for NaN's or infinity
378a472b3eSmickey 	 */
388a472b3eSmickey 	if ((opnd1_exponent = Dbl_exponent(opnd1p1)) == DBL_INFINITY_EXPONENT) {
398a472b3eSmickey 		if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) {
408a472b3eSmickey 			if (Dbl_isnotnan(opnd2p1,opnd2p2)) {
418a472b3eSmickey 				/* invalid since first operand is infinity */
428a472b3eSmickey 				if (Is_invalidtrap_enabled())
438a472b3eSmickey 					return(INVALIDEXCEPTION);
448a472b3eSmickey 				Set_invalidflag();
458a472b3eSmickey 				Dbl_makequietnan(resultp1,resultp2);
468a472b3eSmickey 				Dbl_copytoptr(resultp1,resultp2,dstptr);
478a472b3eSmickey 				return(NOEXCEPTION);
488a472b3eSmickey 			}
498a472b3eSmickey 		}
508a472b3eSmickey 		else {
518a472b3eSmickey 			/*
528a472b3eSmickey 			 * is NaN; signaling or quiet?
538a472b3eSmickey 			 */
548a472b3eSmickey 			if (Dbl_isone_signaling(opnd1p1)) {
558a472b3eSmickey 				/* trap if INVALIDTRAP enabled */
568a472b3eSmickey 				if (Is_invalidtrap_enabled())
578a472b3eSmickey 					return(INVALIDEXCEPTION);
588a472b3eSmickey 				/* make NaN quiet */
598a472b3eSmickey 				Set_invalidflag();
608a472b3eSmickey 				Dbl_set_quiet(opnd1p1);
618a472b3eSmickey 			}
628a472b3eSmickey 			/*
638a472b3eSmickey 			 * is second operand a signaling NaN?
648a472b3eSmickey 			 */
658a472b3eSmickey 			else if (Dbl_is_signalingnan(opnd2p1)) {
668a472b3eSmickey 				/* trap if INVALIDTRAP enabled */
678a472b3eSmickey 				if (Is_invalidtrap_enabled())
688a472b3eSmickey 					return(INVALIDEXCEPTION);
698a472b3eSmickey 				/* make NaN quiet */
708a472b3eSmickey 				Set_invalidflag();
718a472b3eSmickey 				Dbl_set_quiet(opnd2p1);
728a472b3eSmickey 				Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
738a472b3eSmickey 				return(NOEXCEPTION);
748a472b3eSmickey 			}
758a472b3eSmickey 			/*
768a472b3eSmickey 			 * return quiet NaN
778a472b3eSmickey 			 */
788a472b3eSmickey 			Dbl_copytoptr(opnd1p1,opnd1p2,dstptr);
798a472b3eSmickey 			return(NOEXCEPTION);
808a472b3eSmickey 		}
818a472b3eSmickey 	}
828a472b3eSmickey 	/*
838a472b3eSmickey 	 * check second operand for NaN's or infinity
848a472b3eSmickey 	 */
858a472b3eSmickey 	if ((opnd2_exponent = Dbl_exponent(opnd2p1)) == DBL_INFINITY_EXPONENT) {
868a472b3eSmickey 		if (Dbl_iszero_mantissa(opnd2p1,opnd2p2)) {
878a472b3eSmickey 			/*
888a472b3eSmickey 			 * return first operand
898a472b3eSmickey 			 */
908a472b3eSmickey 			Dbl_copytoptr(opnd1p1,opnd1p2,dstptr);
918a472b3eSmickey 			return(NOEXCEPTION);
928a472b3eSmickey 		}
938a472b3eSmickey 		/*
948a472b3eSmickey 		 * is NaN; signaling or quiet?
958a472b3eSmickey 		 */
968a472b3eSmickey 		if (Dbl_isone_signaling(opnd2p1)) {
978a472b3eSmickey 			/* trap if INVALIDTRAP enabled */
988a472b3eSmickey 			if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
998a472b3eSmickey 			/* make NaN quiet */
1008a472b3eSmickey 			Set_invalidflag();
1018a472b3eSmickey 			Dbl_set_quiet(opnd2p1);
1028a472b3eSmickey 		}
1038a472b3eSmickey 		/*
1048a472b3eSmickey 		 * return quiet NaN
1058a472b3eSmickey 		 */
1068a472b3eSmickey 		Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
1078a472b3eSmickey 		return(NOEXCEPTION);
1088a472b3eSmickey 	}
1098a472b3eSmickey 	/*
1108a472b3eSmickey 	 * check second operand for zero
1118a472b3eSmickey 	 */
1128a472b3eSmickey 	if (Dbl_iszero_exponentmantissa(opnd2p1,opnd2p2)) {
1138a472b3eSmickey 		/* invalid since second operand is zero */
1148a472b3eSmickey 		if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
1158a472b3eSmickey 		Set_invalidflag();
1168a472b3eSmickey 		Dbl_makequietnan(resultp1,resultp2);
1178a472b3eSmickey 		Dbl_copytoptr(resultp1,resultp2,dstptr);
1188a472b3eSmickey 		return(NOEXCEPTION);
1198a472b3eSmickey 	}
1208a472b3eSmickey 
1218a472b3eSmickey 	/*
1228a472b3eSmickey 	 * get sign of result
1238a472b3eSmickey 	 */
1248a472b3eSmickey 	resultp1 = opnd1p1;
1258a472b3eSmickey 
1268a472b3eSmickey 	/*
1278a472b3eSmickey 	 * check for denormalized operands
1288a472b3eSmickey 	 */
1298a472b3eSmickey 	if (opnd1_exponent == 0) {
1308a472b3eSmickey 		/* check for zero */
1318a472b3eSmickey 		if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) {
1328a472b3eSmickey 			Dbl_copytoptr(opnd1p1,opnd1p2,dstptr);
1338a472b3eSmickey 			return(NOEXCEPTION);
1348a472b3eSmickey 		}
1358a472b3eSmickey 		/* normalize, then continue */
1368a472b3eSmickey 		opnd1_exponent = 1;
1378a472b3eSmickey 		Dbl_normalize(opnd1p1,opnd1p2,opnd1_exponent);
1388a472b3eSmickey 	}
1398a472b3eSmickey 	else {
1408a472b3eSmickey 		Dbl_clear_signexponent_set_hidden(opnd1p1);
1418a472b3eSmickey 	}
1428a472b3eSmickey 	if (opnd2_exponent == 0) {
1438a472b3eSmickey 		/* normalize, then continue */
1448a472b3eSmickey 		opnd2_exponent = 1;
1458a472b3eSmickey 		Dbl_normalize(opnd2p1,opnd2p2,opnd2_exponent);
1468a472b3eSmickey 	}
1478a472b3eSmickey 	else {
1488a472b3eSmickey 		Dbl_clear_signexponent_set_hidden(opnd2p1);
1498a472b3eSmickey 	}
1508a472b3eSmickey 
1518a472b3eSmickey 	/* find result exponent and divide step loop count */
1528a472b3eSmickey 	dest_exponent = opnd2_exponent - 1;
1538a472b3eSmickey 	stepcount = opnd1_exponent - opnd2_exponent;
1548a472b3eSmickey 
1558a472b3eSmickey 	/*
1568a472b3eSmickey 	 * check for opnd1/opnd2 < 1
1578a472b3eSmickey 	 */
1588a472b3eSmickey 	if (stepcount < 0) {
1598a472b3eSmickey 		/*
1608a472b3eSmickey 		 * check for opnd1/opnd2 > 1/2
1618a472b3eSmickey 		 *
1628a472b3eSmickey 		 * In this case n will round to 1, so
1638a472b3eSmickey 		 *    r = opnd1 - opnd2
1648a472b3eSmickey 		 */
1658a472b3eSmickey 		if (stepcount == -1 &&
1668a472b3eSmickey 		    Dbl_isgreaterthan(opnd1p1,opnd1p2,opnd2p1,opnd2p2)) {
1678a472b3eSmickey 			/* set sign */
1688a472b3eSmickey 			Dbl_allp1(resultp1) = ~Dbl_allp1(resultp1);
1698a472b3eSmickey 			/* align opnd2 with opnd1 */
1708a472b3eSmickey 			Dbl_leftshiftby1(opnd2p1,opnd2p2);
1718a472b3eSmickey 			Dbl_subtract(opnd2p1,opnd2p2,opnd1p1,opnd1p2,
1728a472b3eSmickey 			 opnd2p1,opnd2p2);
1738a472b3eSmickey 			/* now normalize */
1748a472b3eSmickey 			while (Dbl_iszero_hidden(opnd2p1)) {
1758a472b3eSmickey 				Dbl_leftshiftby1(opnd2p1,opnd2p2);
1768a472b3eSmickey 				dest_exponent--;
1778a472b3eSmickey 			}
1788a472b3eSmickey 			Dbl_set_exponentmantissa(resultp1,resultp2,opnd2p1,opnd2p2);
1798a472b3eSmickey 			goto testforunderflow;
1808a472b3eSmickey 		}
1818a472b3eSmickey 		/*
1828a472b3eSmickey 		 * opnd1/opnd2 <= 1/2
1838a472b3eSmickey 		 *
1848a472b3eSmickey 		 * In this case n will round to zero, so
1858a472b3eSmickey 		 *    r = opnd1
1868a472b3eSmickey 		 */
1878a472b3eSmickey 		Dbl_set_exponentmantissa(resultp1,resultp2,opnd1p1,opnd1p2);
1888a472b3eSmickey 		dest_exponent = opnd1_exponent;
1898a472b3eSmickey 		goto testforunderflow;
1908a472b3eSmickey 	}
1918a472b3eSmickey 
1928a472b3eSmickey 	/*
1938a472b3eSmickey 	 * Generate result
1948a472b3eSmickey 	 *
1958a472b3eSmickey 	 * Do iterative subtract until remainder is less than operand 2.
1968a472b3eSmickey 	 */
1978a472b3eSmickey 	while (stepcount-- > 0 && (Dbl_allp1(opnd1p1) || Dbl_allp2(opnd1p2))) {
1988a472b3eSmickey 		if (Dbl_isnotlessthan(opnd1p1,opnd1p2,opnd2p1,opnd2p2)) {
1998a472b3eSmickey 			Dbl_subtract(opnd1p1,opnd1p2,opnd2p1,opnd2p2,opnd1p1,opnd1p2);
2008a472b3eSmickey 		}
2018a472b3eSmickey 		Dbl_leftshiftby1(opnd1p1,opnd1p2);
2028a472b3eSmickey 	}
2038a472b3eSmickey 	/*
2048a472b3eSmickey 	 * Do last subtract, then determine which way to round if remainder
2058a472b3eSmickey 	 * is exactly 1/2 of opnd2
2068a472b3eSmickey 	 */
2078a472b3eSmickey 	if (Dbl_isnotlessthan(opnd1p1,opnd1p2,opnd2p1,opnd2p2)) {
2088a472b3eSmickey 		Dbl_subtract(opnd1p1,opnd1p2,opnd2p1,opnd2p2,opnd1p1,opnd1p2);
2098a472b3eSmickey 		roundup = TRUE;
2108a472b3eSmickey 	}
2118a472b3eSmickey 	if (stepcount > 0 || Dbl_iszero(opnd1p1,opnd1p2)) {
2128a472b3eSmickey 		/* division is exact, remainder is zero */
2138a472b3eSmickey 		Dbl_setzero_exponentmantissa(resultp1,resultp2);
2148a472b3eSmickey 		Dbl_copytoptr(resultp1,resultp2,dstptr);
2158a472b3eSmickey 		return(NOEXCEPTION);
2168a472b3eSmickey 	}
2178a472b3eSmickey 
2188a472b3eSmickey 	/*
2198a472b3eSmickey 	 * Check for cases where opnd1/opnd2 < n
2208a472b3eSmickey 	 *
2218a472b3eSmickey 	 * In this case the result's sign will be opposite that of
2228a472b3eSmickey 	 * opnd1.  The mantissa also needs some correction.
2238a472b3eSmickey 	 */
2248a472b3eSmickey 	Dbl_leftshiftby1(opnd1p1,opnd1p2);
2258a472b3eSmickey 	if (Dbl_isgreaterthan(opnd1p1,opnd1p2,opnd2p1,opnd2p2)) {
2268a472b3eSmickey 		Dbl_invert_sign(resultp1);
2278a472b3eSmickey 		Dbl_leftshiftby1(opnd2p1,opnd2p2);
2288a472b3eSmickey 		Dbl_subtract(opnd2p1,opnd2p2,opnd1p1,opnd1p2,opnd1p1,opnd1p2);
2298a472b3eSmickey 	}
2308a472b3eSmickey 	/* check for remainder being exactly 1/2 of opnd2 */
2318a472b3eSmickey 	else if (Dbl_isequal(opnd1p1,opnd1p2,opnd2p1,opnd2p2) && roundup) {
2328a472b3eSmickey 		Dbl_invert_sign(resultp1);
2338a472b3eSmickey 	}
2348a472b3eSmickey 
2358a472b3eSmickey 	/* normalize result's mantissa */
2368a472b3eSmickey 	while (Dbl_iszero_hidden(opnd1p1)) {
2378a472b3eSmickey 		dest_exponent--;
2388a472b3eSmickey 		Dbl_leftshiftby1(opnd1p1,opnd1p2);
2398a472b3eSmickey 	}
2408a472b3eSmickey 	Dbl_set_exponentmantissa(resultp1,resultp2,opnd1p1,opnd1p2);
2418a472b3eSmickey 
2428a472b3eSmickey 	/*
2438a472b3eSmickey 	 * Test for underflow
2448a472b3eSmickey 	 */
2458a472b3eSmickey     testforunderflow:
2468a472b3eSmickey 	if (dest_exponent <= 0) {
2478a472b3eSmickey 		/* trap if UNDERFLOWTRAP enabled */
2488a472b3eSmickey 		if (Is_underflowtrap_enabled()) {
2498a472b3eSmickey 			/*
2508a472b3eSmickey 			 * Adjust bias of result
2518a472b3eSmickey 			 */
2528a472b3eSmickey 			Dbl_setwrapped_exponent(resultp1,dest_exponent,unfl);
2538a472b3eSmickey 			/* frem is always exact */
2548a472b3eSmickey 			Dbl_copytoptr(resultp1,resultp2,dstptr);
2558a472b3eSmickey 			return(UNDERFLOWEXCEPTION);
2568a472b3eSmickey 		}
2578a472b3eSmickey 		/*
2588a472b3eSmickey 		 * denormalize result or set to signed zero
2598a472b3eSmickey 		 */
2608a472b3eSmickey 		if (dest_exponent >= (1 - DBL_P)) {
2618a472b3eSmickey 			Dbl_rightshift_exponentmantissa(resultp1,resultp2,
2628a472b3eSmickey 			 1-dest_exponent);
2638a472b3eSmickey 		}
2648a472b3eSmickey 		else {
2658a472b3eSmickey 			Dbl_setzero_exponentmantissa(resultp1,resultp2);
2668a472b3eSmickey 		}
2678a472b3eSmickey 	}
2688a472b3eSmickey 	else Dbl_set_exponent(resultp1,dest_exponent);
2698a472b3eSmickey 	Dbl_copytoptr(resultp1,resultp2,dstptr);
2708a472b3eSmickey 	return(NOEXCEPTION);
2718a472b3eSmickey }
272