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