不使用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 <paschen@sohu.com>
// 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 <Windows.h>



//说明:  将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 <paschen@sohu.com>
// 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 <Windows.h>


#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 <typename _CountofType, size_t _SizeOfArray>
	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;
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值