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