Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850//// cvt.cpp//// Copyright (c) Microsoft Corporation. All rights reserved.//// Functions for formatting floating point values with the %a, %e, %f, and %g// printf format specifiers.//#include <corecrt_internal.h>#include <corecrt_internal_ptd_propagation.h>#include <ctype.h>#include <string.h>#include <math.h>#include <locale.h>#include <corecrt_internal_fltintrn.h>#include <fenv.h>#include <float.h>#include <stdio.h>#include <stdlib.h>#include <stddef.h>
// The C String pointed to by string is shifted distance bytes to the right.// If distance is negative, the string is shifted to the left.// The C String pointed to by string and all shifting operations must be// contained within buffer_base or buffer_count.static void __cdecl shift_bytes( _Maybe_unsafe_(_Inout_updates_z_, buffer_count) char * const buffer_base, _In_ size_t const buffer_count, _In_range_(buffer_base, buffer_base + buffer_count) char* const string, _In_ int const distance ) throw(){ UNREFERENCED_PARAMETER(buffer_base); UNREFERENCED_PARAMETER(buffer_count);
if (distance != 0) { memmove(string + distance, string, strlen(string) + 1); }}
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+//// NaN and Infinity Formatting////-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+_Success_(return == 0)static errno_t __cdecl fp_format_nan_or_infinity( _In_ __acrt_fp_class const classification, _In_range_(0,1) bool const is_negative, _Maybe_unsafe_(_Out_writes_z_, result_buffer_count) char* result_buffer, _In_range_(1,SIZE_MAX) size_t result_buffer_count, _In_range_(0,1) bool const use_capitals ) throw(){ using floating_traits = __acrt_floating_type_traits<double>; using components_type = floating_traits::components_type;
// Ensure that we have sufficient space to store at least the basic three- // character INF or NAN string, plus the minus sign if required: if (result_buffer_count < _countof("INF") + is_negative) { *result_buffer = '\0'; return ENOMEM; }
if (is_negative) { *result_buffer++ = '-'; *result_buffer = '\0'; if (result_buffer_count != _CRT_UNBOUNDED_BUFFER_SIZE) { --result_buffer_count; } }
static char const* const strings[][4] = { { "INF", "INF", "inf", "inf" }, // Infinity { "NAN", "NAN", "nan", "nan" }, // Quiet NAN { "NAN(SNAN)", "NAN", "nan(snan)", "nan" }, // Signaling NAN { "NAN(IND)", "NAN", "nan(ind)", "nan" }, // Indeterminate };
uint32_t const row = static_cast<uint32_t>(classification) - 1; uint32_t const column = use_capitals ? 0 : 2;
bool const long_string_will_fit = result_buffer_count > strlen(strings[row][column]); _ERRCHECK(strcpy_s( result_buffer, result_buffer_count, strings[row][column + !long_string_will_fit])); return 0;}
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+//// %e formatting////-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// These functions handle the formatting of floating point values in the %e// printf format. This format has the form [-]d.ddde(+/-)ddd, where there will// be 'precision' digits following the decimal point. If the precision is less// than or equal to zero, no decimal point will appear. The low order digit is// rounded. If 'capitals' is true, then the exponent will appear as E(+/-)ddd._Success_(return == 0)static errno_t 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 ) throw(){ // The max length if calculated like this: // 3 = sign + first digit + decimal point // precision = decimal digits // 5 = exponent letter (e or E), exponent sign, three digits exponent // 1 = extra space for rounding _UCRT_VALIDATE_RETURN_ERRCODE(ptd, result_buffer_count > static_cast<size_t>(3 + (precision > 0 ? precision : 0) + 5 + 1), ERANGE);
// Place the output in the buffer and round. Leave space in the buffer // for the '-' sign (if any) and the decimal point (if any): if (g_fmt) { // Shift it right one place if nec. for decimal point: char* const p = result_buffer + (pflt->sign == '-'); shift_bytes(result_buffer, result_buffer_count, p, precision > 0); }
// Now fix the number up to be in e format: char* p = result_buffer;
// Put in negative sign if needed: if (pflt->sign == '-') *p++ = '-';
// Put in decimal point if needed. Copy the first digit to the place left // for it and put the decimal point in its place: if (precision > 0) { *p = *(p + 1); *++p = *ptd.get_locale()->locinfo->lconv->decimal_point; }
// Find the end of the string, attach the exponent field and save the // exponent position: p = p + precision + (g_fmt ? 0 : 1); _ERRCHECK(strcpy_s( p, result_buffer_count == _CRT_UNBOUNDED_BUFFER_SIZE ? result_buffer_count : result_buffer_count - (p - result_buffer), "e+000")); char* exponentpos = p + 2;
// Adjust exponent indicator according to capitals flag and increment // pointer to point to exponent sign: if (capitals) *p = 'E';
++p;
// If mantissa is zero, then the number is 0 and we are done; otherwise // adjust the exponent sign (if necessary) and value: if (*pflt->mantissa != '0') { // Check to see if exponent is negative; if so adjust exponent sign and // exponent value: int exp = pflt->decpt - 1; if (exp < 0) { exp = -exp; *p = '-'; }
++p;
if (exp >= 100) { *p += static_cast<char>(exp / 100); exp %= 100; }
++p;
if (exp >= 10) { *p += static_cast<char>(exp / 10); exp %= 10; }
*++p += static_cast<char>(exp); }
if (min_exponent_digits == 2) { // If possible, reduce the exponent to two digits: if (*exponentpos == '0') { memmove(exponentpos, exponentpos + 1, 3); } }
return 0;}
_Success_(return == 0)static errno_t __cdecl 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 ) throw(){ // The precision passed to __acrt_fltout is the number of fractional digits. // To ensure that we get enough digits, we require a total of precision + 1 digits, // to account for the digit placed to the left of the decimal point when all digits are fractional. _strflt strflt;
__acrt_has_trailing_digits const trailing_digits = __acrt_fltout( *reinterpret_cast<_CRT_DOUBLE const*>(argument), precision + 1, __acrt_precision_style::scientific, &strflt, scratch_buffer, scratch_buffer_count );
errno_t const e = __acrt_fp_strflt_to_string( result_buffer + (strflt.sign == '-') + (precision > 0), (result_buffer_count == _CRT_UNBOUNDED_BUFFER_SIZE ? result_buffer_count : result_buffer_count - (strflt.sign == '-') - (precision > 0)), precision + 1, &strflt, trailing_digits, rounding_mode, ptd);
if (e != 0) { result_buffer[0] = '\0'; return e; }
return fp_format_e_internal(result_buffer, result_buffer_count, precision, capitals, min_exponent_digits, &strflt, false, ptd);}
static bool fe_to_nearest(double const* const argument, unsigned __int64 const mask, short const maskpos){ using floating_traits = __acrt_floating_type_traits<double>; using components_type = floating_traits::components_type; components_type const* const components = reinterpret_cast<components_type const*>(argument);
unsigned short digit = static_cast<unsigned short>((components->_mantissa & mask) >> maskpos);
if (digit > 8) { return true; }
if (digit < 8) { return false; }
unsigned __int64 const roundBitsMask = (static_cast<unsigned __int64>(1) << maskpos) - 1; if (components->_mantissa & roundBitsMask) { return true; }
//if we still have digits to the left to compare if (maskpos != DBL_MANT_DIG - 5) { // We divide the mantisa by 16 to move the digits to the right, after that we apply the mask // to get the digit at the left. digit = static_cast<unsigned short>(((components->_mantissa / 16) & mask) >> maskpos); } else { digit = components->_exponent == 0 ? 0 : 1; }
return digit % 2 == 1;}
static bool should_round_up(double const* const argument, unsigned __int64 const mask, short const maskpos, __acrt_rounding_mode const rounding_mode){ using floating_traits = __acrt_floating_type_traits<double>; using components_type = floating_traits::components_type; components_type const* const components = reinterpret_cast<components_type const*>(argument);
unsigned short const digit = static_cast<unsigned short>((components->_mantissa & mask) >> maskpos);
if (rounding_mode == __acrt_rounding_mode::legacy) { return digit >= 8; } int const round_mode = fegetround();
if (round_mode == FE_TONEAREST) { return fe_to_nearest(argument, mask, maskpos); }
if (round_mode == FE_UPWARD) { return digit != 0 && !components->_sign; }
if (round_mode == FE_DOWNWARD) { return digit != 0 && components->_sign; }
return false;}
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+//// %a formatting////-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// These functions handle the formatting of floating point values in the %a// printf format. This format has the form [-]0xh.hhhhp(+/-)d, where there will// be 'precision' hex digits following the decimal point. If the precision is// less than or equal to zero, no decimal point will appear. If 'capitals' is// true, then the number will appear as [-]0xH.HHHHP(+/-)d._Success_(return == 0)static errno_t __cdecl 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 ){ using floating_traits = __acrt_floating_type_traits<double>; using components_type = floating_traits::components_type;
if (precision < 0) { precision = 0; }
result_buffer[0] = '\0';
// the constraint for the size of buffer is: // 1 (sign) // 4 ("0xh.") // precision (decimal digits) // 6 ("p+0000") _UCRT_VALIDATE_RETURN_ERRCODE(ptd, result_buffer_count > static_cast<size_t>(1 + 4 + precision + 6), ERANGE);
// Let __acrt_fp_format_e handle the special cases like SNAN, etc.: components_type const* const components = reinterpret_cast<components_type const*>(argument); if (components->_exponent == floating_traits::exponent_mask) { errno_t const e = fp_format_e( argument, result_buffer, result_buffer_count, scratch_buffer, scratch_buffer_count, precision, false, min_exponent_digits, rounding_mode, ptd);
if (e != 0) { // An error occurred result_buffer[0] = '\0'; return e; }
// Substitute the e with p: char* p = strrchr(result_buffer, 'e'); if (p) { *p = capitals ? 'P' : 'p';
// Trim the exponent (which is 0) to only one digit; skip the // exponent sign and the first digit and put the terminating 0: p += 3; *p = 0; } return e; }
// Sign: if (components->_sign) { *result_buffer++ = '-'; }
int const hexadd = (capitals ? 'A' : 'a') - '9' - 1;
// Leading digit (and set the debias): unsigned __int64 debias = floating_traits::exponent_bias; if (components->_exponent == 0) { *result_buffer++ = '0'; if (components->_mantissa == 0) { // Zero: debias = 0; } else { // Denormal: debias--; } } else { *result_buffer++ = '1'; }
// Decimal point (save the position in pos): char* pos = result_buffer++; if (precision == 0) { // If precision is 0, then we don't have to print the decimal point: // we mark this putting 0 instead of the decimal point itself *pos = 0; } else { *pos = *ptd.get_locale()->locinfo->lconv->decimal_point; }
// Mantissa: if (components->_mantissa > 0) { // Print 4 bits at a time, and skip the initial zeroes // Prepare the mask to read the first 4 bits short maskpos = (floating_traits::mantissa_bits - 1) - 4;
unsigned __int64 mask = 0xf; mask <<= maskpos;
while (maskpos >= 0 && precision > 0) { unsigned short digit = static_cast<unsigned short>((components->_mantissa & mask) >> maskpos); digit += '0'; if (digit > '9') { digit += static_cast<unsigned short>(hexadd); } *result_buffer++ = static_cast<char>(digit); mask >>= 4; maskpos -= 4; --precision; }
// Round the mantissa: if (maskpos >= 0) { if (should_round_up(argument, mask, maskpos, rounding_mode)) { char* p = result_buffer; --p; // If the last digit is 'f', we need to add one to the previous // digit, too; pos is the position of the decimal point while (*p == 'f' || *p == 'F') { *p-- = '0'; } // If we reached the decimal point, it means we are rounding // something like 0x0.fffff so this will become 0x1.00000 : if (p != pos) { if (*p == '9') { *p += static_cast<char>(1 + hexadd); } else { *p += 1; } } else // p == pos { // Skip the decimal point: --p;
// The first digit is always 0 or 1, so we don't need to // add hexadd: *p += 1; } } } }
// Add the final zeroes, if needed: for (; precision > 0; --precision) { *result_buffer++ = '0'; }
// Move back the buffer pointer if there is no decimal point: if (*pos == 0) { result_buffer = pos; }
// Exponent: *result_buffer++ = capitals ? 'P' : 'p'; __int64 exponent = components->_exponent - debias; if (exponent >= 0) { *result_buffer++ = '+'; } else { *result_buffer++ = '-'; exponent = -exponent; } // Save the position in pos and write a '0': pos = result_buffer; *pos = '0';
if (exponent >= 1000) { *result_buffer++ = '0' + static_cast<char>(exponent / 1000); exponent %= 1000; } if (result_buffer != pos || exponent >= 100) { *result_buffer++ = '0' + static_cast<char>(exponent / 100); exponent %= 100; } if (result_buffer != pos || exponent >= 10) { *result_buffer++ = '0' + static_cast<char>(exponent / 10); exponent %= 10; }
*result_buffer++ = '0' + static_cast<char>(exponent);
// Terminate the string: *result_buffer = '\0';
return 0;}
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+//// %f formatting////-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// These functions handle the formatting of floating point values in the %f// printf format. This format has the form [-]ddddd.ddddd, where there will be// precision digits following the decimal point. If precision is less than or// equal to zero, no decimal point will appear. The low order digit is rounded._Success_(return == 0)static errno_t 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 ) throw(){ int const g_magnitude = pflt->decpt - 1;
// Place the output in the user's buffer and round. Save space for the // minus sign now if it will be needed: if (g_fmt && g_magnitude == precision) { char* const p = g_magnitude + buffer + (pflt->sign == '-'); p[0] = '0'; p[1] = '\0';
// Allows for extra place-holding '0' in the exponent == precision case // of the %g format. }
// Now fix up the number to be in the correct %f format: char* p = buffer;
// Put in a negative sign, if necessary: if (pflt->sign == '-') *p++ = '-';
// Insert a leading zero for purely fractional values and position ourselves // at the correct spot for inserting the decimal point: if (pflt->decpt <= 0) { // In the specific scenario of the 0 when using g format this would cause // to have an extra zero at the end bool const is_zero_pflt = pflt->decpt == 0 && *pflt->mantissa == '0'; if (!g_fmt || !is_zero_pflt) { shift_bytes(buffer, buffer_count, p, 1); } *p++ = '0'; } else { p += pflt->decpt; }
// Put a decimal point if required, and add any needed zero padding: if (precision > 0) { shift_bytes(buffer, buffer_count, p, 1); *p++ = *ptd.get_locale()->locinfo->lconv->decimal_point;
// If the value is less than 1 then we may need to put zeroes out in // front of the first non-zero digit of the mantissa: if (pflt->decpt < 0) { int const computed_precision = (g_fmt || -pflt->decpt < precision) ? -pflt->decpt : precision;
shift_bytes(buffer, buffer_count, p, computed_precision); memset(p, '0', computed_precision); } }
return 0;}
_Success_(return == 0)static errno_t __cdecl 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 ) throw(){ _strflt strflt{}; __acrt_has_trailing_digits const trailing_digits = __acrt_fltout( *reinterpret_cast<_CRT_DOUBLE const*>(argument), precision, __acrt_precision_style::fixed, &strflt, scratch_buffer, scratch_buffer_count );
errno_t const e = __acrt_fp_strflt_to_string( result_buffer + (strflt.sign == '-'), (result_buffer_count == _CRT_UNBOUNDED_BUFFER_SIZE ? result_buffer_count : result_buffer_count - (strflt.sign == '-')), precision + strflt.decpt, &strflt, trailing_digits, rounding_mode, ptd);
if (e != 0) { result_buffer[0] = '\0'; return e; }
return fp_format_f_internal(result_buffer, result_buffer_count, precision, &strflt, false, ptd);}
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+//// %g formatting////-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// These functions handle the formatting of floating point values in the %g// printf format. The form used depends on the value converted. The printf %e// form will be used if the magnitude of the value is less than -4 or is greater// than 'precision', otherwise %f will be used. The 'precision' always specifies// the number of digits following the decimal point. The low order digit is// appropriately rounded._Success_(return == 0)static errno_t __cdecl 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 ) throw(){ _strflt strflt{};
// Generate digits as though we will use %f formatting, then decide based on the result // whether to use %f or %e formatting. %f always requires more generated digits than %e, // so generating them all now will avoid generating more later (generation isn't resumable). __acrt_has_trailing_digits const trailing_digits = __acrt_fltout( *reinterpret_cast<_CRT_DOUBLE const*>(argument), precision, __acrt_precision_style::fixed, &strflt, scratch_buffer, scratch_buffer_count );
size_t const minus_sign_length = strflt.sign == '-' ? 1 : 0;
int g_magnitude = strflt.decpt - 1; char* p = result_buffer + minus_sign_length;
size_t const buffer_count_for_fptostr = result_buffer_count == _CRT_UNBOUNDED_BUFFER_SIZE ? result_buffer_count : result_buffer_count - minus_sign_length;
errno_t const fptostr_result = __acrt_fp_strflt_to_string(p, buffer_count_for_fptostr, precision, &strflt, trailing_digits, rounding_mode, ptd); if (fptostr_result != 0) { result_buffer[0] = '\0'; return fptostr_result; }
bool const g_round_expansion = g_magnitude < (strflt.decpt - 1);
// Compute the magnitude of value: g_magnitude = strflt.decpt - 1;
// Convert value to the C Language g format: if (g_magnitude < -4 || g_magnitude >= precision) // Use e format { // We can ignore the round expansion flag here: the extra digit will be // overwritten by "e+xxx". return fp_format_e_internal(result_buffer, result_buffer_count, precision, capitals, min_exponent_digits, &strflt, true, ptd); } else // Use f format { if (g_round_expansion) { // Throw away extra final digit from expansion: while (*p++) { // Iterate to the end of the string }
*(p - 2) = '\0'; }
return fp_format_f_internal(result_buffer, result_buffer_count, precision, &strflt, true, ptd); }}
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+//// Format Dispatch////-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// The main floating point formatting dispatch function. This function just// looks at the 'format' character, calls the right formatting function, and// returns the result. The other parameters are passed on to the selected// formatting function and are used as described in the documentation for// those functions.extern "C" errno_t __cdecl __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 ){ _UCRT_VALIDATE_RETURN_ERRCODE(ptd, result_buffer != nullptr, EINVAL); _UCRT_VALIDATE_RETURN_ERRCODE(ptd, result_buffer_count > 0, EINVAL); _UCRT_VALIDATE_RETURN_ERRCODE(ptd, scratch_buffer != nullptr, EINVAL); _UCRT_VALIDATE_RETURN_ERRCODE(ptd, scratch_buffer_count > 0, EINVAL);
bool const use_capitals = format == 'A' || format == 'E' || format == 'F' || format == 'G';
// Detect special cases (NaNs and infinities) and handle them specially. // Note that the underlying __acrt_fltout function will also handle these // special cases, but it does so using the legacy strings (e.g. 1.#INF). // Our special handling here uses the C99 strings (e.g. INF). if ((options & _CRT_INTERNAL_PRINTF_LEGACY_MSVCRT_COMPATIBILITY) == 0) { __acrt_fp_class const classification = __acrt_fp_classify(*value); if (classification != __acrt_fp_class::finite) { return fp_format_nan_or_infinity( classification, __acrt_fp_is_negative(*value), result_buffer, result_buffer_count, use_capitals); } }
unsigned const min_exponent_digits = (options & _CRT_INTERNAL_PRINTF_LEGACY_THREE_DIGIT_EXPONENTS) != 0 ? 3 : 2; if ((options & _CRT_INTERNAL_PRINTF_STANDARD_ROUNDING) == 0) { rounding_mode = __acrt_rounding_mode::legacy; }
switch (format) { case 'a': case 'A': return fp_format_a(value, result_buffer, result_buffer_count, scratch_buffer, scratch_buffer_count, precision, use_capitals, min_exponent_digits, rounding_mode, ptd);
case 'e': case 'E': return fp_format_e(value, result_buffer, result_buffer_count, scratch_buffer, scratch_buffer_count, precision, use_capitals, min_exponent_digits, rounding_mode, ptd);
case 'f': case 'F': return fp_format_f(value, result_buffer, result_buffer_count, scratch_buffer, scratch_buffer_count, precision, rounding_mode, ptd);
default: _ASSERTE(("Unsupported format specifier", 0)); case 'g': case 'G': return fp_format_g(value, result_buffer, result_buffer_count, scratch_buffer, scratch_buffer_count, precision, use_capitals, min_exponent_digits, rounding_mode, ptd); }}