]> git.saurik.com Git - apple/libc.git/blob - stdio/hexfloat.c
2e59d9eea2d0612aa4481d16ab30c77401e90ae0
[apple/libc.git] / stdio / hexfloat.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
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
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25
26 #ifdef HEXFLOAT
27
28 /*
29 * hexfloat.c provides routines that vfprintf and vfwprintf can call to convert
30 * floating point numbers to hexidecimal, as used by the %a and %A conversions.
31 * This is necessarily dependent not only on the floating point data format,
32 * but also byte order and existence of long double type.
33 *
34 * The union hexdouble represents the IEEE-754 double precision format, while
35 * union hexlongdouble represents the IEEE-754 extended double precision
36 * format.
37 */
38
39 #include <stdio.h>
40 #include <math.h>
41 #include <limits.h>
42
43 #define EXPBIAS 1023
44 #define EXPMIN -1022
45 #define EXPSPECIAL 2047
46 #define FRACTHEX 13
47
48 union hexdouble {
49 double d;
50 struct {
51 #if defined(__ppc__)
52 unsigned int sign:1;
53 unsigned int exp:11;
54 unsigned long long fract:52;
55 #elif defined(__i386__)
56 unsigned long long fract:52;
57 unsigned int exp:11;
58 unsigned int sign:1;
59 #else
60 #error Unsupported architecture
61 #endif
62 } s;
63 };
64
65 #if !__TYPE_LONGDOUBLE_IS_DOUBLE
66 #ifdef __i386__
67
68 #define LEXPBIAS 16383
69 #define LEXPMIN -16382
70 #define LEXPSPECIAL 32767
71 #define LFRACTHEX 16
72
73 union hexlongdouble {
74 long double d;
75 struct {
76 unsigned long long fract:63;
77 unsigned int i:1;
78 unsigned int exp:15;
79 unsigned int sign:1;
80 } s;
81 };
82 #endif /* __i386__ */
83 #endif /* !__TYPE_LONGDOUBLE_IS_DOUBLE */
84
85 int
86 __hdtoa(double d, const char *xdigs, int prec, char *cp,
87 int *expt, int *signflag, char **dtoaend)
88 {
89 union hexdouble u;
90 char buf[FRACTHEX];
91 char *hp;
92 int i;
93 long long fract;
94 //char *start = cp; //DEBUG
95
96 u.d = d;
97 //printf("\nsign=%d exp=%x fract=%llx\n", u.s.sign, u.s.exp, u.s.fract); //DEBUG
98 *signflag = u.s.sign;
99 fract = u.s.fract;
100 switch (u.s.exp) {
101 case EXPSPECIAL: /* NaN or Inf */
102 *expt = INT_MAX;
103 *cp = (fract ? 'N' : 'I');
104 return 0;
105 case 0: /* Zero or denormalized */
106 *cp++ = '0';
107 *expt = (fract ? EXPMIN : 0);
108 break;
109 default: /* Normal numbers */
110 *cp++ = '1';
111 *expt = u.s.exp - EXPBIAS;
112 break;
113 }
114 if (prec < 0)
115 prec = FRACTHEX;
116 //printf("prec=%d expt=%d\n", prec, *expt); //DEBUG
117 if (prec > 0) {
118 int dig = (prec > FRACTHEX ? FRACTHEX : prec);
119 int zero = prec - dig;
120 int shift = FRACTHEX - dig;
121 if (shift > 0)
122 fract >>= (shift << 2);
123 for (hp = buf + dig, i = dig; i > 0; i--) {
124 *--hp = xdigs[fract & 0xf];
125 fract >>= 4;
126 }
127 strncpy(cp, hp, dig);
128 cp += dig;
129 while(zero-- > 0)
130 *cp++ = '0';
131 }
132 *dtoaend = cp;
133 //while (start < cp) putchar(*start++); //DEBUG
134 //putchar('\n'); //DEBUG
135 return prec;
136 }
137
138 #if !__TYPE_LONGDOUBLE_IS_DOUBLE
139 #ifdef __i386__
140 int
141 __hldtoa(long double d, const char *xdigs, int prec, char *cp,
142 int *expt, int *signflag, char **dtoaend)
143 {
144 union hexlongdouble u;
145 char buf[LFRACTHEX];
146 char *hp;
147 int i;
148 unsigned long long fract;
149 //char *start = cp; //DEBUG
150
151 u.d = d;
152 //printf("d=%Lg u.d=%Lg\n", d, u.d); //DEBUG
153 //printf("\nsign=%d exp=%x fract=%llx\n", u.s.sign, u.s.exp, u.s.fract); //DEBUG
154 *signflag = u.s.sign;
155 fract = (u.s.fract << 1);
156 switch (u.s.exp) {
157 case LEXPSPECIAL: /* NaN or Inf */
158 *expt = INT_MAX;
159 *cp = (fract ? 'N' : 'I');
160 return 0;
161 default: /* Normal or denormalized */
162 *cp++ = u.s.i ? '1' : '0';
163 *expt = u.s.exp - LEXPBIAS;
164 break;
165 }
166 if (prec < 0)
167 prec = LFRACTHEX;
168 //printf("prec=%d expt=%d\n", prec, *expt); //DEBUG
169 if (prec > 0) {
170 int dig = (prec > LFRACTHEX ? LFRACTHEX : prec);
171 int zero = prec - dig;
172 int shift = LFRACTHEX - dig;
173 if (shift > 0)
174 fract >>= (shift << 2);
175 for (hp = buf + dig, i = dig; i > 0; i--) {
176 *--hp = xdigs[fract & 0xf];
177 fract >>= 4;
178 }
179 strncpy(cp, hp, dig);
180 cp += dig;
181 while(zero-- > 0)
182 *cp++ = '0';
183 }
184 *dtoaend = cp;
185 //while (start < cp) putchar(*start++); //DEBUG
186 //putchar('\n'); //DEBUG
187 return prec;
188 }
189 #endif /* __i386__ */
190 #endif /* !__TYPE_LONGDOUBLE_IS_DOUBLE */
191
192 #endif /* HEXFLOAT */