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