将一个浮点数据转换成字符串,看似简单的一个问题却涉及到许多计算机的基础知识,如浮点数在计算机中的表示方式、计算机计算精度以及计算溢出等问题。

    浮点数转字符串最常用的一种方法是使用C语言库函数sprintf(),它是字符串格式化命令,主要功能是把格式化的数据写入某个字符串中,使用它容易造成内存访问错误,不过这些问题都较容易找出。另外的方法就是自己编写转换函数了,最容易想到的方法就是:1)将浮点数的整数部分转换成字符串;2)将浮点数的小数部分转换成字符串;3)加小数点和浮点数的正负标识。由于计算机中对于一个特定的浮点数据可能是近似表示的,而且在转换成字符串的过程中也存在计算误差,前面的这两种转换方法的转换结果与原特定浮点数据都会有偏差。

    通过实验对比分析:插入(insert)运算符<<的转换精度最低;sprintf()函数可转换的数据范围最大,但转换精度略差于自己编写的转换函数;自己编写的转换函数在整数部分不能超出long整型所能表示的范围,这时转换精度较高于其它方法。转换精度高是指对于一个特定的浮点数转换成的字符串能够更接近该浮点数的字面表示。

    下面是实验的源代码,其中

const string f2str(double a) throw(ParameterErrorException)

是浮点数转字符串函数,

const string f2str(double a, int bitwise) throw(ParameterErrorException);

函数是一种改进的方法。

#include<iostream>
#include<string>
#include<cstddef>
#include<stdexcept>
using namespace std;

class ParameterErrorException : public logic_error {
public:
	ParameterErrorException(const string& msg) : logic_error(msg) {
	}
};

const string f2str(double a) throw(ParameterErrorException);
const string f2str(double a, int bitwise) throw(ParameterErrorException);

const string f2str(double a){
	string temp = "";

	long b = (long)a;
	double c = a-b;
	
	//if a belows zero, then change its
	//integer part and float part to 
	//positive.
	if(a < 0) {
		b = -b;
		c = -c;
	}
	
	if( !(b <= (1<<30)) ) {
		throw ParameterErrorException("Pass illegal parameter a!");
	}

	//change a's integer part into string
	do{
		temp += (char)(b%10 + '0');
		b = b/10;
	}while(b>0);
	size_t i = temp.length();
	for(size_t j=0; j<i/2; j++){
		temp[j] = temp[j] + temp[i-j-1];
		temp[i-j-1] = temp[j] - temp[i-j-1];
		temp[j] = temp[j] - temp[i-j-1];
	}

	//add the pointer of a float number to string
	temp += '.';
	
	//convert a's float part into string
	while(c > 0.000001){
		c = c * 10;
		temp += (char)((int)c + '0');
		c -= (int)c;
	}
	
	//add negtive sign '-'
	if(a<0) {
		temp.insert(0, '-');
	}

	return temp;
}


const string f2str(double a, int bitwise){

	if(bitwise < 0) {
		throw ParameterErrorException("Pass illegal parameter bitwise!");
	}

	string temp = "";

	long b = (long)a;
	double c = a-b;
	
	//if a belows zero, then change its
	//integer part and float part to 
	//positive
	if(a < 0) {
		b = -b;
		c = -c;
	}

	if( !(b <= (1<<30)) ) {
		throw ParameterErrorException("Pass illegal parameter a!");
	}

	//change a's integer part into string
	do{
		temp += (char)(b%10+'0');
		b = b/10;
	}while(b>0);
	size_t i = temp.length();
	for(size_t j=0; j<i/2; j++){
		temp[j] = temp[j] + temp[i-j-1];
		temp[i-j-1] = temp[j]-temp[i-j-1];
		temp[j] = temp[j]-temp[i-j-1];
	}

	//memorize the pointer's position
	int pointpos = temp.length();
	
	//vonvert a's float part into string
	do{
		c = c*10;
		temp += (char)((int)c + '0');
		c -= (int)c;
		bitwise--;
		if(bitwise == 0 && c*10 >= 5) {//computer carrier
			int len = temp.length()-1;
			while(len>=0 && (++temp[len]) > '9') {
				temp[len] = '0';
				len--;
			}
		}
	}while(bitwise > 0);
        
        //add the pointer of a float number to string
	temp.insert(pointpos, ".");
        
        //add negtive sign '-'
	if(a<0) {
		temp.insert(0, "-");
	}

	return temp;
}


int main(){

	double a = -678976544.19812368976;
	cout << a << endl;

	char temp[100] = {0};
	sprintf(temp, "%f", a);
	cout << temp << endl;

	string str;
	try {
		str = f2str(a);
		cout << str << endl;
		str = f2str(a, 8);
		cout<<str<<endl;
	}catch(ParameterErrorException& pee) {
		cout << pee.what() << endl;
		cout << "at file: " << __FILE__ <<endl;
		cout <<"line:" << __LINE__ << endl;
	}

	return 0;
}