xref: /netbsd-src/sys/arch/hppa/spmath/dfrem.c (revision 274254cdae52594c1aa480a736aef78313d15c9c)
1 /*	$NetBSD: dfrem.c,v 1.4 2007/02/22 05:46:29 thorpej Exp $	*/
2 
3 /*	$OpenBSD: dfrem.c,v 1.4 2001/03/29 03:58:17 mickey Exp $	*/
4 
5 /*
6  * Copyright 1996 1995 by Open Software Foundation, Inc.
7  *              All Rights Reserved
8  *
9  * Permission to use, copy, modify, and distribute this software and
10  * its documentation for any purpose and without fee is hereby granted,
11  * provided that the above copyright notice appears in all copies and
12  * that both the copyright notice and this permission notice appear in
13  * supporting documentation.
14  *
15  * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
16  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
17  * FOR A PARTICULAR PURPOSE.
18  *
19  * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
20  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
21  * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
22  * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
23  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24  *
25  */
26 /*
27  * pmk1.1
28  */
29 /*
30  * (c) Copyright 1986 HEWLETT-PACKARD COMPANY
31  *
32  * To anyone who acknowledges that this file is provided "AS IS"
33  * without any express or implied warranty:
34  *     permission to use, copy, modify, and distribute this file
35  * for any purpose is hereby granted without fee, provided that
36  * the above copyright notice and this notice appears in all
37  * copies, and that the name of Hewlett-Packard Company not be
38  * used in advertising or publicity pertaining to distribution
39  * of the software without specific, written prior permission.
40  * Hewlett-Packard Company makes no representations about the
41  * suitability of this software for any purpose.
42  */
43 
44 #include <sys/cdefs.h>
45 __KERNEL_RCSID(0, "$NetBSD: dfrem.c,v 1.4 2007/02/22 05:46:29 thorpej Exp $");
46 
47 #include "../spmath/float.h"
48 #include "../spmath/dbl_float.h"
49 
50 /*
51  *  Double Precision Floating-point Remainder
52  */
53 int
54 dbl_frem(srcptr1,srcptr2,dstptr,status)
55 
56 dbl_floating_point *srcptr1, *srcptr2, *dstptr;
57 unsigned int *status;
58 {
59 	register unsigned int opnd1p1, opnd1p2, opnd2p1, opnd2p2;
60 	register unsigned int resultp1, resultp2;
61 	register int opnd1_exponent, opnd2_exponent, dest_exponent, stepcount;
62 	register int roundup = false;
63 
64 	Dbl_copyfromptr(srcptr1,opnd1p1,opnd1p2);
65 	Dbl_copyfromptr(srcptr2,opnd2p1,opnd2p2);
66 	/*
67 	 * check first operand for NaN's or infinity
68 	 */
69 	if ((opnd1_exponent = Dbl_exponent(opnd1p1)) == DBL_INFINITY_EXPONENT) {
70 		if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) {
71 			if (Dbl_isnotnan(opnd2p1,opnd2p2)) {
72 				/* invalid since first operand is infinity */
73 				if (Is_invalidtrap_enabled())
74 					return(INVALIDEXCEPTION);
75 				Set_invalidflag();
76 				Dbl_makequietnan(resultp1,resultp2);
77 				Dbl_copytoptr(resultp1,resultp2,dstptr);
78 				return(NOEXCEPTION);
79 			}
80 		}
81 		else {
82 			/*
83 			 * is NaN; signaling or quiet?
84 			 */
85 			if (Dbl_isone_signaling(opnd1p1)) {
86 				/* trap if INVALIDTRAP enabled */
87 				if (Is_invalidtrap_enabled())
88 					return(INVALIDEXCEPTION);
89 				/* make NaN quiet */
90 				Set_invalidflag();
91 				Dbl_set_quiet(opnd1p1);
92 			}
93 			/*
94 			 * is second operand a signaling NaN?
95 			 */
96 			else if (Dbl_is_signalingnan(opnd2p1)) {
97 				/* trap if INVALIDTRAP enabled */
98 				if (Is_invalidtrap_enabled())
99 					return(INVALIDEXCEPTION);
100 				/* make NaN quiet */
101 				Set_invalidflag();
102 				Dbl_set_quiet(opnd2p1);
103 				Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
104 				return(NOEXCEPTION);
105 			}
106 			/*
107 			 * return quiet NaN
108 			 */
109 			Dbl_copytoptr(opnd1p1,opnd1p2,dstptr);
110 			return(NOEXCEPTION);
111 		}
112 	}
113 	/*
114 	 * check second operand for NaN's or infinity
115 	 */
116 	if ((opnd2_exponent = Dbl_exponent(opnd2p1)) == DBL_INFINITY_EXPONENT) {
117 		if (Dbl_iszero_mantissa(opnd2p1,opnd2p2)) {
118 			/*
119 			 * return first operand
120 			 */
121 			Dbl_copytoptr(opnd1p1,opnd1p2,dstptr);
122 			return(NOEXCEPTION);
123 		}
124 		/*
125 		 * is NaN; signaling or quiet?
126 		 */
127 		if (Dbl_isone_signaling(opnd2p1)) {
128 			/* trap if INVALIDTRAP enabled */
129 			if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
130 			/* make NaN quiet */
131 			Set_invalidflag();
132 			Dbl_set_quiet(opnd2p1);
133 		}
134 		/*
135 		 * return quiet NaN
136 		 */
137 		Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
138 		return(NOEXCEPTION);
139 	}
140 	/*
141 	 * check second operand for zero
142 	 */
143 	if (Dbl_iszero_exponentmantissa(opnd2p1,opnd2p2)) {
144 		/* invalid since second operand is zero */
145 		if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
146 		Set_invalidflag();
147 		Dbl_makequietnan(resultp1,resultp2);
148 		Dbl_copytoptr(resultp1,resultp2,dstptr);
149 		return(NOEXCEPTION);
150 	}
151 
152 	/*
153 	 * get sign of result
154 	 */
155 	resultp1 = opnd1p1;
156 
157 	/*
158 	 * check for denormalized operands
159 	 */
160 	if (opnd1_exponent == 0) {
161 		/* check for zero */
162 		if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) {
163 			Dbl_copytoptr(opnd1p1,opnd1p2,dstptr);
164 			return(NOEXCEPTION);
165 		}
166 		/* normalize, then continue */
167 		opnd1_exponent = 1;
168 		Dbl_normalize(opnd1p1,opnd1p2,opnd1_exponent);
169 	}
170 	else {
171 		Dbl_clear_signexponent_set_hidden(opnd1p1);
172 	}
173 	if (opnd2_exponent == 0) {
174 		/* normalize, then continue */
175 		opnd2_exponent = 1;
176 		Dbl_normalize(opnd2p1,opnd2p2,opnd2_exponent);
177 	}
178 	else {
179 		Dbl_clear_signexponent_set_hidden(opnd2p1);
180 	}
181 
182 	/* find result exponent and divide step loop count */
183 	dest_exponent = opnd2_exponent - 1;
184 	stepcount = opnd1_exponent - opnd2_exponent;
185 
186 	/*
187 	 * check for opnd1/opnd2 < 1
188 	 */
189 	if (stepcount < 0) {
190 		/*
191 		 * check for opnd1/opnd2 > 1/2
192 		 *
193 		 * In this case n will round to 1, so
194 		 *    r = opnd1 - opnd2
195 		 */
196 		if (stepcount == -1 &&
197 		    Dbl_isgreaterthan(opnd1p1,opnd1p2,opnd2p1,opnd2p2)) {
198 			/* set sign */
199 			Dbl_allp1(resultp1) = ~Dbl_allp1(resultp1);
200 			/* align opnd2 with opnd1 */
201 			Dbl_leftshiftby1(opnd2p1,opnd2p2);
202 			Dbl_subtract(opnd2p1,opnd2p2,opnd1p1,opnd1p2,
203 			 opnd2p1,opnd2p2);
204 			/* now normalize */
205 			while (Dbl_iszero_hidden(opnd2p1)) {
206 				Dbl_leftshiftby1(opnd2p1,opnd2p2);
207 				dest_exponent--;
208 			}
209 			Dbl_set_exponentmantissa(resultp1,resultp2,opnd2p1,opnd2p2);
210 			goto testforunderflow;
211 		}
212 		/*
213 		 * opnd1/opnd2 <= 1/2
214 		 *
215 		 * In this case n will round to zero, so
216 		 *    r = opnd1
217 		 */
218 		Dbl_set_exponentmantissa(resultp1,resultp2,opnd1p1,opnd1p2);
219 		dest_exponent = opnd1_exponent;
220 		goto testforunderflow;
221 	}
222 
223 	/*
224 	 * Generate result
225 	 *
226 	 * Do iterative subtract until remainder is less than operand 2.
227 	 */
228 	while (stepcount-- > 0 && (Dbl_allp1(opnd1p1) || Dbl_allp2(opnd1p2))) {
229 		if (Dbl_isnotlessthan(opnd1p1,opnd1p2,opnd2p1,opnd2p2)) {
230 			Dbl_subtract(opnd1p1,opnd1p2,opnd2p1,opnd2p2,opnd1p1,opnd1p2);
231 		}
232 		Dbl_leftshiftby1(opnd1p1,opnd1p2);
233 	}
234 	/*
235 	 * Do last subtract, then determine which way to round if remainder
236 	 * is exactly 1/2 of opnd2
237 	 */
238 	if (Dbl_isnotlessthan(opnd1p1,opnd1p2,opnd2p1,opnd2p2)) {
239 		Dbl_subtract(opnd1p1,opnd1p2,opnd2p1,opnd2p2,opnd1p1,opnd1p2);
240 		roundup = true;
241 	}
242 	if (stepcount > 0 || Dbl_iszero(opnd1p1,opnd1p2)) {
243 		/* division is exact, remainder is zero */
244 		Dbl_setzero_exponentmantissa(resultp1,resultp2);
245 		Dbl_copytoptr(resultp1,resultp2,dstptr);
246 		return(NOEXCEPTION);
247 	}
248 
249 	/*
250 	 * Check for cases where opnd1/opnd2 < n
251 	 *
252 	 * In this case the result's sign will be opposite that of
253 	 * opnd1.  The mantissa also needs some correction.
254 	 */
255 	Dbl_leftshiftby1(opnd1p1,opnd1p2);
256 	if (Dbl_isgreaterthan(opnd1p1,opnd1p2,opnd2p1,opnd2p2)) {
257 		Dbl_invert_sign(resultp1);
258 		Dbl_leftshiftby1(opnd2p1,opnd2p2);
259 		Dbl_subtract(opnd2p1,opnd2p2,opnd1p1,opnd1p2,opnd1p1,opnd1p2);
260 	}
261 	/* check for remainder being exactly 1/2 of opnd2 */
262 	else if (Dbl_isequal(opnd1p1,opnd1p2,opnd2p1,opnd2p2) && roundup) {
263 		Dbl_invert_sign(resultp1);
264 	}
265 
266 	/* normalize result's mantissa */
267 	while (Dbl_iszero_hidden(opnd1p1)) {
268 		dest_exponent--;
269 		Dbl_leftshiftby1(opnd1p1,opnd1p2);
270 	}
271 	Dbl_set_exponentmantissa(resultp1,resultp2,opnd1p1,opnd1p2);
272 
273 	/*
274 	 * Test for underflow
275 	 */
276     testforunderflow:
277 	if (dest_exponent <= 0) {
278 		/* trap if UNDERFLOWTRAP enabled */
279 		if (Is_underflowtrap_enabled()) {
280 			/*
281 			 * Adjust bias of result
282 			 */
283 			Dbl_setwrapped_exponent(resultp1,dest_exponent,unfl);
284 			/* frem is always exact */
285 			Dbl_copytoptr(resultp1,resultp2,dstptr);
286 			return(UNDERFLOWEXCEPTION);
287 		}
288 		/*
289 		 * denormalize result or set to signed zero
290 		 */
291 		if (dest_exponent >= (1 - DBL_P)) {
292 			Dbl_rightshift_exponentmantissa(resultp1,resultp2,
293 			 1-dest_exponent);
294 		}
295 		else {
296 			Dbl_setzero_exponentmantissa(resultp1,resultp2);
297 		}
298 	}
299 	else Dbl_set_exponent(resultp1,dest_exponent);
300 	Dbl_copytoptr(resultp1,resultp2,dstptr);
301 	return(NOEXCEPTION);
302 }
303