inline static void appenddouble(char **buffer, int *pos, int *size, double number, int width, char padding, int alignment, int precision, int adjust, char fmt, int always_sign) { char num_buf[NUM_BUF_SIZE]; char *s = NULL; int s_len = 0, is_negative = 0; if ((adjust & ADJ_PRECISION) == 0) { precision = FLOAT_PRECISION; } else if (precision > MAX_FLOAT_PRECISION) { precision = MAX_FLOAT_PRECISION; } if (isnan(number)) { is_negative = (number<0); appendstring(buffer, pos, size, "NaN", 3, 0, padding, alignment, 3, is_negative, 0, always_sign); return; } if (isinf(number)) { is_negative = (number<0); appendstring(buffer, pos, size, "INF", 3, 0, padding, alignment, 3, is_negative, 0, always_sign); return; } switch (fmt) { case 'e': case 'E': case 'f': case 'F': s = php_conv_fp((fmt == 'f')?'F':fmt, number, 0, precision, '.', &is_negative, &num_buf[1], &s_len); if (is_negative) { num_buf[0] = '-'; s = num_buf; s_len++; } else if (always_sign) { num_buf[0] = '+'; s = num_buf; s_len++; } break; case 'g': case 'G': if (precision == 0) precision = 1; /* * * We use &num_buf[ 1 ], so that we have room for the sign */ s = php_gcvt(number, precision, '.', (fmt == 'G')?'E':'e', &num_buf[1]); is_negative = 0; if (*s == '-') { is_negative = 1; s = &num_buf[1]; } else if (always_sign) { num_buf[0] = '+'; s = num_buf; } s_len = strlen(s); break; } appendstring(buffer, pos, size, s, width, 0, padding, alignment, s_len, is_negative, 0, always_sign); }
inline static void appenddouble(StringBuffer *buffer, double number, int width, char padding, int alignment, int precision, int adjust, char fmt, int always_sign) { char num_buf[NUM_BUF_SIZE]; char *s = nullptr; int s_len = 0, is_negative = 0; if ((adjust & ADJ_PRECISION) == 0) { precision = FLOAT_PRECISION; } else if (precision > MAX_FLOAT_PRECISION) { precision = MAX_FLOAT_PRECISION; } if (std::isnan(number)) { is_negative = (number<0); appendstring(buffer, "NaN", 3, 0, padding, alignment, 3, is_negative, 0, always_sign); return; } if (std::isinf(number)) { is_negative = (number<0); appendstring(buffer, "INF", 3, 0, padding, alignment, 3, is_negative, 0, always_sign); return; } #if defined(HAVE_LOCALE_H) struct lconv *lconv; lconv = localeconv(); # define APPENDDOUBLE_LCONV_DECIMAL_POINT (*lconv->decimal_point) #else # define APPENDDOUBLE_LCONV_DECIMAL_POINT '.' #endif switch (fmt) { case 'e': case 'E': case 'f': case 'F': s = php_conv_fp((fmt == 'f')?'F':fmt, number, 0, precision, (fmt == 'f')?APPENDDOUBLE_LCONV_DECIMAL_POINT:'.', &is_negative, &num_buf[1], &s_len); if (is_negative) { num_buf[0] = '-'; s = num_buf; s_len++; } else if (always_sign) { num_buf[0] = '+'; s = num_buf; s_len++; } break; case 'g': case 'G': if (precision == 0) precision = 1; /* * * We use &num_buf[ 1 ], so that we have room for the sign */ s = php_gcvt(number, precision, APPENDDOUBLE_LCONV_DECIMAL_POINT, (fmt == 'G')?'E':'e', &num_buf[1]); is_negative = 0; if (*s == '-') { is_negative = 1; s = &num_buf[1]; } else if (always_sign) { num_buf[0] = '+'; s = num_buf; } s_len = strlen(s); break; } appendstring(buffer, s, width, 0, padding, alignment, s_len, is_negative, 0, always_sign); }
/* php_spintf_appenddouble() {{{ */ inline static void php_sprintf_appenddouble(char **buffer, int *pos, int *size, double number, int width, char padding, int alignment, int precision, int adjust, char fmt, int always_sign TSRMLS_DC) { char num_buf[NUM_BUF_SIZE]; char *s = NULL; int s_len = 0, is_negative = 0; #ifdef HAVE_LOCALE_H struct lconv *lconv; #endif PRINTF_DEBUG(("sprintf: appenddouble(%x, %x, %x, %f, %d, '%c', %d, %c)\n", *buffer, pos, size, number, width, padding, alignment, fmt)); if ((adjust & ADJ_PRECISION) == 0) { precision = FLOAT_PRECISION; } else if (precision > MAX_FLOAT_PRECISION) { php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Requested precision of %d digits was truncated to PHP maximum of %d digits", precision, MAX_FLOAT_PRECISION); precision = MAX_FLOAT_PRECISION; } if (zend_isnan(number)) { is_negative = (number<0); php_sprintf_appendstring(buffer, pos, size, "NaN", 3, 0, padding, alignment, 3, is_negative, 0, always_sign); return; } if (zend_isinf(number)) { is_negative = (number<0); php_sprintf_appendstring(buffer, pos, size, "INF", 3, 0, padding, alignment, 3, is_negative, 0, always_sign); return; } switch (fmt) { case 'e': case 'E': case 'f': case 'F': #ifdef HAVE_LOCALE_H lconv = localeconv(); #endif s = php_conv_fp((fmt == 'f')?'F':fmt, number, 0, precision, (fmt == 'f')?LCONV_DECIMAL_POINT:'.', &is_negative, &num_buf[1], &s_len); if (is_negative) { num_buf[0] = '-'; s = num_buf; s_len++; } else if (always_sign) { num_buf[0] = '+'; s = num_buf; s_len++; } break; case 'g': case 'G': if (precision == 0) precision = 1; /* * * We use &num_buf[ 1 ], so that we have room for the sign */ #ifdef HAVE_LOCALE_H lconv = localeconv(); #endif s = php_gcvt(number, precision, LCONV_DECIMAL_POINT, (fmt == 'G')?'E':'e', &num_buf[1]); is_negative = 0; if (*s == '-') { is_negative = 1; s = &num_buf[1]; } else if (always_sign) { num_buf[0] = '+'; s = num_buf; } s_len = strlen(s); break; } php_sprintf_appendstring(buffer, pos, size, s, width, 0, padding, alignment, s_len, is_negative, 0, always_sign); }
/* {{{ ps_fetch_float */ static void ps_fetch_float(zval * zv, const MYSQLND_FIELD * const field, unsigned int pack_len, zend_uchar ** row) { float fval; double dval; DBG_ENTER("ps_fetch_float"); float4get(fval, *row); (*row)+= 4; DBG_INF_FMT("value=%f", fval); /* * The following is needed to correctly support 4-byte floats. * Otherwise, a value of 9.99 in a FLOAT column comes out of mysqli * as 9.9998998641968. * * For GCC, we use the built-in decimal support to "up-convert" a * 4-byte float to a 8-byte double. * When that is not available, we fall back to converting the float * to a string and then converting the string to a double. This mimics * what MySQL does. */ #ifdef HAVE_DECIMAL_FP_SUPPORT { typedef float dec32 __attribute__((mode(SD))); dec32 d32val = fval; /* The following cast is guaranteed to do the right thing */ dval = (double) d32val; } #elif defined(PHP_WIN32) { /* float datatype on Winows is already 4 byte but has a precision of 7 digits */ char num_buf[2048]; (void)_gcvt_s(num_buf, 2048, fval, field->decimals >= 31 ? 7 : field->decimals); dval = zend_strtod(num_buf, NULL); } #else { char num_buf[2048]; /* Over allocated */ char *s; #ifndef FLT_DIG # define FLT_DIG 6 #endif /* Convert to string. Ignoring localization, etc. * Following MySQL's rules. If precision is undefined (NOT_FIXED_DEC i.e. 31) * or larger than 31, the value is limited to 6 (FLT_DIG). */ s = php_gcvt(fval, field->decimals >= 31 ? FLT_DIG : field->decimals, '.', 'e', num_buf); /* And now convert back to double */ dval = zend_strtod(s, NULL); } #endif ZVAL_DOUBLE(zv, dval); DBG_VOID_RETURN; }