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 /*
37 * Convert an 80-bit or 128-bit float to a string in hex ('a') format
38 *
39 * This chunk of code gets inserted into the vfprintf function in the
40 * long double case when long double is larger than 64 bits.
41 *
42 * This code uses the 'u128' type to hold the floating point value as
43 * an integer value.
44 *
45 * This code only works with long double type.
46 */
47
48 #if __SIZEOF_LONG_DOUBLE__ > 8
49
50 #define _NEED_IO_FLOAT_LARGE
51
52 #include "dtoa.h"
53
54 #if __LDBL_MANT_DIG__ == 64
55 # define LEXP_BIAS (__LDBL_MAX_EXP__ + 2)
56 # define LEXP_INF (__LDBL_MAX_EXP__ - 3)
57 # define LSIG_BITS (__LDBL_MANT_DIG__)
58 # ifdef __m68k__
59 # define LDENORM_EXP_BIAS 0
60 # else
61 # define LDENORM_EXP_BIAS 1
62 # define LSIG_MSB_INF _u128_lshift(to_u128(1), __LDBL_MANT_DIG__-1)
63 # endif
64 # if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
65 # define LEXP_SHIFT __LDBL_MANT_DIG__
66 # define LSIGN_SHIFT 79
67 # endif
68 # if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
69 # define LEXP_SHIFT (__LDBL_MANT_DIG__ + 16)
70 # define LSIGN_SHIFT (79 + 16)
71 # endif
72 #else
73 # define LDENORM_EXP_BIAS 1
74 # define LSIGN_SHIFT 127
75 # define LEXP_BIAS (__LDBL_MAX_EXP__ - 1)
76 # define LEXP_INF (__LDBL_MAX_EXP__)
77 # define LSIG_MSB _u128_lshift(to_u128(1), __LDBL_MANT_DIG__-1)
78 # define LSIG_BITS (__LDBL_MANT_DIG__ - 1)
79 # define LEXP_SHIFT (__LDBL_MANT_DIG__ - 1)
80 #endif
81
82 #define LEXP_MASK ((__LDBL_MAX_EXP__ - 1) + __LDBL_MAX_EXP__)
83 #define LSIG_SHIFT 0
84 #define LSIG_MASK _u128_minus_64(_u128_lshift(to_u128(1), LSIG_BITS), 1)
85
86 #define TOCASE(c) ((c) - case_convert)
87
88 #define LDTOX_NDIGS (__LDBL_MANT_DIG__ + 3) / 4
89
90 int
__ldtox_engine(long double x,struct dtoa * dtoa,int prec,unsigned char case_convert)91 __ldtox_engine(long double x, struct dtoa *dtoa, int prec, unsigned char case_convert)
92 {
93 _u128 fi, s;
94 int exp;
95
96 fi = asuintld(x);
97
98 exp = _u128_and_64(_u128_rshift(fi, LEXP_SHIFT), LEXP_MASK);
99 s = fi = _u128_lshift(_u128_and(fi, LSIG_MASK), LSIG_SHIFT);
100 if (!_u128_is_zero(s) || exp != 0) {
101 if (exp == 0)
102 exp = LDENORM_EXP_BIAS;
103 else
104 {
105 #ifdef LSIG_MSB
106 s = _u128_or(s, LSIG_MSB);
107 #endif
108 }
109 exp -= LEXP_BIAS;
110 }
111 dtoa->flags = 0;
112 if (_u128_and_64(_u128_rshift(fi, LSIGN_SHIFT), 1))
113 dtoa->flags = DTOA_MINUS;
114
115 if (prec < 0)
116 prec = 0;
117 else if (prec >= (LDTOX_NDIGS - 1))
118 prec = LDTOX_NDIGS - 1;
119 else {
120 int bits = ((LDTOX_NDIGS - 1) - prec) << 2;
121 _u128 half = _u128_lshift(to_u128(1), bits - 1);
122 _u128 mask = _u128_not(_u128_minus_64(_u128_lshift(half, 1), 1));
123
124 /* round even */
125 if (_u128_gt(_u128_and(s, _u128_not(mask)), half) || _u128_and_64(_u128_rshift(s, bits), 1) != 0)
126 s = _u128_plus(s, half);
127
128 s = _u128_and(s, mask);
129 }
130
131 if (exp == LEXP_INF) {
132 #ifdef LSIG_MSB_INF
133 if (!_u128_eq(fi, LSIG_MSB_INF))
134 #else
135 if (!_u128_is_zero(fi))
136 #endif
137 dtoa->flags |= DTOA_NAN;
138 else
139 dtoa->flags |= DTOA_INF;
140 } else {
141 int8_t d;
142 for (d = LDTOX_NDIGS - 1; d >= 0; d--) {
143 int dig = _u128_and_64(s, 0xf);
144 s = _u128_rshift(s, 4);
145 if (dig == 0 && d > prec)
146 continue;
147 if (dig <= 9)
148 dig += '0';
149 else
150 dig += TOCASE('a' - 10);
151 dtoa->digits[d] = dig;
152 if (prec < d)
153 prec = d;
154 }
155 }
156 dtoa->exp = exp;
157 return prec;
158 }
159
160 #endif
161