1 //
2 // cvt.cpp
3 //
4 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //
6 // Functions for formatting floating point values with the %a, %e, %f, and %g
7 // printf format specifiers.
8 //
9 #include <corecrt_internal.h>
10 #include <corecrt_internal_ptd_propagation.h>
11 #include <ctype.h>
12 #include <string.h>
13 #include <math.h>
14 #include <locale.h>
15 #include <corecrt_internal_fltintrn.h>
16 #include <fenv.h>
17 #include <float.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <stddef.h>
21
22 // The C String pointed to by string is shifted distance bytes to the right.
23 // If distance is negative, the string is shifted to the left.
24 // The C String pointed to by string and all shifting operations must be
25 // contained within buffer_base or buffer_count.
26 static void __cdecl shift_bytes(
_Maybe_unsafe_(_Inout_updates_z_,buffer_count)27 _Maybe_unsafe_(_Inout_updates_z_, buffer_count) char * const buffer_base,
28 _In_ size_t const buffer_count,
29 _In_range_(buffer_base, buffer_base + buffer_count) char* const string,
30 _In_ int const distance
31 ) throw()
32 {
33 UNREFERENCED_PARAMETER(buffer_base);
34 UNREFERENCED_PARAMETER(buffer_count);
35
36 if (distance != 0)
37 {
38 memmove(string + distance, string, strlen(string) + 1);
39 }
40 }
41
42
43 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
44 //
45 // NaN and Infinity Formatting
46 //
47 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
48 _Success_(return == 0)
49 static errno_t __cdecl fp_format_nan_or_infinity(
50 _In_ __acrt_fp_class const classification,
51 _In_range_(0,1) bool const is_negative,
52 _Maybe_unsafe_(_Out_writes_z_, result_buffer_count) char* result_buffer,
53 _In_range_(1,SIZE_MAX) size_t result_buffer_count,
54 _In_range_(0,1) bool const use_capitals
55 ) throw()
56 {
57 using floating_traits = __acrt_floating_type_traits<double>;
58 using components_type = floating_traits::components_type;
59
60 // Ensure that we have sufficient space to store at least the basic three-
61 // character INF or NAN string, plus the minus sign if required:
62 if (result_buffer_count < _countof("INF") + is_negative)
63 {
64 *result_buffer = '\0';
65 return ENOMEM;
66 }
67
68 if (is_negative)
69 {
70 *result_buffer++ = '-';
71 *result_buffer = '\0';
72 if (result_buffer_count != _CRT_UNBOUNDED_BUFFER_SIZE)
73 {
74 --result_buffer_count;
75 }
76 }
77
78 static char const* const strings[][4] =
79 {
80 { "INF", "INF", "inf", "inf" }, // Infinity
81 { "NAN", "NAN", "nan", "nan" }, // Quiet NAN
82 { "NAN(SNAN)", "NAN", "nan(snan)", "nan" }, // Signaling NAN
83 { "NAN(IND)", "NAN", "nan(ind)", "nan" }, // Indeterminate
84 };
85
86 uint32_t const row = static_cast<uint32_t>(classification) - 1;
87 uint32_t const column = use_capitals ? 0 : 2;
88
89 bool const long_string_will_fit = result_buffer_count > strlen(strings[row][column]);
90 _ERRCHECK(strcpy_s(
91 result_buffer,
92 result_buffer_count,
93 strings[row][column + !long_string_will_fit]));
94 return 0;
95 }
96
97
98
99 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
100 //
101 // %e formatting
102 //
103 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
104 // These functions handle the formatting of floating point values in the %e
105 // printf format. This format has the form [-]d.ddde(+/-)ddd, where there will
106 // be 'precision' digits following the decimal point. If the precision is less
107 // than or equal to zero, no decimal point will appear. The low order digit is
108 // rounded. If 'capitals' is true, then the exponent will appear as E(+/-)ddd.
109 _Success_(return == 0)
fp_format_e_internal(_Maybe_unsafe_ (_Inout_updates_z_,result_buffer_count)char * const result_buffer,_In_fits_precision_ (precision)size_t const result_buffer_count,_In_ int const precision,_In_ bool const capitals,_In_ unsigned const min_exponent_digits,_In_ STRFLT const pflt,_In_ bool const g_fmt,_Inout_ __crt_cached_ptd_host & ptd)110 static errno_t fp_format_e_internal(
111 _Maybe_unsafe_(_Inout_updates_z_, result_buffer_count) char* const result_buffer,
112 _In_fits_precision_(precision) size_t const result_buffer_count,
113 _In_ int const precision,
114 _In_ bool const capitals,
115 _In_ unsigned const min_exponent_digits,
116 _In_ STRFLT const pflt,
117 _In_ bool const g_fmt,
118 _Inout_ __crt_cached_ptd_host& ptd
119 ) throw()
120 {
121 // The max length if calculated like this:
122 // 3 = sign + first digit + decimal point
123 // precision = decimal digits
124 // 5 = exponent letter (e or E), exponent sign, three digits exponent
125 // 1 = extra space for rounding
126 _UCRT_VALIDATE_RETURN_ERRCODE(ptd, result_buffer_count > static_cast<size_t>(3 + (precision > 0 ? precision : 0) + 5 + 1), ERANGE);
127
128 // Place the output in the buffer and round. Leave space in the buffer
129 // for the '-' sign (if any) and the decimal point (if any):
130 if (g_fmt)
131 {
132 // Shift it right one place if nec. for decimal point:
133 char* const p = result_buffer + (pflt->sign == '-');
134 shift_bytes(result_buffer, result_buffer_count, p, precision > 0);
135 }
136
137 // Now fix the number up to be in e format:
138 char* p = result_buffer;
139
140 // Put in negative sign if needed:
141 if (pflt->sign == '-')
142 *p++ = '-';
143
144 // Put in decimal point if needed. Copy the first digit to the place left
145 // for it and put the decimal point in its place:
146 if (precision > 0)
147 {
148 *p = *(p + 1);
149 *++p = *ptd.get_locale()->locinfo->lconv->decimal_point;
150 }
151
152 // Find the end of the string, attach the exponent field and save the
153 // exponent position:
154 p = p + precision + (g_fmt ? 0 : 1);
155 _ERRCHECK(strcpy_s(
156 p,
157 result_buffer_count == _CRT_UNBOUNDED_BUFFER_SIZE
158 ? result_buffer_count
159 : result_buffer_count - (p - result_buffer), "e+000"));
160 char* exponentpos = p + 2;
161
162 // Adjust exponent indicator according to capitals flag and increment
163 // pointer to point to exponent sign:
164 if (capitals)
165 *p = 'E';
166
167 ++p;
168
169 // If mantissa is zero, then the number is 0 and we are done; otherwise
170 // adjust the exponent sign (if necessary) and value:
171 if (*pflt->mantissa != '0')
172 {
173 // Check to see if exponent is negative; if so adjust exponent sign and
174 // exponent value:
175 int exp = pflt->decpt - 1;
176 if (exp < 0)
177 {
178 exp = -exp;
179 *p = '-';
180 }
181
182 ++p;
183
184 if (exp >= 100)
185 {
186 *p += static_cast<char>(exp / 100);
187 exp %= 100;
188 }
189
190 ++p;
191
192 if (exp >= 10)
193 {
194 *p += static_cast<char>(exp / 10);
195 exp %= 10;
196 }
197
198 *++p += static_cast<char>(exp);
199 }
200
201 if (min_exponent_digits == 2)
202 {
203 // If possible, reduce the exponent to two digits:
204 if (*exponentpos == '0')
205 {
206 memmove(exponentpos, exponentpos + 1, 3);
207 }
208 }
209
210 return 0;
211 }
212
213 _Success_(return == 0)
fp_format_e(_In_ double const * const argument,_Maybe_unsafe_ (_Inout_updates_z_,result_buffer_count)char * const result_buffer,_In_fits_precision_ (precision)size_t const result_buffer_count,_Out_writes_ (scratch_buffer_count)char * const scratch_buffer,_In_ size_t const scratch_buffer_count,_In_ int const precision,_In_ bool const capitals,_In_ unsigned const min_exponent_digits,_In_ __acrt_rounding_mode const rounding_mode,_Inout_ __crt_cached_ptd_host & ptd)214 static errno_t __cdecl fp_format_e(
215 _In_ double const* const argument,
216 _Maybe_unsafe_(_Inout_updates_z_, result_buffer_count) char* const result_buffer,
217 _In_fits_precision_(precision) size_t const result_buffer_count,
218 _Out_writes_(scratch_buffer_count) char* const scratch_buffer,
219 _In_ size_t const scratch_buffer_count,
220 _In_ int const precision,
221 _In_ bool const capitals,
222 _In_ unsigned const min_exponent_digits,
223 _In_ __acrt_rounding_mode const rounding_mode,
224 _Inout_ __crt_cached_ptd_host& ptd
225 ) throw()
226 {
227 // The precision passed to __acrt_fltout is the number of fractional digits.
228 // To ensure that we get enough digits, we require a total of precision + 1 digits,
229 // to account for the digit placed to the left of the decimal point when all digits are fractional.
230 _strflt strflt;
231
232 __acrt_has_trailing_digits const trailing_digits = __acrt_fltout(
233 *reinterpret_cast<_CRT_DOUBLE const*>(argument),
234 precision + 1,
235 __acrt_precision_style::scientific,
236 &strflt,
237 scratch_buffer,
238 scratch_buffer_count
239 );
240
241 errno_t const e = __acrt_fp_strflt_to_string(
242 result_buffer + (strflt.sign == '-') + (precision > 0),
243 (result_buffer_count == _CRT_UNBOUNDED_BUFFER_SIZE
244 ? result_buffer_count
245 : result_buffer_count - (strflt.sign == '-') - (precision > 0)),
246 precision + 1,
247 &strflt,
248 trailing_digits,
249 rounding_mode,
250 ptd);
251
252 if (e != 0)
253 {
254 result_buffer[0] = '\0';
255 return e;
256 }
257
258 return fp_format_e_internal(result_buffer, result_buffer_count, precision, capitals, min_exponent_digits, &strflt, false, ptd);
259 }
260
fe_to_nearest(double const * const argument,unsigned __int64 const mask,short const maskpos)261 static bool fe_to_nearest(double const* const argument, unsigned __int64 const mask, short const maskpos)
262 {
263 using floating_traits = __acrt_floating_type_traits<double>;
264 using components_type = floating_traits::components_type;
265 components_type const* const components = reinterpret_cast<components_type const*>(argument);
266
267 unsigned short digit = static_cast<unsigned short>((components->_mantissa & mask) >> maskpos);
268
269 if (digit > 8)
270 {
271 return true;
272 }
273
274 if (digit < 8)
275 {
276 return false;
277 }
278
279 unsigned __int64 const roundBitsMask = (static_cast<unsigned __int64>(1) << maskpos) - 1;
280 if (components->_mantissa & roundBitsMask)
281 {
282 return true;
283 }
284
285 //if we still have digits to the left to compare
286 if (maskpos != DBL_MANT_DIG - 5)
287 {
288 // We divide the mantisa by 16 to move the digits to the right, after that we apply the mask
289 // to get the digit at the left.
290 digit = static_cast<unsigned short>(((components->_mantissa / 16) & mask) >> maskpos);
291 }
292 else
293 {
294 digit = components->_exponent == 0 ? 0 : 1;
295 }
296
297 return digit % 2 == 1;
298 }
299
should_round_up(double const * const argument,unsigned __int64 const mask,short const maskpos,__acrt_rounding_mode const rounding_mode)300 static bool should_round_up(double const* const argument, unsigned __int64 const mask, short const maskpos, __acrt_rounding_mode const rounding_mode)
301 {
302 using floating_traits = __acrt_floating_type_traits<double>;
303 using components_type = floating_traits::components_type;
304 components_type const* const components = reinterpret_cast<components_type const*>(argument);
305
306 unsigned short const digit = static_cast<unsigned short>((components->_mantissa & mask) >> maskpos);
307
308 if (rounding_mode == __acrt_rounding_mode::legacy)
309 {
310 return digit >= 8;
311 }
312 int const round_mode = fegetround();
313
314 if (round_mode == FE_TONEAREST)
315 {
316 return fe_to_nearest(argument, mask, maskpos);
317 }
318
319 if (round_mode == FE_UPWARD)
320 {
321 return digit != 0 && !components->_sign;
322 }
323
324 if (round_mode == FE_DOWNWARD)
325 {
326 return digit != 0 && components->_sign;
327 }
328
329 return false;
330 }
331
332 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
333 //
334 // %a formatting
335 //
336 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
337 // These functions handle the formatting of floating point values in the %a
338 // printf format. This format has the form [-]0xh.hhhhp(+/-)d, where there will
339 // be 'precision' hex digits following the decimal point. If the precision is
340 // less than or equal to zero, no decimal point will appear. If 'capitals' is
341 // true, then the number will appear as [-]0xH.HHHHP(+/-)d.
342 _Success_(return == 0)
fp_format_a(_In_ double const * const argument,_Maybe_unsafe_ (_Inout_updates_z_,result_buffer_count)char * result_buffer,_In_fits_precision_ (precision)size_t const result_buffer_count,_Out_writes_ (scratch_buffer_count)char * const scratch_buffer,_In_ size_t const scratch_buffer_count,_In_ int precision,_In_ bool const capitals,_In_ unsigned const min_exponent_digits,_In_ __acrt_rounding_mode const rounding_mode,_Inout_ __crt_cached_ptd_host & ptd)343 static errno_t __cdecl fp_format_a(
344 _In_ double const* const argument,
345 _Maybe_unsafe_(_Inout_updates_z_, result_buffer_count) char* result_buffer,
346 _In_fits_precision_(precision) size_t const result_buffer_count,
347 _Out_writes_(scratch_buffer_count) char* const scratch_buffer,
348 _In_ size_t const scratch_buffer_count,
349 _In_ int precision,
350 _In_ bool const capitals,
351 _In_ unsigned const min_exponent_digits,
352 _In_ __acrt_rounding_mode const rounding_mode,
353 _Inout_ __crt_cached_ptd_host& ptd
354 )
355 {
356 using floating_traits = __acrt_floating_type_traits<double>;
357 using components_type = floating_traits::components_type;
358
359 if (precision < 0)
360 {
361 precision = 0;
362 }
363
364 result_buffer[0] = '\0';
365
366 // the constraint for the size of buffer is:
367 // 1 (sign)
368 // 4 ("0xh.")
369 // precision (decimal digits)
370 // 6 ("p+0000")
371 _UCRT_VALIDATE_RETURN_ERRCODE(ptd, result_buffer_count > static_cast<size_t>(1 + 4 + precision + 6), ERANGE);
372
373 // Let __acrt_fp_format_e handle the special cases like SNAN, etc.:
374 components_type const* const components = reinterpret_cast<components_type const*>(argument);
375 if (components->_exponent == floating_traits::exponent_mask)
376 {
377 errno_t const e = fp_format_e(
378 argument,
379 result_buffer,
380 result_buffer_count,
381 scratch_buffer,
382 scratch_buffer_count,
383 precision,
384 false,
385 min_exponent_digits,
386 rounding_mode,
387 ptd);
388
389 if (e != 0)
390 {
391 // An error occurred
392 result_buffer[0] = '\0';
393 return e;
394 }
395
396 // Substitute the e with p:
397 char* p = strrchr(result_buffer, 'e');
398 if (p)
399 {
400 *p = capitals ? 'P' : 'p';
401
402 // Trim the exponent (which is 0) to only one digit; skip the
403 // exponent sign and the first digit and put the terminating 0:
404 p += 3;
405 *p = 0;
406 }
407 return e;
408 }
409
410 // Sign:
411 if (components->_sign)
412 {
413 *result_buffer++ = '-';
414 }
415
416 int const hexadd = (capitals ? 'A' : 'a') - '9' - 1;
417
418 // Leading digit (and set the debias):
419 unsigned __int64 debias = floating_traits::exponent_bias;
420 if (components->_exponent == 0)
421 {
422 *result_buffer++ = '0';
423 if (components->_mantissa == 0)
424 {
425 // Zero:
426 debias = 0;
427 }
428 else
429 {
430 // Denormal:
431 debias--;
432 }
433 }
434 else
435 {
436 *result_buffer++ = '1';
437 }
438
439 // Decimal point (save the position in pos):
440 char* pos = result_buffer++;
441 if (precision == 0)
442 {
443 // If precision is 0, then we don't have to print the decimal point:
444 // we mark this putting 0 instead of the decimal point itself
445 *pos = 0;
446 }
447 else
448 {
449 *pos = *ptd.get_locale()->locinfo->lconv->decimal_point;
450 }
451
452 // Mantissa:
453 if (components->_mantissa > 0)
454 {
455 // Print 4 bits at a time, and skip the initial zeroes
456 // Prepare the mask to read the first 4 bits
457 short maskpos = (floating_traits::mantissa_bits - 1) - 4;
458
459 unsigned __int64 mask = 0xf;
460 mask <<= maskpos;
461
462 while (maskpos >= 0 && precision > 0)
463 {
464 unsigned short digit = static_cast<unsigned short>((components->_mantissa & mask) >> maskpos);
465 digit += '0';
466 if (digit > '9')
467 {
468 digit += static_cast<unsigned short>(hexadd);
469 }
470 *result_buffer++ = static_cast<char>(digit);
471 mask >>= 4;
472 maskpos -= 4;
473 --precision;
474 }
475
476 // Round the mantissa:
477 if (maskpos >= 0)
478 {
479 if (should_round_up(argument, mask, maskpos, rounding_mode))
480 {
481 char* p = result_buffer;
482 --p;
483 // If the last digit is 'f', we need to add one to the previous
484 // digit, too; pos is the position of the decimal point
485 while (*p == 'f' || *p == 'F')
486 {
487 *p-- = '0';
488 }
489 // If we reached the decimal point, it means we are rounding
490 // something like 0x0.fffff so this will become 0x1.00000 :
491 if (p != pos)
492 {
493 if (*p == '9')
494 {
495 *p += static_cast<char>(1 + hexadd);
496 }
497 else
498 {
499 *p += 1;
500 }
501 }
502 else // p == pos
503 {
504 // Skip the decimal point:
505 --p;
506
507 // The first digit is always 0 or 1, so we don't need to
508 // add hexadd:
509 *p += 1;
510 }
511 }
512 }
513 }
514
515 // Add the final zeroes, if needed:
516 for (; precision > 0; --precision)
517 {
518 *result_buffer++ = '0';
519 }
520
521 // Move back the buffer pointer if there is no decimal point:
522 if (*pos == 0)
523 {
524 result_buffer = pos;
525 }
526
527 // Exponent:
528 *result_buffer++ = capitals ? 'P' : 'p';
529 __int64 exponent = components->_exponent - debias;
530 if (exponent >= 0)
531 {
532 *result_buffer++ = '+';
533 }
534 else
535 {
536 *result_buffer++ = '-';
537 exponent = -exponent;
538 }
539 // Save the position in pos and write a '0':
540 pos = result_buffer;
541 *pos = '0';
542
543 if (exponent >= 1000)
544 {
545 *result_buffer++ = '0' + static_cast<char>(exponent / 1000);
546 exponent %= 1000;
547 }
548 if (result_buffer != pos || exponent >= 100)
549 {
550 *result_buffer++ = '0' + static_cast<char>(exponent / 100);
551 exponent %= 100;
552 }
553 if (result_buffer != pos || exponent >= 10)
554 {
555 *result_buffer++ = '0' + static_cast<char>(exponent / 10);
556 exponent %= 10;
557 }
558
559 *result_buffer++ = '0' + static_cast<char>(exponent);
560
561 // Terminate the string:
562 *result_buffer = '\0';
563
564 return 0;
565 }
566
567
568
569 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
570 //
571 // %f formatting
572 //
573 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
574 // These functions handle the formatting of floating point values in the %f
575 // printf format. This format has the form [-]ddddd.ddddd, where there will be
576 // precision digits following the decimal point. If precision is less than or
577 // equal to zero, no decimal point will appear. The low order digit is rounded.
578 _Success_(return == 0)
fp_format_f_internal(_Pre_z_ _Maybe_unsafe_ (_Inout_updates_z_,buffer_count)char * const buffer,_In_fits_precision_ (precision)size_t const buffer_count,_In_ int const precision,_In_ STRFLT const pflt,_In_ bool const g_fmt,_Inout_ __crt_cached_ptd_host & ptd)579 static errno_t fp_format_f_internal(
580 _Pre_z_ _Maybe_unsafe_(_Inout_updates_z_, buffer_count) char* const buffer,
581 _In_fits_precision_(precision) size_t const buffer_count,
582 _In_ int const precision,
583 _In_ STRFLT const pflt,
584 _In_ bool const g_fmt,
585 _Inout_ __crt_cached_ptd_host& ptd
586 ) throw()
587 {
588 int const g_magnitude = pflt->decpt - 1;
589
590 // Place the output in the user's buffer and round. Save space for the
591 // minus sign now if it will be needed:
592 if (g_fmt && g_magnitude == precision)
593 {
594 char* const p = g_magnitude + buffer + (pflt->sign == '-');
595 p[0] = '0';
596 p[1] = '\0';
597
598 // Allows for extra place-holding '0' in the exponent == precision case
599 // of the %g format.
600 }
601
602 // Now fix up the number to be in the correct %f format:
603 char* p = buffer;
604
605 // Put in a negative sign, if necessary:
606 if (pflt->sign == '-')
607 *p++ = '-';
608
609 // Insert a leading zero for purely fractional values and position ourselves
610 // at the correct spot for inserting the decimal point:
611 if (pflt->decpt <= 0)
612 {
613 // In the specific scenario of the 0 when using g format this would cause
614 // to have an extra zero at the end
615 bool const is_zero_pflt = pflt->decpt == 0 && *pflt->mantissa == '0';
616 if (!g_fmt || !is_zero_pflt) {
617 shift_bytes(buffer, buffer_count, p, 1);
618 }
619 *p++ = '0';
620 }
621 else
622 {
623 p += pflt->decpt;
624 }
625
626 // Put a decimal point if required, and add any needed zero padding:
627 if (precision > 0)
628 {
629 shift_bytes(buffer, buffer_count, p, 1);
630 *p++ = *ptd.get_locale()->locinfo->lconv->decimal_point;
631
632 // If the value is less than 1 then we may need to put zeroes out in
633 // front of the first non-zero digit of the mantissa:
634 if (pflt->decpt < 0)
635 {
636 int const computed_precision = (g_fmt || -pflt->decpt < precision)
637 ? -pflt->decpt
638 : precision;
639
640 shift_bytes(buffer, buffer_count, p, computed_precision);
641 memset(p, '0', computed_precision);
642 }
643 }
644
645 return 0;
646 }
647
648 _Success_(return == 0)
fp_format_f(_In_ double const * const argument,_Maybe_unsafe_ (_Inout_updates_z_,result_buffer_count)char * const result_buffer,_In_fits_precision_ (precision)size_t const result_buffer_count,_Out_writes_ (scratch_buffer_count)char * const scratch_buffer,_In_ size_t const scratch_buffer_count,_In_ int const precision,_In_ __acrt_rounding_mode const rounding_mode,_Inout_ __crt_cached_ptd_host & ptd)649 static errno_t __cdecl fp_format_f(
650 _In_ double const* const argument,
651 _Maybe_unsafe_(_Inout_updates_z_, result_buffer_count) char* const result_buffer,
652 _In_fits_precision_(precision) size_t const result_buffer_count,
653 _Out_writes_(scratch_buffer_count) char* const scratch_buffer,
654 _In_ size_t const scratch_buffer_count,
655 _In_ int const precision,
656 _In_ __acrt_rounding_mode const rounding_mode,
657 _Inout_ __crt_cached_ptd_host& ptd
658 ) throw()
659 {
660 _strflt strflt{};
661 __acrt_has_trailing_digits const trailing_digits = __acrt_fltout(
662 *reinterpret_cast<_CRT_DOUBLE const*>(argument),
663 precision,
664 __acrt_precision_style::fixed,
665 &strflt,
666 scratch_buffer,
667 scratch_buffer_count
668 );
669
670 errno_t const e = __acrt_fp_strflt_to_string(
671 result_buffer + (strflt.sign == '-'),
672 (result_buffer_count == _CRT_UNBOUNDED_BUFFER_SIZE ? result_buffer_count : result_buffer_count - (strflt.sign == '-')),
673 precision + strflt.decpt,
674 &strflt,
675 trailing_digits,
676 rounding_mode,
677 ptd);
678
679 if (e != 0)
680 {
681 result_buffer[0] = '\0';
682 return e;
683 }
684
685 return fp_format_f_internal(result_buffer, result_buffer_count, precision, &strflt, false, ptd);
686 }
687
688
689
690 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
691 //
692 // %g formatting
693 //
694 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
695 // These functions handle the formatting of floating point values in the %g
696 // printf format. The form used depends on the value converted. The printf %e
697 // form will be used if the magnitude of the value is less than -4 or is greater
698 // than 'precision', otherwise %f will be used. The 'precision' always specifies
699 // the number of digits following the decimal point. The low order digit is
700 // appropriately rounded.
701 _Success_(return == 0)
fp_format_g(_In_ double const * const argument,_Maybe_unsafe_ (_Inout_updates_z_,result_buffer_count)char * const result_buffer,_In_fits_precision_ (precision)size_t const result_buffer_count,_Out_writes_ (scratch_buffer_count)char * const scratch_buffer,_In_ size_t const scratch_buffer_count,_In_ int const precision,_In_ bool const capitals,_In_ unsigned const min_exponent_digits,_In_ __acrt_rounding_mode const rounding_mode,_Inout_ __crt_cached_ptd_host & ptd)702 static errno_t __cdecl fp_format_g(
703 _In_ double const* const argument,
704 _Maybe_unsafe_(_Inout_updates_z_, result_buffer_count) char* const result_buffer,
705 _In_fits_precision_(precision) size_t const result_buffer_count,
706 _Out_writes_(scratch_buffer_count) char* const scratch_buffer,
707 _In_ size_t const scratch_buffer_count,
708 _In_ int const precision,
709 _In_ bool const capitals,
710 _In_ unsigned const min_exponent_digits,
711 _In_ __acrt_rounding_mode const rounding_mode,
712 _Inout_ __crt_cached_ptd_host& ptd
713 ) throw()
714 {
715 _strflt strflt{};
716
717 // Generate digits as though we will use %f formatting, then decide based on the result
718 // whether to use %f or %e formatting. %f always requires more generated digits than %e,
719 // so generating them all now will avoid generating more later (generation isn't resumable).
720 __acrt_has_trailing_digits const trailing_digits = __acrt_fltout(
721 *reinterpret_cast<_CRT_DOUBLE const*>(argument),
722 precision,
723 __acrt_precision_style::fixed,
724 &strflt,
725 scratch_buffer,
726 scratch_buffer_count
727 );
728
729 size_t const minus_sign_length = strflt.sign == '-' ? 1 : 0;
730
731 int g_magnitude = strflt.decpt - 1;
732 char* p = result_buffer + minus_sign_length;
733
734 size_t const buffer_count_for_fptostr = result_buffer_count == _CRT_UNBOUNDED_BUFFER_SIZE
735 ? result_buffer_count
736 : result_buffer_count - minus_sign_length;
737
738 errno_t const fptostr_result = __acrt_fp_strflt_to_string(p, buffer_count_for_fptostr, precision, &strflt, trailing_digits, rounding_mode, ptd);
739 if (fptostr_result != 0)
740 {
741 result_buffer[0] = '\0';
742 return fptostr_result;
743 }
744
745 bool const g_round_expansion = g_magnitude < (strflt.decpt - 1);
746
747 // Compute the magnitude of value:
748 g_magnitude = strflt.decpt - 1;
749
750 // Convert value to the C Language g format:
751 if (g_magnitude < -4 || g_magnitude >= precision) // Use e format
752 {
753 // We can ignore the round expansion flag here: the extra digit will be
754 // overwritten by "e+xxx".
755 return fp_format_e_internal(result_buffer, result_buffer_count, precision, capitals, min_exponent_digits, &strflt, true, ptd);
756 }
757 else // Use f format
758 {
759 if (g_round_expansion)
760 {
761 // Throw away extra final digit from expansion:
762 while (*p++)
763 {
764 // Iterate to the end of the string
765 }
766
767 *(p - 2) = '\0';
768 }
769
770 return fp_format_f_internal(result_buffer, result_buffer_count, precision, &strflt, true, ptd);
771 }
772 }
773
774
775
776 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
777 //
778 // Format Dispatch
779 //
780 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
781 // The main floating point formatting dispatch function. This function just
782 // looks at the 'format' character, calls the right formatting function, and
783 // returns the result. The other parameters are passed on to the selected
784 // formatting function and are used as described in the documentation for
785 // those functions.
__acrt_fp_format(double const * const value,char * const result_buffer,size_t const result_buffer_count,char * const scratch_buffer,size_t const scratch_buffer_count,int const format,int const precision,uint64_t const options,__acrt_rounding_mode rounding_mode,__crt_cached_ptd_host & ptd)786 extern "C" errno_t __cdecl __acrt_fp_format(
787 double const* const value,
788 char* const result_buffer,
789 size_t const result_buffer_count,
790 char* const scratch_buffer,
791 size_t const scratch_buffer_count,
792 int const format,
793 int const precision,
794 uint64_t const options,
795 __acrt_rounding_mode rounding_mode,
796 __crt_cached_ptd_host& ptd
797 )
798 {
799 _UCRT_VALIDATE_RETURN_ERRCODE(ptd, result_buffer != nullptr, EINVAL);
800 _UCRT_VALIDATE_RETURN_ERRCODE(ptd, result_buffer_count > 0, EINVAL);
801 _UCRT_VALIDATE_RETURN_ERRCODE(ptd, scratch_buffer != nullptr, EINVAL);
802 _UCRT_VALIDATE_RETURN_ERRCODE(ptd, scratch_buffer_count > 0, EINVAL);
803
804 bool const use_capitals = format == 'A' || format == 'E' || format == 'F' || format == 'G';
805
806 // Detect special cases (NaNs and infinities) and handle them specially.
807 // Note that the underlying __acrt_fltout function will also handle these
808 // special cases, but it does so using the legacy strings (e.g. 1.#INF).
809 // Our special handling here uses the C99 strings (e.g. INF).
810 if ((options & _CRT_INTERNAL_PRINTF_LEGACY_MSVCRT_COMPATIBILITY) == 0)
811 {
812 __acrt_fp_class const classification = __acrt_fp_classify(*value);
813 if (classification != __acrt_fp_class::finite)
814 {
815 return fp_format_nan_or_infinity(
816 classification,
817 __acrt_fp_is_negative(*value),
818 result_buffer,
819 result_buffer_count,
820 use_capitals);
821 }
822 }
823
824 unsigned const min_exponent_digits = (options & _CRT_INTERNAL_PRINTF_LEGACY_THREE_DIGIT_EXPONENTS) != 0 ? 3 : 2;
825 if ((options & _CRT_INTERNAL_PRINTF_STANDARD_ROUNDING) == 0) {
826 rounding_mode = __acrt_rounding_mode::legacy;
827 }
828
829 switch (format)
830 {
831 case 'a':
832 case 'A':
833 return fp_format_a(value, result_buffer, result_buffer_count, scratch_buffer, scratch_buffer_count, precision, use_capitals, min_exponent_digits, rounding_mode, ptd);
834
835 case 'e':
836 case 'E':
837 return fp_format_e(value, result_buffer, result_buffer_count, scratch_buffer, scratch_buffer_count, precision, use_capitals, min_exponent_digits, rounding_mode, ptd);
838
839 case 'f':
840 case 'F':
841 return fp_format_f(value, result_buffer, result_buffer_count, scratch_buffer, scratch_buffer_count, precision, rounding_mode, ptd);
842
843 default:
844 _ASSERTE(("Unsupported format specifier", 0));
845 case 'g':
846 case 'G':
847 return fp_format_g(value, result_buffer, result_buffer_count, scratch_buffer, scratch_buffer_count, precision, use_capitals, min_exponent_digits, rounding_mode, ptd);
848 }
849 }
850