File Coverage

s2d.c
Criterion Covered Total %
statement 0 107 0.0
branch 0 88 0.0
condition n/a
subroutine n/a
pod n/a
total 0 195 0.0


line stmt bran cond sub pod time code
1             // Copyright 2019 Ulf Adams
2             //
3             // The contents of this file may be used under the terms of the Apache License,
4             // Version 2.0.
5             //
6             // (See accompanying file LICENSE-Apache or copy at
7             // http://www.apache.org/licenses/LICENSE-2.0)
8             //
9             // Alternatively, the contents of this file may be used under the terms of
10             // the Boost Software License, Version 1.0.
11             // (See accompanying file LICENSE-Boost or copy at
12             // https://www.boost.org/LICENSE_1_0.txt)
13             //
14             // Unless required by applicable law or agreed to in writing, this software
15             // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16             // KIND, either express or implied.
17              
18             /* The location of the headers, relative to this file, has been changed by
19             * Sisyphus */
20              
21             #include "ryu_headers/ryu_parse.h"
22              
23             #include
24             #include
25             #include
26             #include
27             #include
28              
29             #ifdef RYU_DEBUG
30             #include
31             #include
32             #endif
33              
34             #include "ryu_headers/common.h"
35             #include "ryu_headers/d2s_intrinsics.h"
36              
37             #if defined(RYU_OPTIMIZE_SIZE)
38             #include "ryu_headers/d2s_small_table.h"
39             #else
40             #include "ryu_headers/d2s_full_table.h"
41             #endif
42              
43             #define DOUBLE_MANTISSA_BITS 52
44             #define DOUBLE_EXPONENT_BITS 11
45             #define DOUBLE_EXPONENT_BIAS 1023
46              
47             #if defined(_MSC_VER)
48             #include
49              
50             static inline uint32_t floor_log2(const uint64_t value) {
51             #if !defined(_WIN64) /* _BitScanReverse64 unavailable */
52             long index = 0;
53             uint64_t v = value;
54             if(!v) return 64;
55             while(v >>= 1) index += 1;
56             return index;
57             #else
58             long index;
59             return _BitScanReverse64(&index, value) ? index : 64;
60             #endif
61             }
62              
63             #else
64              
65 0           static inline uint32_t floor_log2(const uint64_t value) {
66 0           return 63 - __builtin_clzll(value);
67             }
68              
69             #endif
70              
71             // The max function is already defined on Windows.
72 0           static inline int32_t max32(int32_t a, int32_t b) {
73 0           return a < b ? b : a;
74             }
75              
76 0           static inline double int64Bits2Double(uint64_t bits) {
77             double f;
78 0           memcpy(&f, &bits, sizeof(double));
79 0           return f;
80             }
81              
82 0           enum Status s2d_n(const char * buffer, const int len, double * result) {
83 0 0         if (len == 0) {
84 0           return INPUT_TOO_SHORT;
85             }
86 0           int m10digits = 0;
87 0           int e10digits = 0;
88 0           int dotIndex = len;
89 0           int eIndex = len;
90 0           uint64_t m10 = 0;
91 0           int32_t e10 = 0;
92 0           bool signedM = false;
93 0           bool signedE = false;
94 0           int i = 0;
95 0 0         if (buffer[i] == '-') {
96 0           signedM = true;
97 0           i++;
98             }
99 0 0         for (; i < len; i++) {
100 0           char c = buffer[i];
101 0 0         if (c == '.') {
102 0 0         if (dotIndex != len) {
103 0           return MALFORMED_INPUT;
104             }
105 0           dotIndex = i;
106 0           continue;
107             }
108 0 0         if ((c < '0') || (c > '9')) {
    0          
109             break;
110             }
111 0 0         if (m10digits >= 17) {
112 0           return INPUT_TOO_LONG;
113             }
114 0           m10 = 10 * m10 + (c - '0');
115 0 0         if (m10 != 0) {
116 0           m10digits++;
117             }
118             }
119 0 0         if (i < len && ((buffer[i] == 'e') || (buffer[i] == 'E'))) {
    0          
    0          
120 0           eIndex = i;
121 0           i++;
122 0 0         if (i < len && ((buffer[i] == '-') || (buffer[i] == '+'))) {
    0          
    0          
123 0           signedE = buffer[i] == '-';
124 0           i++;
125             }
126 0 0         for (; i < len; i++) {
127 0           char c = buffer[i];
128 0 0         if ((c < '0') || (c > '9')) {
    0          
129 0           return MALFORMED_INPUT;
130             }
131 0 0         if (e10digits > 3) {
132             // TODO: Be more lenient. Return +/-Infinity or +/-0 instead.
133 0           return INPUT_TOO_LONG;
134             }
135 0           e10 = 10 * e10 + (c - '0');
136 0 0         if (e10 != 0) {
137 0           e10digits++;
138             }
139             }
140             }
141 0 0         if (i < len) {
142 0           return MALFORMED_INPUT;
143             }
144 0 0         if (signedE) {
145 0           e10 = -e10;
146             }
147 0 0         e10 -= dotIndex < eIndex ? eIndex - dotIndex - 1 : 0;
148 0 0         if (m10 == 0) {
149 0 0         *result = signedM ? -0.0 : 0.0;
150 0           return SUCCESS;
151             }
152              
153             #ifdef RYU_DEBUG
154 0           printf("Input=%s\n", buffer);
155 0           printf("m10digits = %d\n", m10digits);
156 0           printf("e10digits = %d\n", e10digits);
157 0           printf("m10 * 10^e10 = %" PRIu64 " * 10^%d\n", m10, e10);
158             #endif
159              
160 0 0         if ((m10digits + e10 <= -324) || (m10 == 0)) {
    0          
161             // Number is less than 1e-324, which should be rounded down to 0; return +/-0.0.
162 0           uint64_t ieee = ((uint64_t) signedM) << (DOUBLE_EXPONENT_BITS + DOUBLE_MANTISSA_BITS);
163 0           *result = int64Bits2Double(ieee);
164 0           return SUCCESS;
165             }
166 0 0         if (m10digits + e10 >= 310) {
167             // Number is larger than 1e+309, which should be rounded to +/-Infinity.
168 0           uint64_t ieee = (((uint64_t) signedM) << (DOUBLE_EXPONENT_BITS + DOUBLE_MANTISSA_BITS)) | (0x7ffull << DOUBLE_MANTISSA_BITS);
169 0           *result = int64Bits2Double(ieee);
170 0           return SUCCESS;
171             }
172              
173             // Convert to binary float m2 * 2^e2, while retaining information about whether the conversion
174             // was exact (trailingZeros).
175             int32_t e2;
176             uint64_t m2;
177             bool trailingZeros;
178 0 0         if (e10 >= 0) {
179             // The length of m * 10^e in bits is:
180             // log2(m10 * 10^e10) = log2(m10) + e10 log2(10) = log2(m10) + e10 + e10 * log2(5)
181             //
182             // We want to compute the DOUBLE_MANTISSA_BITS + 1 top-most bits (+1 for the implicit leading
183             // one in IEEE format). We therefore choose a binary output exponent of
184             // log2(m10 * 10^e10) - (DOUBLE_MANTISSA_BITS + 1).
185             //
186             // We use floor(log2(5^e10)) so that we get at least this many bits; better to
187             // have an additional bit than to not have enough bits.
188 0           e2 = floor_log2(m10) + e10 + log2pow5(e10) - (DOUBLE_MANTISSA_BITS + 1);
189              
190             // We now compute [m10 * 10^e10 / 2^e2] = [m10 * 5^e10 / 2^(e2-e10)].
191             // To that end, we use the DOUBLE_POW5_SPLIT table.
192 0           int j = e2 - e10 - ceil_log2pow5(e10) + DOUBLE_POW5_BITCOUNT;
193 0 0         assert(j >= 0);
194             #if defined(RYU_OPTIMIZE_SIZE)
195             uint64_t pow5[2];
196             double_computePow5(e10, pow5);
197             m2 = mulShift64(m10, pow5, j);
198             #else
199 0 0         assert(e10 < DOUBLE_POW5_TABLE_SIZE);
200 0           m2 = mulShift64(m10, DOUBLE_POW5_SPLIT[e10], j);
201             #endif
202             // We also compute if the result is exact, i.e.,
203             // [m10 * 10^e10 / 2^e2] == m10 * 10^e10 / 2^e2.
204             // This can only be the case if 2^e2 divides m10 * 10^e10, which in turn requires that the
205             // largest power of 2 that divides m10 + e10 is greater than e2. If e2 is less than e10, then
206             // the result must be exact. Otherwise we use the existing multipleOfPowerOf2 function.
207 0 0         trailingZeros = e2 < e10 || (e2 - e10 < 64 && multipleOfPowerOf2(m10, e2 - e10));
    0          
    0          
208             } else {
209 0           e2 = floor_log2(m10) + e10 - ceil_log2pow5(-e10) - (DOUBLE_MANTISSA_BITS + 1);
210 0           int j = e2 - e10 + ceil_log2pow5(-e10) - 1 + DOUBLE_POW5_INV_BITCOUNT;
211             #if defined(RYU_OPTIMIZE_SIZE)
212             uint64_t pow5[2];
213             double_computeInvPow5(-e10, pow5);
214             m2 = mulShift64(m10, pow5, j);
215             #else
216 0 0         assert(-e10 < DOUBLE_POW5_INV_TABLE_SIZE);
217 0           m2 = mulShift64(m10, DOUBLE_POW5_INV_SPLIT[-e10], j);
218             #endif
219 0           trailingZeros = multipleOfPowerOf5(m10, -e10);
220             }
221              
222             #ifdef RYU_DEBUG
223 0           printf("m2 * 2^e2 = %" PRIu64 " * 2^%d\n", m2, e2);
224             #endif
225              
226             // Compute the final IEEE exponent.
227 0           uint32_t ieee_e2 = (uint32_t) max32(0, e2 + DOUBLE_EXPONENT_BIAS + floor_log2(m2));
228              
229 0 0         if (ieee_e2 > 0x7fe) {
230             // Final IEEE exponent is larger than the maximum representable; return +/-Infinity.
231 0           uint64_t ieee = (((uint64_t) signedM) << (DOUBLE_EXPONENT_BITS + DOUBLE_MANTISSA_BITS)) | (0x7ffull << DOUBLE_MANTISSA_BITS);
232 0           *result = int64Bits2Double(ieee);
233 0           return SUCCESS;
234             }
235              
236             // We need to figure out how much we need to shift m2. The tricky part is that we need to take
237             // the final IEEE exponent into account, so we need to reverse the bias and also special-case
238             // the value 0.
239 0 0         int32_t shift = (ieee_e2 == 0 ? 1 : ieee_e2) - e2 - DOUBLE_EXPONENT_BIAS - DOUBLE_MANTISSA_BITS;
240 0 0         assert(shift >= 0);
241             #ifdef RYU_DEBUG
242 0           printf("ieee_e2 = %d\n", ieee_e2);
243 0           printf("shift = %d\n", shift);
244             #endif
245              
246             // We need to round up if the exact value is more than 0.5 above the value we computed. That's
247             // equivalent to checking if the last removed bit was 1 and either the value was not just
248             // trailing zeros or the result would otherwise be odd.
249             //
250             // We need to update trailingZeros given that we have the exact output exponent ieee_e2 now.
251 0           trailingZeros &= (m2 & ((1ull << (shift - 1)) - 1)) == 0;
252 0           uint64_t lastRemovedBit = (m2 >> (shift - 1)) & 1;
253 0 0         bool roundUp = (lastRemovedBit != 0) && (!trailingZeros || (((m2 >> shift) & 1) != 0));
    0          
    0          
254              
255             #ifdef RYU_DEBUG
256 0           printf("roundUp = %d\n", roundUp);
257 0           printf("ieee_m2 = %" PRIu64 "\n", (m2 >> shift) + roundUp);
258             #endif
259 0           uint64_t ieee_m2 = (m2 >> shift) + roundUp;
260 0 0         assert(ieee_m2 <= (1ull << (DOUBLE_MANTISSA_BITS + 1)));
261 0           ieee_m2 &= (1ull << DOUBLE_MANTISSA_BITS) - 1;
262 0 0         if (ieee_m2 == 0 && roundUp) {
    0          
263             // Due to how the IEEE represents +/-Infinity, we don't need to check for overflow here.
264 0           ieee_e2++;
265             }
266              
267 0           uint64_t ieee = (((((uint64_t) signedM) << DOUBLE_EXPONENT_BITS) | (uint64_t)ieee_e2) << DOUBLE_MANTISSA_BITS) | ieee_m2;
268 0           *result = int64Bits2Double(ieee);
269 0           return SUCCESS;
270             }
271              
272 0           enum Status s2d(const char * buffer, double * result) {
273 0           return s2d_n(buffer, strlen(buffer), result);
274             }