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( 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) 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) 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 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 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) 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) 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) 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) 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. 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