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 SIG_MSB 0x10000000000000LL
62 #define EXP_BIAS 1023
63 #define ASUINT(x) asuint64(x)
64 #define DTOX_NDIGS 14
65
66 #define _NEED_IO_FLOAT64
67
68 #elif DTOX_SIZE == 4
69
70 #define _NEED_IO_FLOAT32
71 #define __dtox_engine __ftox_engine
72
73 #define DTOX_UINT uint32_t
74 #define DTOX_INT int32_t
75 #define DTOX_FLOAT float
76 #define DTOX_ASUINT(x) asuint(x)
77
78 #define EXP_SHIFT 23
79 #define EXP_MASK 0xff
80 #define SIG_SHIFT 1
81 #define SIG_MASK 0x7fffff
82 #define SIG_MSB 0x800000
83 #define EXP_BIAS 127
84 #define ASUINT(x) asuint(x)
85 #define DTOX_NDIGS 7
86 #endif
87
88 #include "dtoa.h"
89
90 /*
91 * Convert a 32-bit or 64-bit float to a string in hex ('a') format
92 *
93 * This chunk of code gets inserted into the vfprintf function in the
94 * double/float handling code as well as the long double case when
95 * long double is 32- or 64- bits.
96 *
97 * This code assumes that there is an integer type suitable for holding
98 * the entire floating point value.
99 *
100 * Define DTOX_UINT, DTOX_INT, DTOX_FLOAT and DTOX_SIZE before including
101 * this file.
102 */
103
104 #define TOCASE(c) ((c) - case_convert)
105
106 int
__dtox_engine(DTOX_FLOAT x,struct dtoa * dtoa,int prec,unsigned char case_convert)107 __dtox_engine (DTOX_FLOAT x, struct dtoa *dtoa, int prec, unsigned char case_convert)
108 {
109 DTOX_INT fi, s;
110 int exp, d;
111
112 fi = ASUINT(x);
113
114 dtoa->flags = 0;
115 if (fi < 0)
116 dtoa->flags = DTOA_MINUS;
117
118 exp = ((fi >> EXP_SHIFT) & EXP_MASK);
119 s = (fi & SIG_MASK) << SIG_SHIFT;
120 if (s || exp) {
121 if (exp == EXP_BIAS * 2 + 1) {
122 if (s)
123 dtoa->flags |= DTOA_NAN;
124 else
125 dtoa->flags |= DTOA_INF;
126 return 0;
127 }
128
129 if (!exp)
130 exp = 1;
131 else
132 s |= (SIG_MSB << SIG_SHIFT);
133 exp -= EXP_BIAS;
134 }
135 dtoa->exp = exp;
136
137 if (prec < 0)
138 prec = 0;
139 else if (prec >= (DTOX_NDIGS - 1))
140 prec = DTOX_NDIGS - 1;
141 else {
142 int bits = ((DTOX_NDIGS - 1) - prec) << 2;
143 DTOX_INT half = ((DTOX_INT) 1) << (bits - 1);
144 DTOX_INT mask = ~((half << 1) - 1);
145
146 /* round even */
147 if ((s & ~mask) > half || ((s >> bits) & 1) != 0)
148 s += half;
149 s &= mask;
150 }
151
152 for (d = DTOX_NDIGS - 1; d >= 0; d--) {
153 int dig = s & 0xf;
154 s >>= 4;
155 if (dig == 0 && d > prec)
156 continue;
157 if (dig > 9)
158 dig += TOCASE('a') - 10 - '0';
159 dig += '0';
160 dtoa->digits[d] = dig;
161 if (prec < d)
162 prec = d;
163 }
164 return prec;
165 }
166
167 #endif
168