1 /* $NetBSD: sfrem.c,v 1.3 2005/12/11 12:17:40 christos Exp $ */
3 /* $OpenBSD: sfrem.c,v 1.4 2001/03/29 03:58:19 mickey Exp $ */
6 * Copyright 1996 1995 by Open Software Foundation, Inc.
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.
15 * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
17 * FOR A PARTICULAR PURPOSE.
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.
30 * (c) Copyright 1986 HEWLETT-PACKARD COMPANY
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.
44 #include <sys/cdefs.h>
45 __KERNEL_RCSID(0, "$NetBSD: sfrem.c,v 1.3 2005/12/11 12:17:40 christos Exp $");
47 #include "../spmath/float.h"
48 #include "../spmath/sgl_float.h"
51 * Single Precision Floating-point Remainder
54 sgl_frem(srcptr1
,srcptr2
,dstptr
,status
)
56 sgl_floating_point
*srcptr1
, *srcptr2
, *dstptr
;
59 register unsigned int opnd1
, opnd2
, result
;
60 register int opnd1_exponent
, opnd2_exponent
, dest_exponent
, stepcount
;
61 register int roundup
= false;
66 * check first operand for NaN's or infinity
68 if ((opnd1_exponent
= Sgl_exponent(opnd1
)) == SGL_INFINITY_EXPONENT
) {
69 if (Sgl_iszero_mantissa(opnd1
)) {
70 if (Sgl_isnotnan(opnd2
)) {
71 /* invalid since first operand is infinity */
72 if (Is_invalidtrap_enabled())
73 return(INVALIDEXCEPTION
);
75 Sgl_makequietnan(result
);
82 * is NaN; signaling or quiet?
84 if (Sgl_isone_signaling(opnd1
)) {
85 /* trap if INVALIDTRAP enabled */
86 if (Is_invalidtrap_enabled())
87 return(INVALIDEXCEPTION
);
93 * is second operand a signaling NaN?
95 else if (Sgl_is_signalingnan(opnd2
)) {
96 /* trap if INVALIDTRAP enabled */
97 if (Is_invalidtrap_enabled())
98 return(INVALIDEXCEPTION
);
101 Sgl_set_quiet(opnd2
);
113 * check second operand for NaN's or infinity
115 if ((opnd2_exponent
= Sgl_exponent(opnd2
)) == SGL_INFINITY_EXPONENT
) {
116 if (Sgl_iszero_mantissa(opnd2
)) {
118 * return first operand
124 * is NaN; signaling or quiet?
126 if (Sgl_isone_signaling(opnd2
)) {
127 /* trap if INVALIDTRAP enabled */
128 if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION
);
131 Sgl_set_quiet(opnd2
);
140 * check second operand for zero
142 if (Sgl_iszero_exponentmantissa(opnd2
)) {
143 /* invalid since second operand is zero */
144 if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION
);
146 Sgl_makequietnan(result
);
157 * check for denormalized operands
159 if (opnd1_exponent
== 0) {
161 if (Sgl_iszero_mantissa(opnd1
)) {
165 /* normalize, then continue */
167 Sgl_normalize(opnd1
,opnd1_exponent
);
170 Sgl_clear_signexponent_set_hidden(opnd1
);
172 if (opnd2_exponent
== 0) {
173 /* normalize, then continue */
175 Sgl_normalize(opnd2
,opnd2_exponent
);
178 Sgl_clear_signexponent_set_hidden(opnd2
);
181 /* find result exponent and divide step loop count */
182 dest_exponent
= opnd2_exponent
- 1;
183 stepcount
= opnd1_exponent
- opnd2_exponent
;
186 * check for opnd1/opnd2 < 1
190 * check for opnd1/opnd2 > 1/2
192 * In this case n will round to 1, so
195 if (stepcount
== -1 && Sgl_isgreaterthan(opnd1
,opnd2
)) {
196 Sgl_all(result
) = ~Sgl_all(result
); /* set sign */
197 /* align opnd2 with opnd1 */
198 Sgl_leftshiftby1(opnd2
);
199 Sgl_subtract(opnd2
,opnd1
,opnd2
);
201 while (Sgl_iszero_hidden(opnd2
)) {
202 Sgl_leftshiftby1(opnd2
);
205 Sgl_set_exponentmantissa(result
,opnd2
);
206 goto testforunderflow
;
211 * In this case n will round to zero, so
214 Sgl_set_exponentmantissa(result
,opnd1
);
215 dest_exponent
= opnd1_exponent
;
216 goto testforunderflow
;
222 * Do iterative subtract until remainder is less than operand 2.
224 while (stepcount
-- > 0 && Sgl_all(opnd1
)) {
225 if (Sgl_isnotlessthan(opnd1
,opnd2
))
226 Sgl_subtract(opnd1
,opnd2
,opnd1
);
227 Sgl_leftshiftby1(opnd1
);
230 * Do last subtract, then determine which way to round if remainder
231 * is exactly 1/2 of opnd2
233 if (Sgl_isnotlessthan(opnd1
,opnd2
)) {
234 Sgl_subtract(opnd1
,opnd2
,opnd1
);
237 if (stepcount
> 0 || Sgl_iszero(opnd1
)) {
238 /* division is exact, remainder is zero */
239 Sgl_setzero_exponentmantissa(result
);
245 * Check for cases where opnd1/opnd2 < n
247 * In this case the result's sign will be opposite that of
248 * opnd1. The mantissa also needs some correction.
250 Sgl_leftshiftby1(opnd1
);
251 if (Sgl_isgreaterthan(opnd1
,opnd2
)) {
252 Sgl_invert_sign(result
);
253 Sgl_subtract((opnd2
<<1),opnd1
,opnd1
);
255 /* check for remainder being exactly 1/2 of opnd2 */
256 else if (Sgl_isequal(opnd1
,opnd2
) && roundup
) {
257 Sgl_invert_sign(result
);
260 /* normalize result's mantissa */
261 while (Sgl_iszero_hidden(opnd1
)) {
263 Sgl_leftshiftby1(opnd1
);
265 Sgl_set_exponentmantissa(result
,opnd1
);
271 if (dest_exponent
<= 0) {
272 /* trap if UNDERFLOWTRAP enabled */
273 if (Is_underflowtrap_enabled()) {
275 * Adjust bias of result
277 Sgl_setwrapped_exponent(result
,dest_exponent
,unfl
);
279 /* frem is always exact */
280 return(UNDERFLOWEXCEPTION
);
283 * denormalize result or set to signed zero
285 if (dest_exponent
>= (1 - SGL_P
)) {
286 Sgl_rightshift_exponentmantissa(result
,1-dest_exponent
);
288 Sgl_setzero_exponentmantissa(result
);
291 else Sgl_set_exponent(result
,dest_exponent
);