]>
Commit | Line | Data |
---|---|---|
e9ce8d39 A |
1 | /* |
2 | * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
734aad71 | 6 | * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. |
e9ce8d39 | 7 | * |
734aad71 A |
8 | * This file contains Original Code and/or Modifications of Original Code |
9 | * as defined in and that are subject to the Apple Public Source License | |
10 | * Version 2.0 (the 'License'). You may not use this file except in | |
11 | * compliance with the License. Please obtain a copy of the License at | |
12 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
13 | * file. | |
14 | * | |
15 | * The Original Code and all software distributed under the License are | |
16 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
e9ce8d39 A |
17 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
18 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
734aad71 A |
19 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. |
20 | * Please see the License for the specific language governing rights and | |
21 | * limitations under the License. | |
e9ce8d39 A |
22 | * |
23 | * @APPLE_LICENSE_HEADER_END@ | |
24 | */ | |
25 | /* Copyright (c) 1992 NeXT Computer, Inc. All rights reserved. | |
26 | * | |
27 | * File: libc/m98k/gen/ecvt.c | |
28 | * | |
29 | * char *ecvt(double x, int ndigits, int *decimal, int *sign); | |
30 | * char *fcvt(double x, int ndigits, int *decimal, int *sign); | |
31 | * | |
32 | * The function `ecvt' converts the double `x' to a null-terminated | |
33 | * string of `ndigits' ASCII digits and returns a pointer to the string. | |
34 | * The position of the decimal point relative to the beginning of the | |
35 | * string is stored in the int pointed to by `decimal'. A negative | |
36 | * value means that the decimal point appears to the left of the returned | |
37 | * digits. If the sign of the result is negative, a non-zero value is | |
38 | * stored in the int pointed to by `sign'; otherwise, a zero value is stored. | |
39 | * The low-order digit of the returned value is rounded. | |
40 | * | |
41 | * The function `fcvt' is identical to `ecvt', except that the correct digit | |
42 | * has been rounded for Fortran F-format output of the number of digits | |
43 | * specified by `ndigits'. | |
44 | * | |
45 | * HISTORY | |
46 | * 10-Nov-92 Derek B Clegg (dclegg@next.com) | |
47 | * Ported to m98k. | |
48 | * 8-Jan-92 Peter King (king@next.com) | |
49 | * Created from M68K sources which was created from VAX sources. | |
50 | */ | |
51 | #import <math.h> | |
52 | ||
53 | static double ecvt_rint(double x); | |
54 | static double ecvt_copysign(double x, double y); | |
55 | static char *cvt(double arg, int ndigits, int *decptp, int *signp, int eflag); | |
56 | ||
57 | #define isNAN(x) ((x) != (x)) | |
58 | ||
59 | /* big enough to handle %.20f conversion of 1e308 */ | |
60 | #define NDIG 350 | |
61 | ||
62 | char * | |
63 | ecvt(double arg, int ndigits, int *decptp, int *signp) | |
64 | { | |
65 | return (cvt(arg, ndigits, decptp, signp, 1)); | |
66 | } | |
67 | ||
68 | char * | |
69 | fcvt(double arg, int ndigits, int *decptp, int *signp) | |
70 | { | |
71 | return (cvt(arg, ndigits, decptp, signp, 0)); | |
72 | } | |
73 | ||
74 | static char * | |
75 | cvt(double arg, int ndigits, int *decptp, int *signp, int eflag) | |
76 | { | |
77 | int decpt; | |
78 | double fi, fj; | |
79 | char *p, *p1; | |
80 | static char buf[NDIG] = { 0 }; | |
81 | ||
82 | if (ndigits < 0) | |
83 | ndigits = 0; | |
84 | if (ndigits >= NDIG - 1) | |
85 | ndigits = NDIG - 2; | |
86 | ||
87 | decpt = 0; | |
88 | *signp = 0; | |
89 | p = &buf[0]; | |
90 | ||
91 | if (arg == 0) { | |
92 | *decptp = 0; | |
93 | while (p < &buf[ndigits]) | |
94 | *p++ = '0'; | |
95 | *p = '\0'; | |
96 | return (buf); | |
97 | } else if (arg < 0) { | |
98 | *signp = 1; | |
99 | arg = -arg; | |
100 | } | |
101 | ||
102 | arg = modf(arg, &fi); | |
103 | p1 = &buf[NDIG]; | |
104 | ||
105 | /* Do integer part */ | |
106 | ||
107 | if (fi != 0) { | |
108 | while (fi != 0) { | |
109 | fj = modf(fi/10, &fi); | |
110 | #if 0 | |
111 | *--p1 = (int)((fj + 0.03) * 10) + '0'; | |
112 | #else | |
113 | *--p1 = (int)ecvt_rint(fj * 10) + '0'; | |
114 | #endif | |
115 | decpt++; | |
116 | } | |
117 | while (p1 < &buf[NDIG]) | |
118 | *p++ = *p1++; | |
119 | } else if (arg > 0) { | |
120 | while ((fj = arg*10) < 1) { | |
121 | arg = fj; | |
122 | decpt--; | |
123 | } | |
124 | } | |
125 | *decptp = decpt; | |
126 | ||
127 | /* Do the fractional part. | |
128 | * p pts to where fraction should be concatenated. | |
129 | * p1 is how far conversion must go to. | |
130 | */ | |
131 | p1 = &buf[ndigits]; | |
132 | if (eflag == 0) { | |
133 | /* fcvt must provide ndigits after decimal pt */ | |
134 | p1 += decpt; | |
135 | /* if decpt was negative, we might be done for fcvt */ | |
136 | if (p1 < &buf[0]) { | |
137 | buf[0] = '\0'; | |
138 | return (buf); | |
139 | } | |
140 | } | |
141 | ||
142 | while (p <= p1 && p < &buf[NDIG]) { | |
143 | arg *= 10; | |
144 | arg = modf(arg, &fj); | |
145 | *p++ = (int)fj + '0'; | |
146 | } | |
147 | ||
148 | /* If we converted all the way to the end of the buf, don't mess with | |
149 | * rounding since there's nothing significant out here anyway. | |
150 | */ | |
151 | if (p1 >= &buf[NDIG]) { | |
152 | buf[NDIG-1] = '\0'; | |
153 | return (buf); | |
154 | } | |
155 | ||
156 | /* Round by adding 5 to last digit and propagating carries. */ | |
157 | p = p1; | |
158 | *p1 += 5; | |
159 | while (*p1 > '9') { | |
160 | *p1 = '0'; | |
161 | if (p1 > buf) { | |
162 | ++*--p1; | |
163 | } else { | |
164 | *p1 = '1'; | |
165 | (*decptp)++; | |
166 | if (eflag == 0) { | |
167 | if (p > buf) | |
168 | *p = '0'; | |
169 | p++; | |
170 | } | |
171 | } | |
172 | } | |
173 | *p = '\0'; | |
174 | return (buf); | |
175 | } | |
176 | ||
177 | static double L = 4503599627370496.0E0; /* 2**52 */ | |
178 | ||
179 | static int ecvt_init = 0; | |
180 | ||
181 | /* | |
182 | * FIXME: This deserves a comment if you turn this off! | |
183 | * This used to #pragma CC_OPT_OFF. | |
184 | * (Probably this was because the isNAN test was optimized away.) | |
185 | * Why don't we just use the value of L given above? | |
186 | */ | |
187 | ||
188 | static double | |
189 | ecvt_rint(double x) | |
190 | { | |
191 | double s, t, one; | |
192 | ||
193 | one = 1.0; | |
194 | ||
195 | if (ecvt_init == 0) { | |
196 | int i; | |
197 | L = 1.0; | |
198 | for (i = 52; i != 0; i--) | |
199 | L *= 2.0; | |
200 | ecvt_init = 1; | |
201 | } | |
202 | if (isNAN(x)) | |
203 | return (x); | |
204 | if (ecvt_copysign(x, one) >= L) /* already an integer */ | |
205 | return (x); | |
206 | s = ecvt_copysign(L, x); | |
207 | t = x + s; /* x+s rounded to integer */ | |
208 | return (t - s); | |
209 | } | |
210 | ||
211 | /* Couldn't we use something like the following structure instead of the | |
212 | hacky unsigned short pointer stuff? | |
213 | ||
214 | struct double_format { | |
215 | unsigned sign:1; | |
216 | unsigned exponent:11; | |
217 | unsigned hi_fraction:20; | |
218 | unsigned lo_fraction:32; | |
219 | }; | |
220 | ||
221 | */ | |
222 | ||
223 | #define msign ((unsigned short)0x7fff) | |
224 | #define mexp ((unsigned short)0x7ff0) | |
225 | ||
226 | static double | |
227 | ecvt_copysign(double x, double y) | |
228 | { | |
229 | unsigned short *px, *py; | |
230 | ||
231 | px = (unsigned short *)&x; | |
232 | py = (unsigned short *)&y; | |
233 | *px = (*px & msign) | (*py & ~msign); | |
234 | return (x); | |
235 | } | |
236 | ||
237 | /* | |
238 | * This used to #pragma CC_OPT_ON | |
239 | */ | |
240 |