1 /*
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright © 2023 Keith Packard
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 *
18 * 3. Neither the name of the copyright holder nor the names of its
19 * contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
33 * OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35
36 #ifndef DTOX_SIZE
37 #define DTOX_SIZE 8
38 #endif
39
40 #include "stdio_private.h"
41
42 #if DTOX_SIZE == 4 || defined(FLOAT64)
43
44 #if DTOX_SIZE == 8
45
46 #define DTOA_MAX_DIG 17
47 #define DTOA_MAX_10_EXP 308
48 #define DTOA_MIN_10_EXP (-307)
49 #define DTOA_SCALE_UP_NUM 9
50 #define DTOA_ROUND_NUM (DTOA_MAX_DIG + 1)
51
52 #define DTOX_UINT uint64_t
53 #define DTOX_INT int64_t
54 #define DTOX_FLOAT FLOAT64
55 #define DTOX_ASUINT(x) asuint64(x)
56
57 #define EXP_SHIFT 52
58 #define EXP_MASK 0x7ff
59 #define SIG_SHIFT 0
60 #define SIG_MASK 0xfffffffffffffLL
61 #define EXP_BIAS 1023
62 #define ASUINT(x) asuint64(x)
63 #define DTOX_NDIGS 14
64
65 #define _NEED_IO_FLOAT64
66
67 #elif DTOX_SIZE == 4
68
69 #define _NEED_IO_FLOAT32
70 #define __dtox_engine __ftox_engine
71
72 #define DTOX_UINT uint32_t
73 #define DTOX_INT int32_t
74 #define DTOX_FLOAT float
75 #define DTOX_ASUINT(x) asuint(x)
76
77 #define EXP_SHIFT 23
78 #define EXP_MASK 0xff
79 #define SIG_SHIFT 1
80 #define SIG_MASK 0x7fffff
81 #define EXP_BIAS 127
82 #define ASUINT(x) asuint(x)
83 #define DTOX_NDIGS 7
84 #endif
85
86 #include "dtoa.h"
87
88 /*
89 * Convert a 32-bit or 64-bit float to a string in hex ('a') format
90 *
91 * This chunk of code gets inserted into the vfprintf function in the
92 * double/float handling code as well as the long double case when
93 * long double is 32- or 64- bits.
94 *
95 * This code assumes that there is an integer type suitable for holding
96 * the entire floating point value.
97 *
98 * Define DTOX_UINT, DTOX_INT, DTOX_FLOAT and DTOX_SIZE before including
99 * this file.
100 */
101
102 #define TOCASE(c) ((c) - case_convert)
103
104 int
__dtox_engine(DTOX_FLOAT x,struct dtoa * dtoa,int prec,unsigned char case_convert)105 __dtox_engine (DTOX_FLOAT x, struct dtoa *dtoa, int prec, unsigned char case_convert)
106 {
107 DTOX_INT fi, s;
108 int exp;
109
110 fi = ASUINT(x);
111
112 dtoa->digits[0] = '0';
113
114 exp = ((fi >> EXP_SHIFT) & EXP_MASK);
115 s = (fi & SIG_MASK) << SIG_SHIFT;
116 if (s | exp) {
117 if (!exp)
118 exp = 1;
119 else
120 dtoa->digits[0] = '1';
121 exp -= EXP_BIAS;
122 }
123 dtoa->flags = 0;
124 if (fi < 0)
125 dtoa->flags = DTOA_MINUS;
126
127 if (prec < 0)
128 prec = 0;
129 else if (prec >= (DTOX_NDIGS - 1))
130 prec = DTOX_NDIGS - 1;
131 else {
132 int bits = ((DTOX_NDIGS - 1) - prec) << 2;
133 DTOX_INT half = ((DTOX_INT) 1) << (bits - 1);
134 DTOX_INT mask = ~((half << 1) - 1);
135
136 /* round even */
137 if ((s & ~mask) > half || ((s >> bits) & 1) != 0)
138 s += half;
139 /* special case rounding first digit */
140 if (s > (SIG_MASK << SIG_SHIFT))
141 dtoa->digits[0]++;
142 s &= mask;
143 }
144
145 if (exp == EXP_BIAS + 1) {
146 if (s)
147 dtoa->flags |= DTOA_NAN;
148 else
149 dtoa->flags |= DTOA_INF;
150 } else {
151 int d;
152 for (d = DTOX_NDIGS - 1; d; d--) {
153 int dig = s & 0xf;
154 s >>= 4;
155 if (dig == 0 && d > prec)
156 continue;
157 if (dig <= 9)
158 dig += '0';
159 else
160 dig += TOCASE('a' - 10);
161 dtoa->digits[d] = dig;
162 if (prec < d)
163 prec = d;
164 }
165 }
166 dtoa->exp = exp;
167 return prec;
168 }
169
170 #endif
171