不使用C/C++标准库实现的浮点数与字符串相互转换(最给力)

C/C++标准库由于需要具有良好的通用性与全面性,使用了较为复杂的实现方法,实现的代码庞大


对于简单的Windows程序,使用C/C++标准库生成的EXE文件体积较大,整个程序80%以上代码可能均来源于标准库


一种可行的解决办法是使用C/C++动态库(MTd、MT),但这要求系统安装有相应版本的CRT


简单的程序往往功能要求不多、限制通常较少、无需考虑过多情况,使用C/C++标准库如同使用高射炮打蚊子


此时,一种更好的方法是架空C/C++标准库,直接使用Windows API (参看: C/C++程序减小可执行文件的大小)


常用的标准库函数实现往往比较简单,但浮点数与字符串的转换则较为复杂,自己实现的代码往往无法周到全面地考虑各种情况


笔者通过对浮点数存储格式深入研究,并参考VS2015标准库相关代码,实现了不使用C/C++标准库浮点数与字符串相互转换的代码


代码考虑了字符串各种特殊情况:Inf、Nan、上溢、下溢等等,支持十六进制的浮点数字符串,运行效果与使用标准库完全相同


啰嗦了那么多,言归正传,直接给实现代码



头文件(浮点数转字符串与字符串转浮点数的函数接口):

/
// DoubleConversion.h: header file
//
// DoubleConversion - Do not use CRT.
//
// Written by Paschen 
// Copyright (c) 2017. All Rights Reserved.
//
// This code may be used in compiled form in any way you desire. This
// file may be redistributed unmodified by any means PROVIDING it is
// not sold for profit without the authors written consent, and
// providing that this notice and the authors name and all copyright
// notices remains intact.
//
// An email letting me know how you are using it would be nice as well.
//
// This file is provided "as is" with no expressed or implied warranty.
// The author accepts no liability for any damage/loss of business that
// this product may cause.
//
/


#ifndef DOUBLECONVERSION_H_H_H
#define DOUBLECONVERSION_H_H_H

#include 



//说明:  将double类型浮点数转换为字符串
//参数:
//       lpszBuffer: 转换结果缓冲区
//       value: 要转换的浮点数
//       FractionalDigitCount: 保留的小数位数
//返回值: 转换结果(字符串)
LPTSTR Double2String(LPTSTR lpszBuffer, double value, UINT32 FractionalDigitCount);



//转换状态枚举
typedef enum
{
	SLD_OK,
	SLD_NODIGITS,
	SLD_UNDERFLOW,
	SLD_OVERFLOW
} SLD_STATUS;



//说明:  将字符串转换为double类型浮点数
//参数:
//       lpszString: 要转换的字符串
//       result: 转换结果(double类型浮点数)
//返回值: 转换状态枚举
SLD_STATUS String2Double(LPCTSTR lpszString, double& result);


#endif



源文件(函数具体实现,由于实现过程复杂,可不必仔细研读,包含使用即可):

/
// DoubleConversion.cpp : implementation file
//
// DoubleConversion - Do not use CRT.
//
// Written by Paschen 
// Copyright (c) 2017. All Rights Reserved.
//
// This code may be used in compiled form in any way you desire. This
// file may be redistributed unmodified by any means PROVIDING it is 
// not sold for profit without the authors written consent, and 
// providing that this notice and the authors name and all copyright 
// notices remains intact. 
//
// An email letting me know how you are using it would be nice as well. 
//
// This file is provided "as is" with no expressed or implied warranty.
// The author accepts no liability for any damage/loss of business that
// this product may cause.
//
/


#include "DoubleConversion.h"
#include 


#define CHAR_BIT		8
#define DBL_MANT_DIG	53I32
#define DBL_MAX_EXP		1024I32
#define DBL_MIN_EXP		(-1021I32) 
#define LN10			2.3025850929940456840179914547
#define LN1_2217		0.2002433314278771112016301167
#define __MAX(a,b)		(((a) > (b)) ? (a) : (b))
#define __MIN(a,b)		(((a) < (b)) ? (a) : (b))


#ifndef _countof
#ifdef __cplusplus
extern "C++"
{
	template 
	char(*__countof_helper(_UNALIGNED _CountofType(&_Array)[_SizeOfArray]))[_SizeOfArray];
	#define _countof(_Array) (sizeof(*__countof_helper(_Array)) + 0U)
}
#else
#define _countof(_Array) (sizeof(_Array) / sizeof(_Array[0]))
#endif
#endif


enum : INT32
{
	mantissa_bits = DBL_MANT_DIG,
	exponent_bits = (INT32)sizeof(double) * (INT32)CHAR_BIT - DBL_MANT_DIG,
	maximum_binary_exponent = DBL_MAX_EXP - 1I32,
	minimum_binary_exponent = DBL_MIN_EXP - 1I32,
	exponent_bias = 1023I32
};

enum : UINT64
{
	exponent_mask = (1UI64 << (exponent_bits)) - 1UI64,
	normal_mantissa_mask = (1UI64 << (mantissa_bits)) - 1UI64,
	denormal_mantissa_mask = (1UI64 << (mantissa_bits - 1UI64)) - 1UI64,
	special_nan_mantissa_mask = (1UI64 << (mantissa_bits - 2UI64))
};

enum : INT32
{
	maximum_temporary_decimal_exponent = 5200I32,
	minimum_temporary_decimal_exponent = -5200I32
};

struct double_type
{
	UINT64 _mantissa : mantissa_bits - 1I32;
	UINT64 _exponent : exponent_bits;
	UINT64 _sign : 1I32;
};


#pragma optimize( "", off )
static inline VOID Memcpy(LPVOID lpDst, LPCVOID lpSrc, SIZE_T dwLen)
{
	SIZE_T n = dwLen & ~(sizeof(UINT64) - 1U);
	PUINT64 pDst64 = (PUINT64)lpDst;
	PUINT64 pSrc64 = (PUINT64)lpSrc;
	while (n)
	{
		*pDst64++ = *pSrc64++;
		n -= sizeof(UINT64);
	}
	n = dwLen & (sizeof(UINT64) - 1U);
	PUINT8 pDst8 = (PUINT8)pDst64;
	PUINT8 pSrc8 = (PUINT8)pSrc64;
	while (n--)
		*pDst8++ = *pSrc8++;
}
#pragma optimize( "", on )

#ifdef _DEBUG
#pragma optimize( "", off )
static inline VOID Memset(LPVOID lpDst, int Val, SIZE_T dwLen)
{
	PUINT8 pDst8 = (PUINT8)lpDst;
	while (dwLen--)
		*pDst8++ = (UINT8)Val;
}
#pragma optimize( "", on )
#endif

static inline VOID Memsetzero(LPVOID lpDst, SIZE_T dwLen)
{
	SIZE_T n = dwLen & ~(sizeof(UINT64) - 1U);
	PUINT64 pDst64 = (PUINT64)lpDst;
	while (n)
	{
		*pDst64++ = (UINT64)0U;
		n -= sizeof(UINT64);
	}
	n = dwLen & (sizeof(UINT64) - 1U);
	PUINT8 pDst8 = (PUINT8)pDst64;
	while (n--)
		*pDst8++ = (UINT8)0U;
}

static inline double Log(double x)
{
	int k = 0, l = 0;
	for (; x > 1; ++k)
		x /= 10.0;
	for (; x <= 0.1; --k)
		x *= 10.0;
	for (; x < 0.9047; --l)
		x *= 1.2217;
	double y = (x - 1.0) / (x + 1.0);
	double y2 = y * y;
	double t = y2;
	double z = t / 3.0;
	double v = 1.0;
	for (UINT32 i = 3UI32; z; z = (t *= y2) / (double)(i += 2UI32))
		v += z;
	return k * LN10 + l * LN1_2217 + v * y * 2;
}

static inline INT32 Ceil(double x)
{
	double_type& components = (double_type&)x;
	if (!components._exponent && !components._mantissa)
		return 0I32;
	if (components._sign)
		return (INT32)x;
	return (INT32)x + 1I32;
}


struct big_integer
{
	big_integer() : used(0UI32)
	{
	#ifdef _DEBUG
		Memset(data, 0xcc, sizeof(data));
	#endif
	}
	big_integer(const big_integer& other) : used(other.used)
	{
		Memcpy(data, other.data, other.used * sizeof(UINT32));
	}
	big_integer& operator=(const big_integer& other)
	{
		used = other.used;
		Memcpy(data, other.data, (size_t)other.used * sizeof(UINT32));
		return *this;
	}
	enum : UINT32
	{
		maximum_bits = 1074UI32 + 2552UI32 + 32UI32, // 1074 bits required to represent 2^1074 | ceil(log2(10^768)) | shift space
		element_bits = (UINT32)sizeof(UINT32) * (UINT32)CHAR_BIT,
		element_count = (maximum_bits + element_bits - 1UI32) / element_bits
	};
	UINT32 used;
	UINT32 data[element_count];
};

static inline BOOL operator==(const big_integer& lhs, const big_integer& rhs)
{
	if (lhs.used != rhs.used)
		return FALSE;
	for (UINT32 i = 0UI32; i != lhs.used; ++i)
		if (lhs.data[i] != rhs.data[i])
			return FALSE;
	return TRUE;
}

static inline BOOL operator!=(const big_integer& lhs, const big_integer& rhs)
{
	return !(rhs == lhs);
}

static inline BOOL operator<(const big_integer& lhs, const big_integer& rhs)
{
	if (lhs.used > rhs.used)
		return FALSE;
	if (lhs.used < rhs.used)
		return TRUE;
	UINT32 i = lhs.used - 1UI32;
	for (; i != (UINT32)(-1) && lhs.data[i] == rhs.data[i]; --i)
	{
	}
	if (i == (UINT32)(-1))
		return FALSE;
	if (lhs.data[i] <= rhs.data[i])
		return TRUE;
	return FALSE;
}

static inline BOOL operator>=(const big_integer& lhs, const big_integer& rhs)
{
	return !(lhs < rhs);
}

static inline big_integer make_big_integer(UINT64 value)
{
	big_integer x;
	x.data[0] = value & 0xFFFFFFFFUI64;
	x.data[1] = (UINT32)(value >> 32UI64);
	x.used = x.data[1] ? 2UI32 : 1UI32;
	return x;
}

static inline big_integer make_big_integer_power_of_two(UINT32 power)
{
	UINT32 one = 1UI32;
	big_integer x;
	UINT32 element_index = power / big_integer::element_bits;
	UINT32 bit_index = power % big_integer::element_bits;
	Memsetzero(x.data, (size_t)element_index * sizeof(UINT32));
	x.data[element_index] = (one << bit_index);
	x.used = element_index + 1UI32;
	return x;
}

static inline BOOL is_zero(const big_integer& value)
{
	return value.used == 0UI32;
}

static inline UINT32 bit_scan_reverse(UINT32 value)
{
	UINT32 index;
	if (_BitScanReverse((LPDWORD)&index, value))
		return index + 1UI32;
	return 0UI32;
}

static inline UINT32 bit_scan_reverse(UINT64 value)
{
	if (value > 0xFFFFFFFFUI64)
		return bit_scan_reverse(((PUINT32)(&value))[1]) + 32UI32;
	else
		return bit_scan_reverse(((PUINT32)(&value))[0]);
}

static inline UINT32 bit_scan_reverse(const big_integer& x)
{
	if (x.used == 0UI32)
		return 0UI32;
	return (x.used - 1UI32) * big_integer::element_bits + bit_scan_reverse(x.data[x.used - 1UI32]);
}

static inline BOOL shift_left(big_integer& x, UINT32 n)
{
	UINT32 unit_shift = n / big_integer::element_bits;
	UINT32 bit_shift = n % big_integer::element_bits;
	UINT64 one = 1UI64;
	UINT32 msb_bits = bit_shift;
	UINT32 lsb_bits = big_integer::element_bits - msb_bits;
	UINT32 lsb_mask = (UINT32)((one << lsb_bits) - one);
	UINT32 msb_mask = ~lsb_mask;
	BOOL bit_shifts_into_next_unit = bit_shift > (big_integer::element_bits - bit_scan_reverse(x.data[x.used - 1UI32]));
	BOOL unit_shift_will_overflow = x.used + unit_shift > big_integer::element_count;
	BOOL bit_shift_will_overflow = x.used + unit_shift == big_integer::element_count && bit_shifts_into_next_unit;
	if (unit_shift_will_overflow || bit_shift_will_overflow)
	{
		x = big_integer();
		return FALSE;
	}
	UINT32 max_destination_index = __MIN(x.used + unit_shift, big_integer::element_count - 1UI32);
	for (UINT32 destination_index = max_destination_index; destination_index != (UINT32)(-1) && destination_index >= unit_shift; --destination_index)
	{
		UINT32 upper_source_index = destination_index - unit_shift;
		UINT32 lower_source_index = destination_index - unit_shift - 1UI32;
		UINT32 upper_source = upper_source_index < x.used ? x.data[upper_source_index] : 0UI32;
		UINT32 lower_source = lower_source_index < x.used ? x.data[lower_source_index] : 0UI32;
		UINT32 shifted_upper_source = (upper_source & lsb_mask) << msb_bits;
		UINT32 shifted_lower_source = (lower_source & msb_mask) >> lsb_bits;
		UINT32 combined_shifted_source = shifted_upper_source | shifted_lower_source;
		x.data[destination_index] = combined_shifted_source;
	}
	for (UINT32 destination_index = 0UI32; destination_index != unit_shift; ++destination_index)
		x.data[destination_index] = 0UI32;
	x.used = bit_shifts_into_next_unit ? max_destination_index + 1UI32 : max_destination_index;
	return TRUE;
}

static inline BOOL add(big_integer& x, UINT32 value)
{
	if (value == 0UI32)
		return TRUE;
	UINT32 carry = value;
	for (UINT32 i = 0UI32; i != x.used; ++i)
	{
		UINT64 result = (UINT64)(x.data[i]) + (UINT64)carry;
		x.data[i] = (UINT32)result;
		carry = (UINT32)(result >> 32UI64);
	}
	if (carry)
	{
		if (x.used < big_integer::element_count)
		{
			x.data[x.used] = carry;
			++x.used;
		}
		else
		{
			x = big_integer();
			return FALSE;
		}
	}
	return TRUE;
}

static inline UINT32 add_carry(UINT32& u1, UINT32 u2, UINT32 u_carry)
{
	UINT64 uu = (UINT64)u1 + (UINT64)u2 +(UINT64)u_carry;
	u1 = (UINT32)uu;
	return (UINT32)(uu >> 32UI64);
}

static inline UINT32 add_multiply_carry(UINT32& u_add, UINT32 u_mul_1, UINT32 u_mul_2, UINT32 u_carry)
{
	UINT64 uu_res = (UINT64)u_mul_1 * (UINT64)u_mul_2 + (UINT64)u_add + (UINT64)u_carry;
	u_add = (UINT32)uu_res;
	return  ((PUINT32)(&uu_res))[1];
}

static inline UINT32 multiply_core(PUINT32 multiplicand, UINT32 multiplicand_count, UINT32 multiplier)
{
	UINT32 carry = 0UI32;
	for (UINT32 i = 0UI32; i != multiplicand_count; ++i)
	{
		UINT64 result = (UINT64)multiplicand[i] * (UINT64)multiplier + (UINT64)carry;
		multiplicand[i] = (UINT32)result;
		carry = (UINT32)(result >> 32UI64);
	}
	return carry;
}

static inline BOOL multiply(big_integer& multiplicand, UINT32 multiplier)
{
	if (multiplier == 0UI32)
	{
		multiplicand = big_integer();
		return TRUE;
	}
	if (multiplier == 1UI32)
		return TRUE;
	if (!multiplicand.used)
		return TRUE;
	UINT32 carry = multiply_core(multiplicand.data, multiplicand.used, multiplier);
	if (carry)
	{
		if (multiplicand.used < big_integer::element_count)
		{
			multiplicand.data[multiplicand.used] = carry;
			++multiplicand.used;
		}
		else
		{
			multiplicand = big_integer();
			return FALSE;
		}
	}
	return TRUE;
}

static inline BOOL multiply(big_integer& multiplicand, const big_integer& multiplier)
{
	if (multiplier.used <= 1UI32)
		return multiply(multiplicand, multiplier.data[0]);
	if (multiplicand.used <= 1UI32)
	{
		UINT32 small_multiplier = multiplicand.data[0];
		multiplicand = multiplier;
		return multiply(multiplicand, small_multiplier);
	}
	BOOL multiplier_is_shorter = multiplier.used < multiplicand.used;
	const UINT32* rgu1 = multiplier_is_shorter ? multiplier.data : multiplicand.data;
	const UINT32* rgu2 = multiplier_is_shorter ? multiplicand.data : multiplier.data;
	UINT32 cu1 = multiplier_is_shorter ? multiplier.used : multiplicand.used;
	UINT32 cu2 = multiplier_is_shorter ? multiplicand.used : multiplier.used;
	big_integer result;
	for (UINT32 iu1 = 0UI32; iu1 != cu1; ++iu1)
	{
		UINT32 u_cur = rgu1[iu1];
		if (u_cur == 0UI32)
		{
			if (iu1 == result.used)
			{
				result.data[iu1] = 0UI32;
				result.used = iu1 + 1UI32;
			}
			continue;
		}
		UINT32 u_carry = 0UI32;
		UINT32 iu_res = iu1;
		for (UINT32 iu2 = 0UI32; iu2 != cu2 && iu_res != big_integer::element_count; ++iu2, ++iu_res)
		{
			if (iu_res == result.used)
			{
				result.data[iu_res] = 0UI32;
				result.used = iu_res + 1UI32;
			}
			u_carry = add_multiply_carry(result.data[iu_res], u_cur, rgu2[iu2], u_carry);
		}
		while (u_carry != 0UI32 && iu_res != big_integer::element_count)
		{
			if (iu_res == result.used)
			{
				result.data[iu_res] = 0UI32;
				result.used = iu_res + 1UI32;
			}
			u_carry = add_carry(result.data[iu_res++], 0UI32, u_carry);
		}
		if (iu_res == big_integer::element_count)
		{
			multiplicand = big_integer();
			return FALSE;
		}
	}
	multiplicand = result;
	return TRUE;
}

static inline BOOL multiply_by_power_of_ten(big_integer& x, UINT32 power)
{
	static UINT32 large_power_data[] =
	{
		0x540be400, 0x00000002, 0x63100000, 0x6bc75e2d, 0x00000005, 0x40000000, 0x4674edea, 0x9f2c9cd0,
		0x0000000c, 0xb9f56100, 0x5ca4bfab, 0x6329f1c3, 0x0000001d, 0xb5640000, 0xc40534fd, 0x926687d2,
		0x6c3b15f9, 0x00000044, 0x10000000, 0x946590d9, 0xd762422c, 0x9a224501, 0x4f272617, 0x0000009f,
		0x07950240, 0x245689c1, 0xc5faa71c, 0x73c86d67, 0xebad6ddc, 0x00000172, 0xcec10000, 0x63a22764,
		0xefa418ca, 0xcdd17b25, 0x6bdfef70, 0x9dea3e1f, 0x0000035f, 0xe4000000, 0xcdc3fe6e, 0x66bc0c6a,
		0x2e391f32, 0x5a450203, 0x71d2f825, 0xc3c24a56, 0x000007da, 0xa82e8f10, 0xaab24308, 0x8e211a7c,
		0xf38ace40, 0x84c4ce0b, 0x7ceb0b27, 0xad2594c3, 0x00001249, 0xdd1a4000, 0xcc9f54da, 0xdc5961bf,
		0xc75cabab, 0xf505440c, 0xd1bc1667, 0xfbb7af52, 0x608f8d29, 0x00002a94, 0x21000000, 0x17bb8a0c,
		0x56af8ea4, 0x06479fa9, 0x5d4bb236, 0x80dc5fe0, 0xf0feaa0a, 0xa88ed940, 0x6b1a80d0, 0x00006323,
		0x324c3864, 0x8357c796, 0xe44a42d5, 0xd9a92261, 0xbd3c103d, 0x91e5f372, 0xc0591574, 0xec1da60d,
		0x102ad96c, 0x0000e6d3, 0x1e851000, 0x6e4f615b, 0x187b2a69, 0x0450e21c, 0x2fdd342b, 0x635027ee,
		0xa6c97199, 0x8e4ae916, 0x17082e28, 0x1a496e6f, 0x0002196e, 0x32400000, 0x04ad4026, 0xf91e7250,
		0x2994d1d5, 0x665bcdbb, 0xa23b2e96, 0x65fa7ddb, 0x77de53ac, 0xb020a29b, 0xc6bff953, 0x4b9425ab,
		0x0004e34d, 0xfbc32d81, 0x5222d0f4, 0xb70f2850, 0x5713f2f3, 0xdc421413, 0xd6395d7d, 0xf8591999,
		0x0092381c, 0x86b314d6, 0x7aa577b9, 0x12b7fe61, 0x000b616a, 0x1d11e400, 0x56c3678d, 0x3a941f20,
		0x9b09368b, 0xbd706908, 0x207665be, 0x9b26c4eb, 0x1567e89d, 0x9d15096e, 0x7132f22b, 0xbe485113,
		0x45e5a2ce, 0x001a7f52, 0xbb100000, 0x02f79478, 0x8c1b74c0, 0xb0f05d00, 0xa9dbc675, 0xe2d9b914,
		0x650f72df, 0x77284b4c, 0x6df6e016, 0x514391c2, 0x2795c9cf, 0xd6e2ab55, 0x9ca8e627, 0x003db1a6,
		0x40000000, 0xf4ecd04a, 0x7f2388f0, 0x580a6dc5, 0x43bf046f, 0xf82d5dc3, 0xee110848, 0xfaa0591c,
		0xcdf4f028, 0x192ea53f, 0xbcd671a0, 0x7d694487, 0x10f96e01, 0x791a569d, 0x008fa475, 0xb9b2e100,
		0x8288753c, 0xcd3f1693, 0x89b43a6b, 0x089e87de, 0x684d4546, 0xfddba60c, 0xdf249391, 0x3068ec13,
		0x99b44427, 0xb68141ee, 0x5802cac3, 0xd96851f1, 0x7d7625a2, 0x014e718d, 0xfb640000, 0xf25a83e6,
		0x9457ad0f, 0x0080b511, 0x2029b566, 0xd7c5d2cf, 0xa53f6d7d, 0xcdb74d1c, 0xda9d70de, 0xb716413d,
		0x71d0ca4e, 0xd7e41398, 0x4f403a90, 0xf9ab3fe2, 0x264d776f, 0x030aafe6, 0x10000000, 0x09ab5531,
		0xa60c58d2, 0x566126cb, 0x6a1c8387, 0x7587f4c1, 0x2c44e876, 0x41a047cf, 0xc908059e, 0xa0ba063e,
		0xe7cfc8e8, 0xe1fac055, 0xef0144b2, 0x24207eb0, 0xd1722573, 0xe4b8f981, 0x071505ae, 0x7a3b6240,
		0xcea45d4f, 0x4fe24133, 0x210f6d6d, 0xe55633f2, 0x25c11356, 0x28ebd797, 0xd396eb84, 0x1e493b77,
		0x471f2dae, 0x96ad3820, 0x8afaced1, 0x4edecddb, 0x5568c086, 0xb2695da1, 0x24123c89, 0x107d4571,
		0x1c410000, 0x6e174a27, 0xec62ae57, 0xef2289aa, 0xb6a2fbdd, 0x17e1efe4, 0x3366bdf2, 0x37b48880,
		0xbfb82c3e, 0x19acde91, 0xd4f46408, 0x35ff6a4e, 0x67566a0e, 0x40dbb914, 0x782a3bca, 0x6b329b68,
		0xf5afc5d9, 0x266469bc, 0xe4000000, 0xfb805ff4, 0xed55d1af, 0x9b4a20a8, 0xab9757f8, 0x01aefe0a,
		0x4a2ca67b, 0x1ebf9569, 0xc7c41c29, 0xd8d5d2aa, 0xd136c776, 0x93da550c, 0x9ac79d90, 0x254bcba8,
		0x0df07618, 0xf7a88809, 0x3a1f1074, 0xe54811fc, 0x59638ead, 0x97cbe710, 0x26d769e8, 0xb4e4723e,
		0x5b90aa86, 0x9c333922, 0x4b7a0775, 0x2d47e991, 0x9a6ef977, 0x160b40e7, 0x0c92f8c4, 0xf25ff010,
		0x25c36c11, 0xc9f98b42, 0x730b919d, 0x05ff7caf, 0xb0432d85, 0x2d2b7569, 0xa657842c, 0xd01fef10,
		0xc77a4000, 0xe8b862e5, 0x10d8886a, 0xc8cd98e5, 0x108955c5, 0xd059b655, 0x58fbbed4, 0x03b88231,
		0x034c4519, 0x194dc939, 0x1fc500ac, 0x794cc0e2, 0x3bc980a1, 0xe9b12dd1, 0x5e6d22f8, 0x7b38899a,
		0xce7919d8, 0x78c67672, 0x79e5b99f, 0xe494034e, 0x00000001, 0xa1000000, 0x6c5cd4e9, 0x9be47d6f,
		0xf93bd9e7, 0x77626fa1, 0xc68b3451, 0xde2b59e8, 0xcf3cde58, 0x2246ff58, 0xa8577c15, 0x26e77559,
		0x17776753, 0xebe6b763, 0xe3fd0a5f, 0x33e83969, 0xa805a035, 0xf631b987, 0x211f0f43, 0xd85a43db,
		0xab1bf596, 0x683f19a2, 0x00000004, 0xbe7dfe64, 0x4bc9042f, 0xe1f5edb0, 0x8fa14eda, 0xe409db73,
		0x674fee9c, 0xa9159f0d, 0xf6b5b5d6, 0x7338960e, 0xeb49c291, 0x5f2b97cc, 0x0f383f95, 0x2091b3f6,
		0xd1783714, 0xc1d142df, 0x153e22de, 0x8aafdf57, 0x77f5e55f, 0xa3e7ca8b, 0x032f525b, 0x42e74f3d,
		0x0000000a, 0xf4dd1000, 0x5d450952, 0xaeb442e1, 0xa3b3342e, 0x3fcda36f, 0xb4287a6e, 0x4bc177f7,
		0x67d2c8d0, 0xaea8f8e0, 0xadc93b67, 0x6cc856b3, 0x959d9d0b, 0x5b48c100, 0x4abe8a3d, 0x52d936f4,
		0x71dbe84d, 0xf91c21c5, 0x4a458109, 0xd7aad86a, 0x08e14c7c, 0x759ba59c, 0xe43c8800, 0x00000017,
		0x92400000, 0x04f110d4, 0x186472be, 0x8736c10c, 0x1478abfb, 0xfc51af29, 0x25eb9739, 0x4c2b3015,
		0xa1030e0b, 0x28fe3c3b, 0x7788fcba, 0xb89e4358, 0x733de4a4, 0x7c46f2c2, 0x8f746298, 0xdb19210f,
		0x2ea3b6ae, 0xaa5014b2, 0xea39ab8d, 0x97963442, 0x01dfdfa9, 0xd2f3d3fe, 0xa0790280, 0x00000037,
		0x509c9b01, 0xc7dcadf1, 0x383dad2c, 0x73c64d37, 0xea6d67d0, 0x519ba806, 0xc403f2f8, 0xa052e1a2,
		0xd710233a, 0x448573a9, 0xcf12d9ba, 0x70871803, 0x52dc3a9b, 0xe5b252e8, 0x0717fb4e, 0xbe4da62f,
		0x0aabd7e1, 0x8c62ed4f, 0xceb9ec7b, 0xd4664021, 0xa1158300, 0xcce375e6, 0x842f29f2, 0x00000081,
		0x7717e400, 0xd3f5fb64, 0xa0763d71, 0x7d142fe9, 0x33f44c66, 0xf3b8f12e, 0x130f0d8e, 0x734c9469,
		0x60260fa8, 0x3c011340, 0xcc71880a, 0x37a52d21, 0x8adac9ef, 0x42bb31b4, 0xd6f94c41, 0xc88b056c,
		0xe20501b8, 0x5297ed7c, 0x62c361c4, 0x87dad8aa, 0xb833eade, 0x94f06861, 0x13cc9abd, 0x8dc1d56a,
		0x0000012d, 0x13100000, 0xc67a36e8, 0xf416299e, 0xf3493f0a, 0x77a5a6cf, 0xa4be23a3, 0xcca25b82,
		0x3510722f, 0xbe9d447f, 0xa8c213b8, 0xc94c324e, 0xbc9e33ad, 0x76acfeba, 0x2e4c2132, 0x3e13cd32,
		0x70fe91b4, 0xbb5cd936, 0x42149785, 0x46cc1afd, 0xe638ddf8, 0x690787d2, 0x1a02d117, 0x3eb5f1fe,
		0xc3b9abae, 0x1c08ee6f, 0x000002be, 0x40000000, 0x8140c2aa, 0x2cf877d9, 0x71e1d73d, 0xd5e72f98,
		0x72516309, 0xafa819dd, 0xd62a5a46, 0x2a02dcce, 0xce46ddfe, 0x2713248d, 0xb723d2ad, 0xc404bb19,
		0xb706cc2b, 0x47b1ebca, 0x9d094bdc, 0xc5dc02ca, 0x31e6518e, 0x8ec35680, 0x342f58a8, 0x8b041e42,
		0xfebfe514, 0x05fffc13, 0x6763790f, 0x66d536fd, 0xb9e15076, 0x00000662, 0x67b06100, 0xd2010a1a,
		0xd005e1c0, 0xdb12733b, 0xa39f2e3f, 0x61b29de2, 0x2a63dce2, 0x942604bc, 0x6170d59b, 0xc2e32596,
		0x140b75b9, 0x1f1d2c21, 0xb8136a60, 0x89d23ba2, 0x60f17d73, 0xc6cad7df, 0x0669df2b, 0x24b88737,
		0x669306ed, 0x19496eeb, 0x938ddb6f, 0x5e748275, 0xc56e9a36, 0x3690b731, 0xc82842c5, 0x24ae798e,
		0x00000ede, 0x41640000, 0xd5889ac1, 0xd9432c99, 0xa280e71a, 0x6bf63d2e, 0x8249793d, 0x79e7a943,
		0x22fde64a, 0xe0d6709a, 0x05cacfef, 0xbd8da4d7, 0xe364006c, 0xa54edcb3, 0xa1a8086e, 0x748f459e,
		0xfc8e54c8, 0xcc74c657, 0x42b8c3d4, 0x57d9636e, 0x35b55bcc, 0x6c13fee9, 0x1ac45161, 0xb595badb,
		0xa1f14e9d, 0xdcf9e750, 0x07637f71, 0xde2f9f2b, 0x0000229d, 0x10000000, 0x3c5ebd89, 0xe3773756,
		0x3dcba338, 0x81d29e4f, 0xa4f79e2c, 0xc3f9c774, 0x6a1ce797, 0xac5fe438, 0x07f38b9c, 0xd588ecfa,
		0x3e5ac1ac, 0x85afccce, 0x9d1f3f70, 0xe82d6dd3, 0x177d180c, 0x5e69946f, 0x648e2ce1, 0x95a13948,
		0x340fe011, 0xb4173c58, 0x2748f694, 0x7c2657bd, 0x758bda2e, 0x3b8090a0, 0x2ddbb613, 0x6dcf4890,
		0x24e4047e, 0x00005099,
	};
	struct unpack_index
	{
		UINT16 _offset; // The offset of this power's initial byte in the array
		UINT8 _zeroes; // The number of omitted leading zero elements
		UINT8 _size; // The number of elements present for this power
	};
	static const unpack_index large_power_indices[] =
	{
		{ 0UI16, 0UI8, 2UI8 },{ 2UI16, 0UI8, 3UI8 },{ 5UI16, 0UI8, 4UI8 },{ 9UI16, 1UI8, 4UI8 },
		{ 130UI16, 1UI8, 5UI8 },{ 18UI16, 1UI8, 6UI8 },{ 24UI16, 2UI8, 6UI8 },{ 30UI16, 2UI8, 7UI8 },
		{ 370UI16, 2UI8, 8UI8 },{ 45UI16, 3UI8, 8UI8 },{ 53UI16, 3UI8, 9UI8 },{ 62UI16, 3UI8, 10UI8 },
		{ 720UI16, 4UI8, 10UI8 },{ 82UI16, 4UI8, 11UI8 },{ 93UI16, 4UI8, 12UI8 },{ 105UI16, 5UI8, 12UI8 },
		{ 1170UI16, 5UI8, 13UI8 },{ 130UI16, 5UI8, 14UI8 },{ 144UI16, 5UI8, 15UI8 },{ 159UI16, 6UI8, 15UI8 },
		{ 1740UI16, 6UI8, 16UI8 },{ 190UI16, 6UI8, 17UI8 },{ 207UI16, 7UI8, 17UI8 },{ 224UI16, 7UI8, 18UI8 },
		{ 2420UI16, 7UI8, 19UI8 },{ 261UI16, 8UI8, 19UI8 },{ 280UI16, 8UI8, 21UI8 },{ 301UI16, 8UI8, 22UI8 },
		{ 3230UI16, 9UI8, 22UI8 },{ 345UI16, 9UI8, 23UI8 },{ 368UI16, 9UI8, 24UI8 },{ 392UI16, 10UI8, 24UI8 },
		{ 4160UI16, 10UI8, 25UI8 },{ 441UI16, 10UI8, 26UI8 },{ 467UI16, 10UI8, 27UI8 },{ 494UI16, 11UI8, 27UI8 },
		{ 5210UI16, 11UI8, 28UI8 },{ 549UI16, 11UI8, 29UI8 },
	};
	UINT32 large_power = power / 10UI32;
	while (large_power)
	{
		UINT32 current_power = large_power > _countof(large_power_indices) ? _countof(large_power_indices) : large_power;
		const unpack_index& index = large_power_indices[current_power - 1UI32];
		big_integer multiplier;
		multiplier.used = index._size + index._zeroes;
		Memsetzero(multiplier.data, (size_t)index._zeroes * sizeof(UINT32));
		Memcpy(multiplier.data + index._zeroes, large_power_data + index._offset, (size_t)index._size * sizeof(UINT32));
		if (!multiply(x, multiplier))
		{
			x = big_integer();
			return FALSE;
		}
		large_power -= current_power;
	}
	static UINT32 small_powers_of_ten[9] =
	{
		10UI32,
		100UI32,
		1000UI32,
		1000UI32 * 10UI32,
		1000UI32 * 100UI32,
		1000UI32 * 1000UI32,
		1000UI32 * 1000UI32 * 10UI32,
		1000UI32 * 1000UI32 * 100UI32,
		1000UI32 * 1000UI32 * 1000UI32
	};
	UINT32 small_power = power % 10UI32;
	if (small_power)
	{
		if (!multiply(x, small_powers_of_ten[small_power - 1UI32]))
			return FALSE;
	}
	return TRUE;
}

static inline UINT32 count_sequential_high_zeroes(UINT32 u)
{
	UINT32 result;
	return _BitScanReverse((LPDWORD)&result, u) ? 31UI32 - result : 32UI32;
}

#ifdef _M_IX86
static inline UINT64 multiply_64_32(UINT64 multiplicand, UINT32 multiplier)
{
	__asm
	{
		mov eax, dword ptr[multiplicand + 4UI64]
		mul multiplier
		mov ecx, eax
		mov eax, dword ptr[multiplicand]
		mul multiplier
		add edx, ecx
	}
}
#else
static inline UINT64 multiply_64_32(UINT64 multiplicand, UINT32 multiplier)
{
	return multiplicand * multiplier;
}
#endif

static UINT64 divide(big_integer& numerator, const big_integer& denominator)
{
	if (!numerator.used)
		return 0UI64;
	if (!denominator.used)
	{
		//_ASSERTE(("Division by zero", FALSE));
		return 0UI64;
	}
	UINT32 max_numerator_element_index = numerator.used - 1UI32;
	UINT32 max_denominator_element_index = denominator.used - 1UI32;
	if (!max_denominator_element_index)
	{
		UINT32 small_denominator = denominator.data[0];
		if (small_denominator == 1UI32)
		{
			UINT32 quotient = numerator.data[0];
			numerator = big_integer();
			return quotient;
		}
		if (!max_numerator_element_index)
		{
			UINT32 small_numerator = numerator.data[0];
			numerator = big_integer();
			numerator.data[0] = small_numerator % small_denominator;
			numerator.used = numerator.data[0] ? 1UI32 : 0UI32;
			return small_numerator / small_denominator;
		}
		UINT64 quotient = 0UI64;
		UINT64 uu = 0UI64;
		for (UINT32 iv = max_numerator_element_index; iv != (UINT32)(-1); --iv)
		{
			uu = (uu << 32UI64) | numerator.data[iv];
			quotient = (quotient << 32UI64) + (UINT32)(uu / small_denominator);
			uu %= small_denominator;
		}
		numerator = big_integer();
		numerator.data[1] = (UINT32)(uu >> 32UI64);
		numerator.data[0] = (UINT32)uu;
		numerator.used = numerator.data[1]? 2UI32 : 1UI32;
		return quotient;
	}

	if (max_denominator_element_index > max_numerator_element_index)
		return 0UI64;
	UINT32 cu_den = max_denominator_element_index + 1UI32;
	INT32 cu_diff = max_numerator_element_index - max_denominator_element_index;
	INT32 cu_quo = cu_diff;
	for (INT32 iu = max_numerator_element_index; ; --iu)
	{
		if (iu < cu_diff)
		{
			++cu_quo;
			break;
		}
		if (denominator.data[iu - cu_diff] != numerator.data[iu])
		{
			if (denominator.data[iu - cu_diff] < numerator.data[iu])
				++cu_quo;
			break;
		}
	}
	if (!cu_quo)
		return 0UI64;
	UINT32 u_den = denominator.data[cu_den - 1UI32];
	UINT32 u_den_next = denominator.data[cu_den - 2UI32];
	UINT32 cbit_shift_left = count_sequential_high_zeroes(u_den);
	UINT32 cbit_shift_right = 32UI32 - cbit_shift_left;
	if (cbit_shift_left)
	{
		u_den = (u_den << cbit_shift_left) | (u_den_next >> cbit_shift_right);
		u_den_next <<= cbit_shift_left;
		if (cu_den > 2UI32)
			u_den_next |= denominator.data[cu_den - 3UI32] >> cbit_shift_right;
	}
	UINT64 quotient = 0UI64;
	for (INT32 iu = cu_quo; --iu >= 0I32; )
	{
		UINT32 u_num_hi = ((UINT32)iu + cu_den <= max_numerator_element_index) ? numerator.data[(UINT32)iu + cu_den] : 0UI32;
		UINT64 uu_num = numerator.data[(UINT32)iu + cu_den - 1UI32];
		((PUINT32)(&uu_num))[1] = u_num_hi;
		UINT32 u_num_next = numerator.data[(UINT32)iu + cu_den - 2UI32];
		if (cbit_shift_left)
		{
			uu_num = (uu_num << cbit_shift_left) | (u_num_next >> cbit_shift_right);
			u_num_next <<= cbit_shift_left;
			if ((UINT32)iu + cu_den >= 3UI32)
				u_num_next |= numerator.data[(UINT32)iu + cu_den - 3UI32] >> cbit_shift_right;
		}
		UINT64 uu_quo = uu_num / (UINT64)u_den;
		UINT64 uu_rem = (UINT64)(UINT32)(uu_num % (UINT64)u_den);
		if (uu_quo > 0xFFFFFFFFUI64)
		{
			uu_rem += (UINT64)u_den * (uu_quo - 0xFFFFFFFFUI64);
			uu_quo = 0xFFFFFFFFUI64;
		}
		while (uu_rem <= 0xFFFFFFFFUI64 && uu_quo * (UINT64)u_den_next > ((uu_rem << 32UI64) | (UINT64)u_num_next))
		{
			--uu_quo;
			uu_rem += (UINT64)u_den;
		}
		if (uu_quo)
		{
			UINT64 uu_borrow = 0UI64;
			for (UINT32 iu2 = 0UI32; iu2 < cu_den; ++iu2)
			{
				uu_borrow += multiply_64_32(uu_quo, denominator.data[iu2]);
				UINT32 u_sub = (UINT32)uu_borrow;
				uu_borrow >>= 32UI64;
				if (numerator.data[(UINT32)iu + iu2] < u_sub)
					++uu_borrow;
				numerator.data[(UINT32)iu + iu2] -= u_sub;
			}
			if (u_num_hi < uu_borrow)
			{
				UINT32 u_carry = 0UI32;
				for (UINT32 iu2 = 0UI32; iu2 < cu_den; ++iu2)
				{
					UINT64 sum = (UINT64)(numerator.data[(UINT32)iu + iu2]) + (UINT64)(denominator.data[iu2]) + (UINT64)u_carry;
					numerator.data[(UINT32)iu + iu2] = (UINT32)sum;
					u_carry = sum >> 32UI64;
				}
				--uu_quo;
			}
			max_numerator_element_index = (UINT32)iu + cu_den - 1UI32;
		}
		quotient = (quotient << 32UI64) + (UINT64)(UINT32)uu_quo;
	}
	numerator.used = max_numerator_element_index + 1UI32;
	while (numerator.used && !numerator.data[numerator.used - 1UI32])
		--numerator.used;
	return quotient;
}


LPTSTR Double2String(LPTSTR lpszBuffer, double value, UINT32 FractionalDigitCount)
{
	double_type& components = (double_type&)value;
	if (!components._exponent && !components._mantissa)
	{
		lpszBuffer[0] = TEXT('0');
		if (FractionalDigitCount)
		{
			lpszBuffer[1] = TEXT('.');
			LPTSTR buffer_it = lpszBuffer + 2;
			while (FractionalDigitCount--)
				*buffer_it++ = TEXT('0');
			*buffer_it = TEXT('\0');
		}
		else
			lpszBuffer[1] = TEXT('\0');
		return lpszBuffer;
	}
	if (components._exponent == (1I32 << exponent_bits) - 1I32)
	{
		if (!components._mantissa)
		{
			lpszBuffer[0] = TEXT('1');
			lpszBuffer[1] = TEXT('#');
			lpszBuffer[2] = TEXT('I');
			lpszBuffer[3] = TEXT('N');
			lpszBuffer[4] = TEXT('F');
			lpszBuffer[5] = TEXT('\0');
		}
		else if (components._sign == 1UI64 && components._mantissa == special_nan_mantissa_mask)
		{
			lpszBuffer[0] = TEXT('1');
			lpszBuffer[1] = TEXT('#');
			lpszBuffer[2] = TEXT('I');
			lpszBuffer[3] = TEXT('N');
			lpszBuffer[4] = TEXT('D');
			lpszBuffer[5] = TEXT('\0');
		}
		else if (components._mantissa & special_nan_mantissa_mask)
		{
			lpszBuffer[0] = TEXT('1');
			lpszBuffer[1] = TEXT('#');
			lpszBuffer[2] = TEXT('Q');
			lpszBuffer[3] = TEXT('N');
			lpszBuffer[4] = TEXT('A');
			lpszBuffer[5] = TEXT('N');
			lpszBuffer[6] = TEXT('\0');
		}
		else
		{
			lpszBuffer[0] = TEXT('1');
			lpszBuffer[1] = TEXT('#');
			lpszBuffer[2] = TEXT('S');
			lpszBuffer[3] = TEXT('N');
			lpszBuffer[4] = TEXT('A');
			lpszBuffer[5] = TEXT('N');
			lpszBuffer[6] = TEXT('\0');
		}
		return lpszBuffer;
	}
	BOOL bPositive = !components._sign;
	components._sign = 0UI64;
	UINT64 mantissa_adjustment;
	INT32 exponent_adjustment;
	if (components._exponent)
	{
		mantissa_adjustment = 1UI64 << (mantissa_bits - 1UI64);
		exponent_adjustment = 1UI32;
	}
	else
	{
		mantissa_adjustment = 0UI64;
		exponent_adjustment = 2UI32;
	}
	UINT64 f = components._mantissa + mantissa_adjustment;
	INT32 e = (INT32)components._exponent - exponent_bias - mantissa_bits + exponent_adjustment;
	INT32 k = (INT32)Ceil(Log(value) / LN10);
	big_integer r = make_big_integer(f);
	big_integer s;
	if (e >= 0I32)
	{
		if (r != make_big_integer_power_of_two(mantissa_bits - 1I32))
		{
			shift_left(r, (UINT32)(e + 1I32));
			s = make_big_integer(2UI64);
		}
		else
		{
			shift_left(r, (UINT32)(e + 2I32));
			s = make_big_integer(4UI64);
		}
	}
	else
	{
		if (e == minimum_binary_exponent || r != make_big_integer_power_of_two(mantissa_bits - 1))
		{
			shift_left(r, 1UI32);
			s = make_big_integer_power_of_two((UINT32)(-e + 1I32));
		}
		else
		{
			shift_left(r, 2UI32);
			s = make_big_integer_power_of_two((UINT32)(-e + 2I32));
		}
	}
	if (k >= 0I32)
		multiply_by_power_of_ten(s, (UINT32)k);
	else
		multiply_by_power_of_ten(r, (UINT32)-k);
	LPTSTR mantissa_it = lpszBuffer + 3;
	multiply(r, 10UI32);
	UINT32 initial_digit = (UINT32)divide(r, s);
	TCHAR ch;
	if (initial_digit == 10UI32)
	{
		++k;
		ch = TEXT('1');
		multiply(s, 10UI32);
	}
	else if (!initial_digit)
	{
		--k;
		ch = TEXT('\0');
	}
	else
		ch = (TCHAR)(TEXT('0') + initial_digit);
	while (k <= 0I32)
	{
		++k;
		*mantissa_it++ = TEXT('0');
	}
	if (ch != TEXT('\0'))
		*mantissa_it++ = ch;
	LPTSTR mantissa_last = lpszBuffer + 3 + k + FractionalDigitCount + 1;
	if (mantissa_it < mantissa_last)
	{
		for (;;)
		{
			const UINT32 digits_per_iteration = 9UI32;
			const UINT32 digits_per_iteration_multiplier = 1000UI32 * 1000UI32 * 1000UI32;
			multiply(r, digits_per_iteration_multiplier);
			UINT32 quotient = (UINT32)divide(r, s);
			#pragma warning(suppress: 6293)
			for (UINT32 i = digits_per_iteration - 1UI32; i != (UINT32)(-1); --i)
			{
				TCHAR d = (TCHAR)(TEXT('0') + quotient % 10UI32);
				quotient /= 10UI32;
				if ((UINT32)(mantissa_last - mantissa_it) < i)
					continue;
				mantissa_it[i] = d;
			}
			mantissa_it += __MIN(digits_per_iteration, (UINT32)(mantissa_last - mantissa_it));
			if (mantissa_it >= mantissa_last)
				break;
			if (is_zero(r))
			{
				while (mantissa_it < mantissa_last)
					*mantissa_it++ = TEXT('0');
				break;
			}
		}
	}
	else if (is_zero(r))
	{
		while (mantissa_it < mantissa_last)
			*mantissa_it++ = TEXT('0');
	}
	lpszBuffer[2] = TEXT('0');
	LPTSTR buffer_it = lpszBuffer + 3;
	if (*--mantissa_last >= TEXT('5'))
	{
		LPTSTR it = mantissa_last - 1;
		while (*it == TEXT('9'))
		{
			*it-- = TEXT('0');
		}
		*it += 1;
	}
	if (lpszBuffer[2] == TEXT('1'))
	{
		++k;
		--buffer_it;
	}
	if (FractionalDigitCount)
	{
		--buffer_it;
		for (INT32 i = 0I32; i != k; ++i)
			buffer_it[i] = buffer_it[i + 1I32];
		buffer_it[k] = TEXT('.');
	}
	if (!bPositive)
		*--buffer_it = TEXT('-');
	*mantissa_last = TEXT('\0');
	return buffer_it;
}


static inline UINT32 parse_digit(TCHAR ch)
{
	if (ch >= TEXT('0') && ch <= TEXT('9'))
		return (UINT32)(ch - TEXT('0'));
#ifndef SLD_NO_HEX
	if (ch >= TEXT('a') && ch <= TEXT('z'))
		return (UINT32)(ch - TEXT('a')) + 10UI32;
	if (ch >= TEXT('A') && ch <= TEXT('Z'))
		return (UINT32)(ch - TEXT('A')) + 10UI32;
#endif
	return (UINT32)(-1);
}

static inline VOID accumulate_decimal_digits_into_big_integer(PUINT8 first_digit, PUINT8 last_digit, big_integer& result)
{
	UINT32 accumulator = 0UI32;
	UINT32 accumulator_count = 0UI32;
	for (PUINT8 it = first_digit; it != last_digit; ++it)
	{
		if (accumulator_count == 9UI32)
		{
			multiply(result, 1000UI32 * 1000UI32 * 1000UI32);
			add(result, accumulator);
			accumulator = 0UI32;
			accumulator_count = 0UI32;
		}
		accumulator *= 10UI32;
		accumulator += (UINT32)*it;
		++accumulator_count;
	}
	if (accumulator_count)
	{
		multiply_by_power_of_ten(result, accumulator_count);
		add(result, accumulator);
	}
}

static inline VOID right_shift_with_rounding(UINT64& value, UINT64 shift, BOOL bZeroTail)
{
	if (shift >= sizeof(UINT64) * (UINT64)CHAR_BIT)
	{
		value = 0UI64;
		return;
	}
	const BOOL lsb_bit = (value & (1UI64 << shift)) != 0UI64;
	const BOOL round_bit = (value & ((1UI64 << (shift - 1UI64)))) != 0UI64;
	const BOOL tail_bits = !bZeroTail || (value & ((1UI64 << (shift - 1UI64)) - 1UI64)) != 0UI64;
	value >>= shift;
	if (!round_bit && !tail_bits)
		return;
	if (round_bit && (tail_bits || lsb_bit))
		++value;
}

SLD_STATUS String2Double(LPCTSTR lpszString, double& result)
{
	double_type& components = (double_type&)result;
	while (*lpszString == TEXT(' ') || *lpszString == TEXT('\t') || *lpszString == TEXT('\r') || *lpszString == TEXT('\n') || *lpszString == TEXT('\v') || *lpszString == TEXT('\f'))
		++lpszString;
	if (*lpszString == TEXT('-'))
	{
		components._sign = 1UI64;
		++lpszString;
	}
	else
	{
		components._sign = 0UI64;
		if (*lpszString == TEXT('+'))
			++lpszString;
	}
	if (*lpszString == TEXT('I') || *lpszString == TEXT('i'))
	{
		++lpszString;
		if (*lpszString == TEXT('N') || *lpszString == TEXT('n'))
		{
			++lpszString;
			if (*lpszString == TEXT('F') || *lpszString == TEXT('f'))
			{
				components._exponent = exponent_mask;
				components._mantissa = 0UI64;
				return SLD_OK;
			}
		}
		goto NoDigits;
	}
	if (*lpszString == TEXT('N') || *lpszString == TEXT('n'))
	{
		++lpszString;
		if (*lpszString == TEXT('A') || *lpszString == TEXT('a'))
		{
			++lpszString;
			if (*lpszString == TEXT('N') || *lpszString == TEXT('n'))
			{
				components._exponent = exponent_mask;
				++lpszString;
				if (*lpszString == TEXT('('))
				{
					++lpszString;
					if (*lpszString == TEXT('S') || *lpszString == TEXT('s'))
					{
						++lpszString;
						if (*lpszString == TEXT('N') || *lpszString == TEXT('n'))
						{
							++lpszString;
							if (*lpszString == TEXT('A') || *lpszString == TEXT('a'))
							{
								++lpszString;
								if (*lpszString == TEXT('N') || *lpszString == TEXT('n'))
								{
									++lpszString;
									if (*lpszString == TEXT(')'))
									{
										components._mantissa = 1UI64;
										return SLD_OK;
									}
								}
							}
						}
					}
					else if (*lpszString == TEXT('I') || *lpszString == TEXT('i'))
					{
						++lpszString;
						if (*lpszString == TEXT('N') || *lpszString == TEXT('n'))
						{
							++lpszString;
							if (*lpszString == TEXT('D') || *lpszString == TEXT('d'))
							{
								++lpszString;
								if (*lpszString == TEXT(')'))
								{
									components._sign = 1UI64;
									components._mantissa = special_nan_mantissa_mask;
									return SLD_OK;
								}
							}
						}
					}
				}
				components._mantissa = denormal_mantissa_mask;
				return SLD_OK;
			}
		}
		goto NoDigits;
	}
#ifndef SLD_NO_HEX
	UINT32 max_digit_value;
	if (*lpszString == TEXT('0') && (*(lpszString + 1) == TEXT('x') || *(lpszString + 1) == TEXT('X')))
	{
		max_digit_value = 0xFUI64;
		lpszString += 2;
	}
	else
		max_digit_value = 9UI64;
#else
	UINT32 max_digit_value = 9UI64;
#endif
	INT32 exponent_adjustment = 0I32;
	BOOL bDigits = FALSE;
	while (*lpszString == TEXT('0'))
	{
		bDigits = TRUE;
		++lpszString;
	}
	UINT8 mantissa_buffer[768];
	PUINT8 mantissa_it = mantissa_buffer;
	PUINT8 mantissa_last = mantissa_buffer + _countof(mantissa_buffer);
	for (; ; ++lpszString)
	{
		UINT32 digit_value = parse_digit(*lpszString);
		if (digit_value > max_digit_value)
			break;
		bDigits = TRUE;
		if (mantissa_it != mantissa_last)
			*mantissa_it++ = (UINT8)digit_value;
		++exponent_adjustment;
	}
	if (*lpszString == TEXT('.'))
	{
		++lpszString;
		if (mantissa_it == mantissa_buffer)
		{
			while (*lpszString == TEXT('0'))
			{
				bDigits = TRUE;
				--exponent_adjustment;
				++lpszString;
			}
		}
		for (; ; ++lpszString)
		{
			UINT32 digit_value = parse_digit(*lpszString);
			if (digit_value > max_digit_value)
				break;
			bDigits = TRUE;
			if (mantissa_it != mantissa_last)
				*mantissa_it++ = (UINT8)digit_value;
		}
	}
	if (!bDigits)
	{
#ifndef SLD_NO_HEX
		if (max_digit_value == 0xFUI64)
		{
			components._exponent = 0UI64;
			components._mantissa = 0UI64;
			return SLD_OK;
		}
#endif
		goto NoDigits;
	}
	BOOL bExponent;
	switch (*lpszString)
	{
	case 'e':
	case 'E':
#ifndef SLD_NO_HEX
		bExponent = max_digit_value != 0xFUI64;
#else
		bExponent = TRUE;
#endif
		break;
#ifndef SLD_NO_HEX
	case 'p':
	case 'P':
		bExponent = max_digit_value == 0xFUI64;
		break;
#endif
	default:
		bExponent = FALSE;
		break;
	}
	INT32 exponent = 0I32;
	if (bExponent)
	{
		++lpszString;
		BOOL bExponentNegative;
		if (*lpszString == TEXT('-'))
		{
			bExponentNegative = TRUE;
			++lpszString;
		}
		else
		{
			bExponentNegative = FALSE;
			if (*lpszString == TEXT('+'))
				++lpszString;
		}
		while (*lpszString == TEXT('0'))
			++lpszString;
		for (; ; ++lpszString)
		{
			UINT32 digit_value = parse_digit(*lpszString);
			if (digit_value >= 10UI32)
				break;
			exponent = exponent * 10I32 + (INT32)digit_value;
			if (exponent > maximum_temporary_decimal_exponent)
			{
				exponent = maximum_temporary_decimal_exponent + 1I32;
				break;
			}
		}
		if (bExponentNegative)
			exponent = -exponent;
	}
	while (mantissa_it != mantissa_buffer && *(mantissa_it - 1) == 0UI8)
		--mantissa_it;
	if (mantissa_it == mantissa_buffer)
	{
		components._exponent = 0UI64;
		components._mantissa = 0UI64;
		return SLD_OK;
	}
	if (exponent > maximum_temporary_decimal_exponent)
	{
		components._exponent = exponent_mask;
		components._mantissa = 0UI64;
		return SLD_OVERFLOW;
	}
	if (exponent < minimum_temporary_decimal_exponent)
	{
		components._exponent = 0UI64;
		components._mantissa = 0UI64;
		return SLD_UNDERFLOW;
	}
#ifndef SLD_NO_HEX
	exponent += exponent_adjustment * (max_digit_value == 0xFUI64 ? 4I32 : 1I32);
#else
	exponent += exponent_adjustment;
#endif
	if (exponent > maximum_temporary_decimal_exponent)
	{
		components._exponent = exponent_mask;
		components._mantissa = 0UI64;
		return SLD_OVERFLOW;
	}
	if (exponent < minimum_temporary_decimal_exponent)
	{
		components._exponent = 0UI64;
		components._mantissa = 0UI64;
		return SLD_UNDERFLOW;
	}
	UINT64 mantissa_value;
	INT32 exponent_value;
	BOOL bZeroTail;
#ifndef SLD_NO_HEX
	if (max_digit_value == 0xFUI64)
	{
		mantissa_value = 0UI64;
		exponent_value = exponent + mantissa_bits - 1I32;
		mantissa_last = mantissa_it;
		mantissa_it = mantissa_buffer;
		while (mantissa_it != mantissa_last && mantissa_value <= normal_mantissa_mask)
		{
			mantissa_value = mantissa_value * 16UI64 + *mantissa_it++;
			exponent_value -= 4I32;
		}
		bZeroTail = TRUE;
		while (mantissa_it != mantissa_last && bZeroTail)
			bZeroTail = bZeroTail && *mantissa_it++ == 0UI8;
		goto AssembleDouble;;
	}
#endif
	{
		const UINT32 required_bits_of_precision = (UINT32)mantissa_bits + 1UI32;
		const UINT32 positive_exponent = (UINT32)__MAX(0I32, exponent);
		const UINT32 mantissa_count = (UINT32)(mantissa_it - mantissa_buffer);
		const UINT32 integer_digits_present = __MIN(positive_exponent, mantissa_count);
		const UINT32 integer_digits_missing = positive_exponent - integer_digits_present;
		const PUINT8 integer_last = mantissa_buffer + integer_digits_present;
		const PUINT8 fractional_last = mantissa_buffer + mantissa_count;
		const UINT32 fractional_digits_present = (UINT32)(fractional_last - integer_last);
		{
			big_integer integer_value;
			accumulate_decimal_digits_into_big_integer(mantissa_buffer, integer_last, integer_value);
			if (integer_digits_missing && !multiply_by_power_of_ten(integer_value, integer_digits_missing))
			{
				components._exponent = exponent_mask;
				components._mantissa = 0UI64;
				return SLD_OVERFLOW;
			}
			const UINT32 integer_bits_of_precision = bit_scan_reverse(integer_value);
			if (integer_bits_of_precision >= required_bits_of_precision || !fractional_digits_present)
				goto BigIntegerToDouble;
			{
				big_integer fractional_numerator;
				accumulate_decimal_digits_into_big_integer(integer_last, fractional_last, fractional_numerator);
				big_integer fractional_denominator = make_big_integer(1UI64);
				if (!multiply_by_power_of_ten(fractional_denominator, exponent < 0I32 ? fractional_digits_present + (UINT32)(-exponent) : fractional_digits_present))
				{
					components._exponent = 0UI64;
					components._mantissa = 0UI64;
					return SLD_UNDERFLOW;
				}
				const UINT32 fractional_numerator_bits = bit_scan_reverse(fractional_numerator);
				const UINT32 fractional_denominator_bits = bit_scan_reverse(fractional_denominator);
				const UINT32 fractional_shift = fractional_denominator_bits > fractional_numerator_bits ? fractional_denominator_bits - fractional_numerator_bits : 0UI32;
				if (fractional_shift)
					shift_left(fractional_numerator, fractional_shift);
				const UINT32 required_fractional_bits_of_precision = required_bits_of_precision - integer_bits_of_precision;
				UINT32 remaining_bits_of_precision_required = required_fractional_bits_of_precision;
				if (integer_bits_of_precision)
				{
					if (fractional_shift > remaining_bits_of_precision_required)
						goto BigIntegerToDouble;
					remaining_bits_of_precision_required -= fractional_shift;
				}
				const UINT32 fractional_exponent = fractional_numerator < fractional_denominator ? fractional_shift + 1U : fractional_shift;
				shift_left(fractional_numerator, remaining_bits_of_precision_required);
				UINT64 fractional_mantissa = divide(fractional_numerator, fractional_denominator);
				bZeroTail = !fractional_numerator.used;
				const UINT32 fractional_mantissa_bits = bit_scan_reverse(fractional_mantissa);
				if (fractional_mantissa_bits > required_fractional_bits_of_precision)
				{
					const UINT32 shift = fractional_mantissa_bits - required_fractional_bits_of_precision;
					bZeroTail = bZeroTail && (fractional_mantissa & ((1UI64 << (UINT64)shift) - 1UI64)) == 0UI64;
					fractional_mantissa >>= (UINT64)shift;
				}
				const UINT32 integer_mantissa_low = integer_value.used ? integer_value.data[0] : 0UI32;
				const UINT32 integer_mantissa_high = integer_value.used > 1UI32 ? integer_value.data[1] : 0UI32;
				const UINT64 integer_mantissa = (UINT64)integer_mantissa_low + ((UINT64)integer_mantissa_high << 32UI64);
				mantissa_value = (integer_mantissa << (UINT64)required_fractional_bits_of_precision) + fractional_mantissa;
				exponent_value = integer_bits_of_precision ? (INT32)integer_bits_of_precision - 2I32 : -(INT32)fractional_exponent - 1I32;
				goto AssembleDouble;
			}

		BigIntegerToDouble:
			const INT32 base_exponent = mantissa_bits - 1I32;
			if (integer_bits_of_precision <= 64UI32)
			{
				const UINT32 mantissa_low = integer_value.used ? integer_value.data[0] : 0UI32;
				const UINT32 mantissa_high = integer_value.used > 1UI32 ? integer_value.data[1] : 0UI32;
				mantissa_value = mantissa_low + ((UINT64)mantissa_high << 32UI64);
				exponent_value = base_exponent;
				bZeroTail = fractional_digits_present == 0UI32;
				goto AssembleDouble;
			}
			const UINT32 top_element_bits = integer_bits_of_precision % 32UI32;
			const UINT32 top_element_index = integer_bits_of_precision / 32UI32;
			const UINT32 middle_element_index = top_element_index - 1UI32;
			const UINT32 bottom_element_index = top_element_index - 2UI32;
			if (!top_element_bits)
			{
				mantissa_value = integer_value.data[bottom_element_index] + ((UINT64)(integer_value.data[middle_element_index]) << 32UI64);
				exponent_value = base_exponent + (INT32)(bottom_element_index * 32UI32);
				bZeroTail = fractional_digits_present == 0UI32;
				for (UINT32 i = 0UI32; i != bottom_element_index; ++i)
					bZeroTail &= integer_value.data[i] == 0UI32;
				goto AssembleDouble;
			}
			const UINT32 top_element_mask = (1UI32 << top_element_bits) - 1UI32;
			const UINT32 top_element_shift = 64UI32 - top_element_bits;
			const UINT32 middle_element_shift = top_element_shift - 32UI32;
			const UINT32 bottom_element_bits = 32UI32 - top_element_bits;
			const UINT32 bottom_element_mask = ~top_element_mask;
			const UINT32 bottom_element_shift = 32UI32 - bottom_element_bits;
			mantissa_value = ((UINT64)(integer_value.data[top_element_index] & top_element_mask) << top_element_shift) + ((UINT64)integer_value.data[middle_element_index] << middle_element_shift) + ((UINT64)(integer_value.data[bottom_element_index] & bottom_element_mask) >> bottom_element_shift);
			exponent_value = base_exponent + (INT32)(bottom_element_index * 32UI32 + top_element_bits);
			bZeroTail = fractional_digits_present == 0UI32 && (integer_value.data[bottom_element_index] & top_element_mask) == 0UI32;
			for (UINT32 i = 0UI32; i != bottom_element_index; ++i)
				bZeroTail &= integer_value.data[i] == 0UI32;
		}

	AssembleDouble:
		const INT32 normal_mantissa_shift = mantissa_bits - (INT32)bit_scan_reverse(mantissa_value);
		INT32 normal_exponent = exponent_value - normal_mantissa_shift;
		if (normal_exponent > maximum_binary_exponent)
		{
			components._exponent = exponent_mask;
			components._mantissa = 0UI64;
			return SLD_OVERFLOW;
		}
		if (normal_exponent < minimum_binary_exponent)
		{
			const INT32 denormal_mantissa_shift = normal_mantissa_shift + normal_exponent + exponent_bias - 1I32;
			normal_exponent = -exponent_bias;
			if (denormal_mantissa_shift < 0I32)
			{
				right_shift_with_rounding(mantissa_value, -denormal_mantissa_shift, bZeroTail);
				if (!mantissa_value)
				{
					components._exponent = exponent_mask;
					components._mantissa = 0UI64;
					return SLD_UNDERFLOW;
				}
				if (mantissa_value > denormal_mantissa_mask)
					normal_exponent = exponent_value - (denormal_mantissa_shift + 1I32) - normal_mantissa_shift;
			}
			else
			{
				mantissa_value <<= (UINT64)denormal_mantissa_shift;
			}
		}
		else
		{
			if (normal_mantissa_shift < 0I32)
			{
				right_shift_with_rounding(mantissa_value, -normal_mantissa_shift, bZeroTail);
				if (mantissa_value > normal_mantissa_mask)
				{
					mantissa_value >>= 1UI64;
					++normal_exponent;
					if (normal_exponent > maximum_binary_exponent)
					{
						components._exponent = exponent_mask;
						components._mantissa = 0UI64;
						return SLD_OVERFLOW;
					}
				}
			}
			else if (normal_mantissa_shift > 0I32)
			{
				mantissa_value <<= (UINT64)normal_mantissa_shift;
			}
		}
		mantissa_value &= denormal_mantissa_mask;
		components._exponent = (UINT64)(normal_exponent + exponent_bias);
		components._mantissa = mantissa_value;
		return SLD_OK;
	}

NoDigits:
	components._exponent = 0UI64;
	components._mantissa = 0UI64;
	return SLD_NODIGITS;
}

对转换代码的几点说明:

1、代码C/C++语言,仅适用于Windows平台

2、代码仅实现了double类型的浮点数与字符串的相互转换,float类型可使用double类型进行过渡

3、由于转换需要,按C++方式实现了一个轻量级大整数类,用于C语言时需在此简单改造即可

4、代码借鉴了标准库中相关代码,并做了一些优化,运行效率并不低于标准库类似函数

5、代码基于IEEE规范对浮点数进行解析,有较高的精度,结果与标准库结果完全一致

6、由于时间仓促,还未对源文件中代码进行详细注释,敬请见谅



对Double2String函数的几点说明:

1、函数不检查lpszBuffer是否是空指针,亦不检查是否会导致lpszBuffer缓冲区溢出,但当缓冲区大小大于max(360, FractionalDigitCount + 50)时,可满足各情况不溢出

2、FractionalDigitCount参数为保留的小数位数,而非标准库中的有效数字(笔者认为前者应用更多)

3、lpszBuffer仅为存放结果的缓冲区,最终得到的字符串为函数的返回值(这样设计是因为:为提高效率,减小不必要的复制,代码实现时,转换得到的字符串可能从lpszBuffer开头的后几个字符开始存储,前面的字符用于正负号的添加、四舍五入时的进位等)

4、保留的小数位数仅支持正数(通常亦为该情况)

5、当转换结果为"1#INF"、"1#IND"、"1#QNAN"、"1#SNAN"时,参数FractionalDigitCount将被忽略



对String2Double函数的几点说明:

1、字符串可为INF、NAN、NAN(SNAN)、NAN(IND)等(不区分大小写)

2、字符串支持IEEE规范规定的任意格式

3、字符串支持十六进制浮点数,需以"0x"或"0X"开头

4、字符串不需要十六进制支持时,可在头文件包含前定义SLD_NO_HEX宏,以减小代码体积并提高运行效率

5、函数返回值为转换状态枚举,枚举成员分别代表成功、没有数据、下溢、上溢



最后附上一个更加精简的字符串转浮点数的代码:

static double _ttof(LPCTSTR lpszString)
{
    TCHAR cSign = TEXT('+');
    while (*lpszString <= TEXT(' '))
        ++lpszString;
    if (*lpszString == TEXT('-') || *lpszString == TEXT('+'))
        cSign = *lpszString++;
    double value = 0.0;
    while ((unsigned int)(*lpszString - TEXT('0')) < 10U)
        value = value * 10.0 + (double)(*lpszString++ - TEXT('0'));
    if (*lpszString == TEXT('.'))
    {
        ++lpszString;
        double factor = 1.0;
        while ((unsigned int)(*lpszString - TEXT('0')) < 10U)
        {
            factor *= 0.1;
            value += (double)(*lpszString++ - TEXT('0')) * factor;
        }
    }
    if (*lpszString == TEXT('e') || *lpszString == TEXT('E'))
    {
        ++lpszString;
        unsigned int expo = 0U;
        double factor = 10.0;
        switch (*lpszString)
        {
        case TEXT('-'):
            factor = 0.1;
        case TEXT('+'):
            ++lpszString;
            break;
        case TEXT('0'):
        case TEXT('1'):
        case TEXT('2'):
        case TEXT('3'):
        case TEXT('4'):
        case TEXT('5'):
        case TEXT('6'):
        case TEXT('7'):
        case TEXT('8'):
        case TEXT('9'):
            break;
        default:
            return value;
        }
        while ((unsigned int)(*lpszString - TEXT('0')) < 10U)
            expo = 10U * expo + (unsigned int)(*lpszString++ - TEXT('0'));
        for (;;)
        {
            if (expo & 1U)
                value *= factor;
            if (!(expo >>= 1U))
                break;
            factor *= factor;
        }
    }
    return cSign == TEXT('-') ? -value : value;
}

该代码实现非常简单,没有考虑溢出、INF、NAN等情况,亦可能存在精度丢失,且仅支持十进制浮点数字符串,不建议使用该代码



结语:

1、代码实现了浮点数与字符串的相互转换,代码具有较高的运行效率,并考虑各种特殊情况,具有较好的适用性与可靠性

2、代码的完成经历了研究、编写、调试等阶段,过程较为辛苦,但收获颇丰,对浮点数的存储及转换有了更加深刻的理解

3、代码中错误在所难免,如果发现任何BUG或有不足之处敬请告知,同时欢迎提出宝贵意见和建议,后续会不断进行完善


你可能感兴趣的:(C/C++应用与心得)