From 4394a588c2d8f07b12201592054234cb321f37e5 Mon Sep 17 00:00:00 2001 From: "arseny.kapoulkine" Date: Mon, 14 Jun 2010 18:03:50 +0000 Subject: XPath: Rewritten number->string conversion using CRT scientific format (much better XPath REC compliance) git-svn-id: http://pugixml.googlecode.com/svn/trunk@523 99668b35-9821-0410-8761-19e4c4f06640 --- src/pugixpath.cpp | 104 ++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 85 insertions(+), 19 deletions(-) (limited to 'src/pugixpath.cpp') diff --git a/src/pugixpath.cpp b/src/pugixpath.cpp index 8e35478..dfc5637 100644 --- a/src/pugixpath.cpp +++ b/src/pugixpath.cpp @@ -332,34 +332,100 @@ namespace return (value != 0 && !is_nan(value)); } + // gets mantissa digits in the form of 0.xxxxx with 0. implied and the exponent + void convert_number_to_mantissa_exponent(double value, char* buffer, char** out_mantissa, int* out_exponent) + { + // get a scientific notation value with IEEE DBL_DIG decimals + sprintf(buffer, "%.15e", value); + + // get the exponent (possibly negative) + char* exponent_string = strchr(buffer, 'e'); + assert(exponent_string); + + int exponent = atoi(exponent_string + 1); + + // extract mantissa string: skip sign + char* mantissa = buffer[0] == '-' ? buffer + 1 : buffer; + assert(mantissa[0] != '0' && mantissa[1] == '.'); + + // divide mantissa by 10 to eliminate integer part + mantissa[1] = mantissa[0]; + mantissa++; + exponent++; + + // remove extra mantissa digits and zero-terminate mantissa + char* mantissa_end = exponent_string; + + while (mantissa != mantissa_end && *(mantissa_end - 1) == '0') --mantissa_end; + + *mantissa_end = 0; + + // fill results + *out_mantissa = mantissa; + *out_exponent = exponent; + } + string_t convert_number_to_string(double value) { + // try special number conversion const char_t* special = convert_number_to_string_special(value); if (special) return special; - - char buf[512]; - sprintf(buf, "%f", value); - - // trim trailing zeros after decimal point - if (strchr(buf, '.')) + + // get mantissa + exponent form + char mantissa_buffer[64]; + + char* mantissa; + int exponent; + convert_number_to_mantissa_exponent(value, mantissa_buffer, &mantissa, &exponent); + + // make the number! + char_t result[512]; + char_t* s = result; + + // sign + if (value < 0) *s++ = '-'; + + // integer part + if (exponent <= 0) { - char* ptr = buf + strlen(buf) - 1; - for (; *ptr == '0'; --ptr) ; + *s++ = '0'; + } + else + { + while (exponent > 0) + { + assert(*mantissa == 0 || (unsigned)(*mantissa - '0') <= 9); + *s++ = *mantissa ? *mantissa++ : '0'; + exponent--; + } + } - // trim leftover decimal point (for integer numbers) - if (*ptr == '.') --ptr; + // fractional part + if (*mantissa) + { + // decimal point + *s++ = '.'; - *(ptr+1) = 0; + // extra zeroes from negative exponent + while (exponent < 0) + { + *s++ = '0'; + exponent++; + } + + // extra mantissa digits + while (*mantissa) + { + assert((unsigned)(*mantissa - '0') <= 9); + *s++ = *mantissa++; + } } - #ifdef PUGIXML_WCHAR_MODE - wchar_t wbuf[512]; - impl::widen_ascii(wbuf, buf); - - return string_t(wbuf); - #else - return string_t(buf); - #endif + // zero-terminate + assert(s < result + sizeof(result) / sizeof(result[0])); + *s = 0; + + return string_t(result); } bool check_string_to_number_format(const char_t* string) -- cgit v1.2.3