Changed fp specials handling in XPath (using fpclassify/fpclass where possible, NaN generation is based on float QNaN, removed magic double constants/byte arrays)
git-svn-id: http://pugixml.googlecode.com/svn/trunk@479 99668b35-9821-0410-8761-19e4c4f06640
This commit is contained in:
parent
a0887a0124
commit
51bb70cdcf
@ -28,6 +28,14 @@
|
|||||||
# include <wchar.h>
|
# include <wchar.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// int32_t
|
||||||
|
#if !defined(_MSC_VER) || _MSC_VER >= 1600
|
||||||
|
# include <stdint.h>
|
||||||
|
#else
|
||||||
|
typedef __int32 int32_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
# pragma warning(disable: 4127) // conditional expression is constant
|
# pragma warning(disable: 4127) // conditional expression is constant
|
||||||
# pragma warning(disable: 4702) // unreachable code
|
# pragma warning(disable: 4702) // unreachable code
|
||||||
@ -261,100 +269,83 @@ namespace
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* From trio
|
|
||||||
*
|
|
||||||
* Endian-agnostic indexing macro.
|
|
||||||
*
|
|
||||||
* The value of internalEndianMagic, when converted into a 64-bit
|
|
||||||
* integer, becomes 0x0706050403020100 (we could have used a 64-bit
|
|
||||||
* integer value instead of a double, but not all platforms supports
|
|
||||||
* that type). The value is automatically encoded with the correct
|
|
||||||
* endianess by the compiler, which means that we can support any
|
|
||||||
* kind of endianess. The individual bytes are then used as an index
|
|
||||||
* for the IEEE 754 bit-patterns and masks.
|
|
||||||
*/
|
|
||||||
#define DOUBLE_INDEX(x) (((unsigned char *)&internal_endian_magic)[7-(x)])
|
|
||||||
|
|
||||||
static const double internal_endian_magic = 7.949928895127363e-275;
|
|
||||||
|
|
||||||
static const unsigned char ieee_754_exponent_mask[] = { 0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
|
||||||
|
|
||||||
static const unsigned char ieee_754_mantissa_mask[] = { 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
|
||||||
|
|
||||||
static const unsigned char ieee_754_qnan_array[] = { 0x7F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
|
||||||
|
|
||||||
bool is_special(double value, bool& has_mantissa)
|
|
||||||
{
|
|
||||||
bool is_special_quantity = true;
|
|
||||||
|
|
||||||
has_mantissa = false;
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < sizeof(double); ++i)
|
|
||||||
{
|
|
||||||
unsigned char current = ((unsigned char *)&value)[DOUBLE_INDEX(i)];
|
|
||||||
|
|
||||||
is_special_quantity = is_special_quantity && (current & ieee_754_exponent_mask[i]) == ieee_754_exponent_mask[i];
|
|
||||||
has_mantissa = has_mantissa || (current & ieee_754_mantissa_mask[i]) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return is_special_quantity;
|
|
||||||
}
|
|
||||||
|
|
||||||
double gen_nan()
|
double gen_nan()
|
||||||
{
|
{
|
||||||
#if FLT_RADIX == 2 && DBL_MAX_EXP == 1024 && DBL_MANT_DIG == 53
|
#if defined(__STDC_IEC_559__) || ((FLT_RADIX - 0 == 2) && (FLT_MAX_EXP - 0 == 128) && (FLT_MANT_DIG - 0 == 24))
|
||||||
// IEEE 754
|
union { float f; int32_t i; } u[sizeof(float) == sizeof(int32_t) ? 1 : -1];
|
||||||
|
u[0].i = 0x7fc00000;
|
||||||
double result = 0;
|
return u[0].f;
|
||||||
|
#else
|
||||||
for (unsigned int i = 0; i < sizeof(double); ++i)
|
// fallback
|
||||||
{
|
|
||||||
((unsigned char *)&result)[DOUBLE_INDEX(i)] = ieee_754_qnan_array[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
#else
|
|
||||||
const volatile double zero = 0.0;
|
const volatile double zero = 0.0;
|
||||||
return zero / zero;
|
return zero / zero;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_nan(double value)
|
bool is_nan(double value)
|
||||||
{
|
{
|
||||||
#if defined(__USE_ISOC99)
|
#if defined(_MSC_VER) || defined(__BORLANDC__)
|
||||||
return isnan(value);
|
|
||||||
#elif (defined(_MSC_VER) || defined(__BORLANDC__)) && !defined(__COMO__)
|
|
||||||
return !!_isnan(value);
|
return !!_isnan(value);
|
||||||
#elif FLT_RADIX == 2 && DBL_MAX_EXP == 1024 && DBL_MANT_DIG == 53
|
#elif defined(FP_NAN)
|
||||||
// IEEE 754
|
return fpclassify(value) == FP_NAN;
|
||||||
|
#else
|
||||||
bool has_mantissa;
|
// fallback
|
||||||
|
const volatile double v = value;
|
||||||
bool is_special_quantity = is_special(value, has_mantissa);
|
return v != v;
|
||||||
|
#endif
|
||||||
return (is_special_quantity && has_mantissa);
|
|
||||||
#else
|
|
||||||
return value != value;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_inf(double value)
|
const char_t* convert_number_to_string_special(double value)
|
||||||
{
|
{
|
||||||
#if defined(__USE_ISOC99)
|
#if defined(_MSC_VER)
|
||||||
return !isfinite(value);
|
switch (_fpclass(value))
|
||||||
#elif (defined(_MSC_VER) || defined(__BORLANDC__)) && !defined(__COMO__)
|
{
|
||||||
return !_finite(value);
|
case _FPCLASS_SNAN:
|
||||||
#elif FLT_RADIX == 2 && DBL_MAX_EXP == 1024 && DBL_MANT_DIG == 53
|
case _FPCLASS_QNAN:
|
||||||
// IEEE 754
|
return PUGIXML_TEXT("NaN");
|
||||||
|
|
||||||
bool has_mantissa;
|
case _FPCLASS_NINF:
|
||||||
|
return PUGIXML_TEXT("-Infinity");
|
||||||
bool is_special_quantity = is_special(value, has_mantissa);
|
|
||||||
|
case _FPCLASS_NZ:
|
||||||
return (is_special_quantity && !has_mantissa);
|
case _FPCLASS_PZ:
|
||||||
#else
|
return PUGIXML_TEXT("0");
|
||||||
return value + 1 == value && value - 1 == value;
|
|
||||||
#endif
|
case _FPCLASS_PINF:
|
||||||
|
return PUGIXML_TEXT("Infinity");
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#elif defined(__BORLANDC__) // _fpclass in BorlandC breaks fp flags
|
||||||
|
if (_isnan(value)) return PUGIXML_TEXT("NaN");
|
||||||
|
if (!_finite(value)) return PUGIXML_TEXT("-Infinity") + (value > 0);
|
||||||
|
if (value == 0) return PUGIXML_TEXT("0");
|
||||||
|
return 0;
|
||||||
|
#elif defined(FP_NAN) && defined(FP_INFINITE) && defined(FP_ZERO)
|
||||||
|
switch (fpclassify(value))
|
||||||
|
{
|
||||||
|
case FP_NAN:
|
||||||
|
return PUGIXML_TEXT("NaN");
|
||||||
|
|
||||||
|
case FP_INFINITE:
|
||||||
|
return PUGIXML_TEXT("-Infinity") + (value > 0);
|
||||||
|
|
||||||
|
case FP_ZERO:
|
||||||
|
return PUGIXML_TEXT("0");
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
// fallback
|
||||||
|
const volatile double v = value;
|
||||||
|
|
||||||
|
if (v == 0) return PUGIXML_TEXT("0");
|
||||||
|
if (v != v) return PUGIXML_TEXT("NaN");
|
||||||
|
if (v * 2 == v) return PUGIXML_TEXT("-Infinity") + (value > 0);
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool convert_number_to_boolean(double value)
|
bool convert_number_to_boolean(double value)
|
||||||
@ -364,9 +355,8 @@ namespace
|
|||||||
|
|
||||||
string_t convert_number_to_string(double value)
|
string_t convert_number_to_string(double value)
|
||||||
{
|
{
|
||||||
if (is_nan(value)) return PUGIXML_TEXT("NaN");
|
const char_t* special = convert_number_to_string_special(value);
|
||||||
else if (is_inf(value)) return value < 0 ? PUGIXML_TEXT("-Infinity") : PUGIXML_TEXT("Infinity");
|
if (special) return special;
|
||||||
else if (value == 0) return PUGIXML_TEXT("0");
|
|
||||||
|
|
||||||
char buf[512];
|
char buf[512];
|
||||||
sprintf(buf, "%f", value);
|
sprintf(buf, "%f", value);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user