]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - lib/libc/powerpc64/gen/modf.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / lib / libc / powerpc64 / gen / modf.c
1 /*
2  * Copyright (c) 1994, 1995 Carnegie-Mellon University.
3  * All rights reserved.
4  *
5  * Author: Chris G. Demetriou
6  * 
7  * Permission to use, copy, modify and distribute this software and
8  * its documentation is hereby granted, provided that both the copyright
9  * notice and this permission notice appear in all copies of the
10  * software, derivative works or modified versions, and any portions
11  * thereof, and that both notices appear in supporting documentation.
12  * 
13  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 
14  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 
15  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
16  * 
17  * Carnegie Mellon requests users of this software to return to
18  *
19  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
20  *  School of Computer Science
21  *  Carnegie Mellon University
22  *  Pittsburgh PA 15213-3890
23  *
24  * any improvements or extensions that they make and grant Carnegie the
25  * rights to redistribute these changes.
26  *
27  *      $NetBSD: modf.c,v 1.1 1995/02/10 17:50:25 cgd Exp $
28  */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include <sys/types.h>
34 #include <machine/ieee.h>
35 #include <errno.h>
36 #include <math.h>
37
38 /*
39  * double modf(double val, double *iptr)
40  * returns: f and i such that |f| < 1.0, (f + i) = val, and
41  *      sign(f) == sign(i) == sign(val).
42  *
43  * Beware signedness when doing subtraction, and also operand size!
44  */
45 double
46 modf(val, iptr)
47         double val, *iptr;
48 {
49         union doub {
50                 double v;
51                 struct ieee_double s;
52         } u, v;
53         u_int64_t frac;
54
55         /*
56          * If input is Inf or NaN, return it and leave i alone.
57          */
58         u.v = val;
59         if (u.s.dbl_exp == DBL_EXP_INFNAN)
60                 return (u.v);
61
62         /*
63          * If input can't have a fractional part, return
64          * (appropriately signed) zero, and make i be the input.
65          */
66         if ((int)u.s.dbl_exp - DBL_EXP_BIAS > DBL_FRACBITS - 1) {
67                 *iptr = u.v;
68                 v.v = 0.0;
69                 v.s.dbl_sign = u.s.dbl_sign;
70                 return (v.v);
71         }
72
73         /*
74          * If |input| < 1.0, return it, and set i to the appropriately
75          * signed zero.
76          */
77         if (u.s.dbl_exp < DBL_EXP_BIAS) {
78                 v.v = 0.0;
79                 v.s.dbl_sign = u.s.dbl_sign;
80                 *iptr = v.v;
81                 return (u.v);
82         }
83
84         /*
85          * There can be a fractional part of the input.
86          * If you look at the math involved for a few seconds, it's
87          * plain to see that the integral part is the input, with the
88          * low (DBL_FRACBITS - (exponent - DBL_EXP_BIAS)) bits zeroed,
89          * the fractional part is the part with the rest of the
90          * bits zeroed.  Just zeroing the high bits to get the
91          * fractional part would yield a fraction in need of
92          * normalization.  Therefore, we take the easy way out, and
93          * just use subtraction to get the fractional part.
94          */
95         v.v = u.v;
96         /* Zero the low bits of the fraction, the sleazy way. */
97         frac = ((u_int64_t)v.s.dbl_frach << 32) + v.s.dbl_fracl;
98         frac >>= DBL_FRACBITS - (u.s.dbl_exp - DBL_EXP_BIAS);
99         frac <<= DBL_FRACBITS - (u.s.dbl_exp - DBL_EXP_BIAS);
100         v.s.dbl_fracl = frac & 0xffffffff;
101         v.s.dbl_frach = frac >> 32;
102         *iptr = v.v;
103
104         u.v -= v.v;
105         u.s.dbl_sign = v.s.dbl_sign;
106         return (u.v);
107 }