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