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