Ruby 4.1.0dev (2026-11-05 revision 15d19e341cedf69b35a840d21328374927e50ec9)
double.c
1#include "prism/internal/double.h"
2
3#include "prism/internal/bignum.h"
4#include "prism/internal/bit.h"
5
6#include <assert.h>
7#include <float.h>
8#include <stdbool.h>
9#include <stdint.h>
10#include <string.h>
11
12/* The conversion builds the bits of the result directly, so it depends on the
13 * layout of a binary64 double. */
14#if FLT_RADIX != 2 || DBL_MANT_DIG != 53 || DBL_MIN_EXP != -1021 || DBL_MAX_EXP != 1024
15#error "prism requires IEEE 754 binary64 doubles"
16#endif
17
21#define PM_DOUBLE_DIGITS 768
22
26#define PM_DOUBLE_WORDS 84
27
34#define PM_DOUBLE_EXPONENT_MAXIMUM 100000000000000000
35
39#define PM_DOUBLE_INFINITY ((uint64_t) 0x7FF0000000000000)
40
44#define PM_DOUBLE_POWER5_13 1220703125
45
49static const double pm_double_powers[] = {
50 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11,
51 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22
52};
53
57static uint64_t
58pm_double_bit_length(const pm_bignum_t *bignum) {
59 assert(bignum->length > 0);
60 return (uint64_t) (bignum->length - 1) * 32 + pm_bsrll(bignum->words[bignum->length - 1]) + 1;
61}
62
66static void
67pm_double_multiply_powof5(pm_bignum_t *bignum, uint64_t power) {
68 for (; power >= 13; power -= 13) pm_bignum_mul_add(bignum, PM_DOUBLE_POWER5_13, 0);
69
70 uint32_t multiplier = 1;
71 for (; power > 0; power--) multiplier *= 5;
72 if (multiplier > 1) pm_bignum_mul_add(bignum, multiplier, 0);
73}
74
83static uint64_t
84pm_double_divide(pm_bignum_t *numerator, const pm_bignum_t *divisor, bool *inexact) {
85 uint32_t *numerator_words = numerator->words;
86 const uint32_t *divisor_words = divisor->words;
87 uint32_t numerator_length = numerator->length;
88 uint32_t divisor_length = divisor->length;
89
90 assert(divisor_length >= 2 && numerator_length >= divisor_length && (divisor_words[divisor_length - 1] >> 31) == 1);
91
92 uint64_t top = divisor_words[divisor_length - 1];
93 uint64_t next = divisor_words[divisor_length - 2];
94 uint64_t quotient = 0;
95 numerator_words[numerator_length] = 0;
96
97 for (uint32_t index = numerator_length - divisor_length + 1; index > 0; index--) {
98 uint32_t *window = numerator_words + index - 1;
99 uint64_t current = ((uint64_t) window[divisor_length] << 32) | window[divisor_length - 1];
100 uint64_t estimate = current / top;
101 uint64_t remainder = current % top;
102
103 while (estimate > UINT32_MAX || estimate * next > ((remainder << 32) | window[divisor_length - 2])) {
104 estimate--;
105 remainder += top;
106 if (remainder > UINT32_MAX) break;
107 }
108
109 /* A difference below zero wraps around, which sets its top bit. */
110 uint64_t carry = 0;
111 uint64_t borrow = 0;
112
113 for (uint32_t offset = 0; offset < divisor_length; offset++) {
114 uint64_t product = estimate * divisor_words[offset] + carry;
115 carry = product >> 32;
116
117 uint64_t difference = (uint64_t) window[offset] - (uint32_t) product - borrow;
118 window[offset] = (uint32_t) difference;
119 borrow = difference >> 63;
120 }
121
122 uint64_t difference = (uint64_t) window[divisor_length] - carry - borrow;
123 window[divisor_length] = (uint32_t) difference;
124
125 if ((difference >> 63) != 0) {
126 estimate--;
127 carry = 0;
128
129 for (uint32_t offset = 0; offset < divisor_length; offset++) {
130 uint64_t sum = (uint64_t) window[offset] + divisor_words[offset] + carry;
131 window[offset] = (uint32_t) sum;
132 carry = sum >> 32;
133 }
134
135 window[divisor_length] += (uint32_t) carry;
136 }
137
138 assert((quotient >> 32) == 0);
139 quotient = (quotient << 32) | estimate;
140 }
141
142 for (uint32_t index = 0; index < divisor_length; index++) {
143 if (numerator_words[index] != 0) {
144 *inexact = true;
145 break;
146 }
147 }
148
149 return quotient;
150}
151
158static uint64_t
159pm_double_round(uint64_t mantissa, int64_t exponent, bool inexact) {
160 assert(mantissa != 0);
161
162 /* Drop the bits below the 53 that a double keeps, or below the smallest
163 * subnormal if the value is that small. */
164 int64_t shift = (int64_t) pm_bsrll(mantissa) + 1 - 53;
165 if (shift < -1074 - exponent) shift = -1074 - exponent;
166
167 uint64_t bits;
168 if (shift <= 0) {
169 assert(!inexact);
170 bits = mantissa << -shift;
171 } else if (shift > 64) {
172 return 0;
173 } else {
174 uint64_t half = (uint64_t) 1 << (shift - 1);
175 uint64_t rest = mantissa & (half - 1 + half);
176 bits = shift == 64 ? 0 : mantissa >> shift;
177 if (rest > half || (rest == half && (inexact || (bits & 1)))) bits++;
178 }
179
180 /* The bits hold the significand with its implicit bit, so adding the
181 * exponent field on top makes that bit carry into it. That also moves a
182 * subnormal that rounded up into the normal range, and a significand that
183 * rounded up to 2**53 into the next binade. */
184 int64_t scale = exponent + shift;
185 if (scale > 971) return PM_DOUBLE_INFINITY;
186
187 bits += (uint64_t) (scale + 1074) << 52;
188 return bits < PM_DOUBLE_INFINITY ? bits : PM_DOUBLE_INFINITY;
189}
190
195static uint64_t
196pm_double_exact(const uint8_t *start, uint32_t digits, int64_t exponent, uint64_t value) {
197 uint32_t numerator_words[PM_DOUBLE_WORDS] = { 0 };
198 pm_bignum_t numerator = { .length = 0, .words = numerator_words };
199
200 if (digits <= 19) {
201 numerator_words[0] = (uint32_t) value;
202 numerator_words[1] = (uint32_t) (value >> 32);
203 numerator.length = value > UINT32_MAX ? 2 : 1;
204 } else {
205 uint32_t remaining = digits > PM_DOUBLE_DIGITS ? PM_DOUBLE_DIGITS : digits;
206 uint32_t chunk = 0;
207 uint32_t multiplier = 1;
208
209 for (const uint8_t *cursor = start; remaining > 0; cursor++) {
210 if (*cursor < '0' || *cursor > '9') continue;
211
212 chunk = chunk * 10 + (uint32_t) (*cursor - '0');
213 multiplier *= 10;
214 remaining--;
215
216 if (multiplier == 1000000000) {
217 pm_bignum_mul_add(&numerator, multiplier, chunk);
218 chunk = 0;
219 multiplier = 1;
220 }
221 }
222
223 if (digits > PM_DOUBLE_DIGITS) {
224 chunk = chunk * 10 + 1;
225 multiplier *= 10;
226 exponent += (int64_t) (digits - PM_DOUBLE_DIGITS) - 1;
227 }
228
229 if (multiplier > 1) pm_bignum_mul_add(&numerator, multiplier, chunk);
230 }
231
232 bool inexact = false;
233 uint64_t mantissa;
234 int64_t binary;
235
236 /* Since 10**exp is 5**exp * 2**exp, only the power of five needs
237 * arithmetic; the power of 2 goes into the binary exponent. */
238 if (exponent >= 0) {
239 /* Multiply by the power of five and round the top 64 bits. */
240 pm_double_multiply_powof5(&numerator, (uint64_t) exponent);
241
242 uint64_t length = pm_double_bit_length(&numerator);
243 binary = exponent;
244
245 if (length > 64) {
246 uint64_t dropped = length - 64;
247 inexact = pm_bignum_trailing_zeros(&numerator) < dropped;
248 pm_bignum_shift_right(&numerator, (size_t) dropped);
249 binary += (int64_t) dropped;
250 }
251
252 mantissa = pm_bignum_uint64(&numerator);
253 } else {
254 /* Divide by the power of five and round the 64-bit quotient. */
255 uint32_t denominator_words[PM_DOUBLE_WORDS];
256 pm_bignum_t denominator = { .length = 1, .words = denominator_words };
257
258 denominator_words[0] = 1;
259 pm_double_multiply_powof5(&denominator, (uint64_t) -exponent);
260
261 /* Shift the denominator so that its top bit is set and it has at least
262 * two words, and the numerator so that it has 63 more bits than the
263 * denominator. If the numerator is already longer than that, the
264 * denominator shifts by more whole words instead. */
265 int64_t numerator_bits = (int64_t) pm_double_bit_length(&numerator);
266 int64_t denominator_bits = (int64_t) pm_double_bit_length(&denominator);
267
268 int64_t denominator_shift = (32 - denominator_bits % 32) % 32;
269 if (denominator_bits + denominator_shift == 32) denominator_shift += 32;
270
271 int64_t numerator_shift = 63 + denominator_bits + denominator_shift - numerator_bits;
272 if (numerator_shift < 0) {
273 denominator_shift += (31 - numerator_shift) / 32 * 32;
274 numerator_shift = 63 + denominator_bits + denominator_shift - numerator_bits;
275 }
276
277 pm_bignum_shift_left(&numerator, (size_t) numerator_shift);
278 pm_bignum_shift_left(&denominator, (size_t) denominator_shift);
279 assert(numerator.length < PM_DOUBLE_WORDS && denominator.length <= PM_DOUBLE_WORDS);
280
281 mantissa = pm_double_divide(&numerator, &denominator, &inexact);
282 binary = exponent + denominator_shift - numerator_shift;
283 }
284
285 return pm_double_round(mantissa, binary, inexact);
286}
287
291double
292pm_double_parse(const uint8_t *start, const uint8_t *end, bool *out_of_range) {
293 *out_of_range = false;
294 if (start < end && *start == '+') start++;
295
296 const uint8_t *first = NULL;
297 const uint8_t *cursor = start;
298
299 uint32_t digits = 0;
300 uint32_t zeros = 0;
301
302 uint64_t value = 0;
303 int64_t exponent = 0;
304
305 bool fraction = false;
306 bool e = false;
307
308 for (; !e && cursor < end; cursor++) {
309 switch (*cursor) {
310 case '_':
311 break;
312 case '.':
313 fraction = true;
314 break;
315 case 'e': case 'E':
316 e = true;
317 break;
318 case '0':
319 if (fraction) exponent--;
320 if (first != NULL) zeros++;
321 break;
322 case '1': case '2': case '3': case '4': case '5':
323 case '6': case '7': case '8': case '9':
324 if (fraction) exponent--;
325 if (first == NULL) first = cursor;
326
327 digits += zeros + 1;
328 if (digits <= 19) {
329 for (; zeros > 0; zeros--) value *= 10;
330 value = value * 10 + (uint64_t) (*cursor - '0');
331 } else {
332 zeros = 0;
333 }
334 break;
335 default:
336 assert(false && "unreachable");
337 break;
338 }
339 }
340
341 exponent += (int64_t) zeros;
342 if (digits == 0) return 0.0;
343
344 if (e) {
345 bool positive = true;
346 if (cursor < end && (*cursor == '+' || *cursor == '-')) {
347 positive = *cursor == '+';
348 cursor++;
349 }
350
351 int64_t power = 0;
352 for (; cursor < end; cursor++) {
353 if (*cursor != '_' && power < PM_DOUBLE_EXPONENT_MAXIMUM) power = power * 10 + (*cursor - '0');
354 }
355
356 exponent += positive ? power : -power;
357 }
358
359 int64_t magnitude = (int64_t) digits + exponent;
360 uint64_t bits;
361
362 if (magnitude > 309) {
363 bits = PM_DOUBLE_INFINITY;
364 } else if (magnitude < -323) {
365 bits = 0;
366 } else {
367 /* When the digits and the power of ten are both exactly representable,
368 * a single correctly rounded multiplication or division gives the
369 * result. When the power is too large but the digits have room, part
370 * of the power moves into the digits. This depends on the operation
371 * rounding once, to a double, rather than to a wider type first. */
372#if defined(FLT_EVAL_METHOD) && FLT_EVAL_METHOD == 0
373 if (digits <= 19 && value <= ((uint64_t) 1 << 53)) {
374 if (exponent >= -22 && exponent < 0) {
375 return (double) value / pm_double_powers[-exponent];
376 } else if (exponent >= 0 && exponent <= 22) {
377 return (double) value * pm_double_powers[exponent];
378 } else if (exponent > 22 && exponent <= 22 + 15) {
379 uint64_t scaled = value;
380 for (int64_t power = exponent; power > 22 && scaled <= ((uint64_t) 1 << 53); power--) scaled *= 10;
381 if (scaled <= ((uint64_t) 1 << 53)) return (double) scaled * 1e22;
382 }
383 }
384#endif
385
386 bits = pm_double_exact(first, digits, exponent, value);
387 }
388
389 *out_of_range = bits == 0 || bits == PM_DOUBLE_INFINITY;
390
391 double result;
392 memcpy(&result, &bits, sizeof(double));
393 return result;
394}
C99 shim for <stdbool.h>