C++ 基于vector的高精度浮点类

前言

大家好,写代码也是一个上瘾的事情啊,刚刚结束了赫夫曼编码我就马不停蹄的开始着手算数编码了。不过在我研究了一下算数编码的原理过后,我发现如果只用C语言默认提供的float和double类型,去完成我们图像的算数编码好像有些困难。当我们不断的划分区间后,最终的结果将是一个相当精确地小数,而以IEEE754为标准的double都不能完成这个任务。显然,我们要搬出曾经的噩梦,高精度算法了。
早在大一学习c++时,我就接触过高精度算法的一些基础内容,当时是作为选做的课后题,我用char*动态分配长度的字符串艰难的完成了+、-、*运算,卡在了除法。这回我先做了一些研究,最后我决定参考这篇博客中提供的代码,利用vector<char>来比较好的实现一个高精度浮点类。(参考博客中的除法算法不完备,我已改正。另:如有侵权,请告知)

一、类定义

先上代码:

class WFloat	//高精度浮点数类
{
	//基本运算符重载
	friend WFloat operator+(const WFloat&, const WFloat&);	//加法重载
	friend WFloat operator-(const WFloat&, const WFloat&);	//减法重载
	friend WFloat operator*(const WFloat&, const WFloat&);	//乘法重载
	friend WFloat operator/(const WFloat&, const WFloat&) throw(DividedByZeroException);	//除法重载
	friend WFloat operator-(const WFloat&);	//负号重载
	
	//比较重载
	friend bool operator==(const WFloat&, const WFloat&);	//等于重载
	friend bool operator!=(const WFloat&, const WFloat&);	//不等于重载
	friend bool operator<(const WFloat&, const WFloat&);	//小于重载
	friend bool operator<=(const WFloat&, const WFloat&);	//小于等于重载
	friend bool operator>(const WFloat&, const WFloat&);	//大于重载
	friend bool operator>=(const WFloat&, const WFloat&);	//大于等于重载

	//扩展运算符重载
	friend WFloat operator+=(WFloat&, const WFloat&);	//加等重载
	friend WFloat operator-=(WFloat&, const WFloat&);	//减等重载
	friend WFloat operator*=(WFloat&, const WFloat&);	//乘等重载
	friend WFloat operator/=(WFloat&, const WFloat&);	//除等重载
	
	//输入输出重载
	friend ostream& operator<<(ostream&, const WFloat&);	//输出重载
	friend istream& operator>>(istream&, WFloat&);	//输入重载

public:
	WFloat();
	WFloat(int);	//用一个整数构造
	WFloat(string&);	//用一个字符串构造
	WFloat(const WFloat&);	//用一个高精度数构造
	WFloat operator=(const WFloat&);	//赋值函数
	WFloat abs() const;	//取绝对值
	~WFloat() {}

	static const WFloat ZERO;	//定义0
	static const WFloat ONE;	//定义1
	static const WFloat TEN;	//定义10(用于除法化整)

private:
	vector<char>integer;	//整数部分
	vector<char>decimal;	//小数部分
	void trim();	//将多余的零删去
	bool tag;	//用来表示正负,true为正
};
1、私有成员

首先看私有成员,我们用两个vector<char>类型的动态数组分别存储浮点数的整数部分和小数部分,我们在读入一个高精度数时(比如用字符串来构造),按照从后(右)往前(左)的顺序分别写入到小数部分和整数部分,以'.'小数点作为分隔。例如:输入“1234.5678”,那么小数部分的存储如下8 7 6 5,整数部分为4 3 2 1
正因为我们按照上述的方式存储,因此在小数部分的首部可能会出现多余的0,例如输入"1.5600",那么小数部分就是0 0 6 5,同理可知整数部分的尾部可能会有多余的0。为了解决这个问题,提供了函数trim()来删除多余的0。
对于正负的表示,我们用了一个布尔型的tag标签,这主要是便于条件判断。

2、公有成员

公有成员主要是提供了构造函数,可以看到我们可以使用int、string、WFloat来构造一个高精度浮点数,其中利用string和WFloat构造的情况比较多,int型只是为了表示高精度整型。
我们还定义了三个静态变量,分别是0、1、10,其用处会在运算符重载部分看到。

3、友元函数

友元函数占了最大头,但是没什么好说的,我们的目的就是重载所有的相关运算符,来实现一个可以与double、float近似的高精度浮点类。由于我的需求是完成算数编码,因此我只实现了基础四则运算,布尔运算,如果需要平方、开方等运算,可以自行实现。

二、重要函数实现

因为按照惯例我会在文末给出仓库传送门,所以全部的代码大家都可以查到。出于篇幅的考虑,我决定只将最重要的函数讲解一下(实际上也不少了)

1、构造函数

构造函数我们只讲用string类型构造

WFloat::WFloat(string &num)	//用字符串初始化,格式形如"-123.456"、"1.0"
{
	bool type = true;	//用于判断小数部分是否结束
	tag = true;	//默认为正数,读到'-'再变为负数
	for (string::reverse_iterator iter = num.rbegin(); iter < num.rend(); iter++)	  //逆向迭代
	{
		char ch = (*iter);
		if (ch == '.')	//遇到小数点则开始向整数部分写入
		{
			type = false;
			iter++;
		}
		if (iter == num.rend() - 1)	//读取正负号
		{
			if (ch == '+')
			{
				break;
			}
			if (ch == '-')
			{
				tag = false;
				break;
			}
		}
		//利用逆向迭代器,将整个数据倒序存入
		if (type)
			decimal.push_back((char)((*iter) - '0'));
		else
			integer.push_back((char)((*iter) - '0'));
	}
}

就像我在类定义里所说的,我们用一个逆向迭代器从后往前的赋值,在遇到小数点之前将字符存入小数部分,之后存入整数部分。

2、trim()

整理函数拿出来说是因为参考博客中写的有一点问题。

void WFloat::trim()	
{
	//因为我们是逆向存储的,所以整数的尾部和小数的首部可能会有多余的0
	vector<char>::reverse_iterator iter = integer.rbegin();	//对整数部分
	while (!integer.empty() && (*iter) == 0)
	{
		integer.pop_back();	//指向不为空且尾部为0,删去
		iter = integer.rbegin();	//再次指向尾部
		//整数部分的“尾部”就是最高位,如00515.424900的左两个0
	}

	if (integer.size() == 0 && decimal.size() == 0)	//如果整数、小数全为空
	{
		tag = true;
	}

	if (integer.size() == 0)	//如果整数部分是0
	{
		integer.push_back(0);
	}

	vector<char>::const_iterator it = decimal.begin();	//对小数部分
	while (!decimal.empty() && (*it) == 0)
	{
		it = decimal.erase(it);	//指向不为空且首部为0,删去
		//小数部分的“首部”就是最低位,上例中的右两个0
	}

	if (decimal.size() == 0)	//如果小数部分是0
	{
		decimal.push_back(0);
	}
}

参考博客中对于符号的修改有问题,应该是当整数部分和小数部分同时为0时,才将符号修改为正,而不是任一为0时修改为正。这个问题会影响后面乘法与除法的结果符号,特此说明。

3、输入与输出
3.1 operator<<
ostream& operator<<(ostream& out, const WFloat& num)	//输出重载
{
	if (!num.tag)	//负数
	{
		out << "-";
	}

	for (vector<char>::const_reverse_iterator iter = num.integer.rbegin(); iter != num.integer.rend(); iter++)  //输出整数部分
	{
		out << (char)((*iter) + '0');
	}

	cout << '.';

	for (vector<char>::const_reverse_iterator iter = num.decimal.rbegin(); iter != num.decimal.rend(); iter++)  //输出小数部分
	{
		out << (char)((*iter) + '0');
	}
	return out;
}

输出部分只要注意从后往前的顺序即可。

3.2 operator>>
istream& operator>>(istream& in, WFloat& num)	//输入重载
{
	string str;
	in >> str;
	num = WFloat(str);
	return in;
}

输入部分我们调用构造函数。

4、布尔判断

我们先写布尔判断部分,因为在计算过程中需要使用到两个高精度数之间的各种判断。

4.1 operator<

小于和等于,通过一些简单的布尔代数运算就可以推导出全部逻辑关系,因此我们只列出小于和等于的定义。

bool operator<(const WFloat& num1, const WFloat& num2)	//小于重载
{
	bool sign;	//返回值
	if (num1.tag != num2.tag)	//如果异号
	{
		sign = !num1.tag;	//如果num1正,则不小于;反之,则小于
		return sign;
	}
	else
	{
		//如果同号,先比较整数再比较小数
		if (num1.integer.size() != num2.integer.size())	//如果整数部分不等长
		{
			if (num1.tag)	//如果同为正,则整数部分长的大
			{
				sign = num1.integer.size() < num2.integer.size();	
				return sign;
			}
			else
			{
				//同为负,则整数部分长的小
				sign = num1.integer.size() > num2.integer.size();
				return sign;
			}
		}
		//如果整数部分等长
		vector<char>::const_reverse_iterator iter1, iter2;
		iter1 = num1.integer.rbegin();
		iter2 = num2.integer.rbegin();
		while (iter1 != num1.integer.rend())
		{
			if (num1.tag && *iter1 < *iter2)
				return true;
			if (num1.tag && *iter1 > *iter2)
				return false;
			if (!num1.tag && *iter1 > *iter2)
				return true;
			if (!num1.tag && *iter1 < *iter2)
				return false;
			iter1++;
			iter2++;
		}

		//下面比较小数部分
		vector<char>::const_reverse_iterator it1, it2;
		it1 = num1.decimal.rbegin();
		it2 = num2.decimal.rbegin();
		while (it1 != num1.decimal.rend() && it2!=num2.decimal.rend())
		{
			if (num1.tag && *it1 < *it2)
				return true;
			if (num1.tag && *it1 > *it2)
				return false;
			if (!num1.tag && *it1 > *it2)
				return true;
			if (!num1.tag && *it1 < *it2)
				return false;
			it1++;
			it2++;
		}
		//如果整数部分,而小数部分停止前全部一样,那么看谁的小数位更多
		return(num1.tag && it2 != num2.decimal.rend()) || (!num1.tag && it1 != num1.decimal.rend());
	}
}

布尔运算这部分主要是情况的考虑完全问题。异号的情况最容易判断,正数为大,因此我们将同号、异号作为最外层的条件判断。
当同号时,先比较整数部分、再比较小数部分。整数部分比较时先比较长度,如果没有结果再逐位比较;整数部分完全相同时,需要逐位比较小数部分。

4.1 operator==

等于和小于的判断逻辑几乎相同,不再复述。

bool operator==(const WFloat& num1, const WFloat& num2)	//等于重载
{
	if (num1.tag != num2.tag)
		return false;
	if (num1.integer.size() != num2.integer.size())
		return false;
	if (num1.decimal.size() != num2.decimal.size())
		return false;

	//如果长度和符号相同,那么下面逐位比较
	vector<char>::const_iterator iter1, iter2;
	iter1 = num1.decimal.begin();
	iter2 = num2.decimal.begin();
	while (iter1 != num1.decimal.end())
	{
		if (*iter1 != *iter2)
			return false;
		iter1++;
		iter2++;
	}

	iter1 = num1.integer.begin();
	iter2 = num2.integer.begin();
	while (iter1 != num1.integer.end())
	{
		if (*iter1 != *iter2)
			return false;
		iter1++;
		iter2++;
	}
	return true;
}
5、运算符重载

+、-、*、/可以转化为+=、-=、*=、/=,因此我们只需要完成后者。

5.1 operator+=

加、减运算是相对容易完成的部分。我们先上代码,再对其中的部分进行精解。

WFloat operator+=(WFloat& num1, const WFloat& num2)	//加等于重载
{
	if (num1.tag == num2.tag)	//只处理同符号数,异号由-减法处理
	{
		vector<char>::iterator iter1;
		vector<char>::const_iterator iter2, it;

		//先处理小数部分
		int num1_decimal_size = num1.decimal.size();	//小数部分长度
		int num2_decimal_size = num2.decimal.size();
		char carry = 0;	//进位
		if (num1_decimal_size < num2_decimal_size)	//如果num2小数部分更长
		{
			iter1 = num1.decimal.begin();
			iter2 = num2.decimal.begin();
			iter2 = iter2 - (num1_decimal_size - num2_decimal_size);	//将指向调整到一一对应的位置

			while (iter1 != num1.decimal.end() && iter2 != num2.decimal.end())
			{
				(*iter1) = (*iter1) + (*iter2) + carry;
				carry = ((*iter1) > 9);	//如果大于9则carry=1
				(*iter1) = (*iter1) % 10;
				iter1++;
				iter2++;
			}

			it = num2.decimal.begin();
			iter2 = num2.decimal.end();
			iter2 = iter2 - num1_decimal_size - 1;	//指向长出部分
			while (iter2 != it)
			{
				num1.decimal.insert(num1.decimal.begin(), *iter2);
				iter2--;
			}
			num1.decimal.insert(num1.decimal.begin(), *iter2);
			iter1 = num1.decimal.begin();
		}
		else
			if (num1_decimal_size > num2_decimal_size) //如果num1小数部分更长,同理
			{
				iter1 = num1.decimal.begin();
				iter1 = iter1 + (num1_decimal_size - num2_decimal_size);
				//将指向调整到一一对应的位置
				iter2 = num2.decimal.begin();

				while (iter1 != num1.decimal.end() && iter2 != num2.decimal.end())
				{
					(*iter1) = (*iter1) + (*iter2) + carry;
					carry = ((*iter1) > 9);	//如果大于9则carry=1
					(*iter1) = (*iter1) % 10;
					iter1++;
					iter2++;
				}
			}
			else
			{
				iter1 = num1.decimal.begin();	//如果二者等长
				iter2 = num2.decimal.begin();
				while (iter1 != num1.decimal.end() && iter2 != num2.decimal.end())
				{
					(*iter1) = (*iter1) + (*iter2) + carry;
					carry = ((*iter1) > 9);	//如果大于9则carry=1
					(*iter1) = (*iter1) % 10;
					iter1++;
					iter2++;
				}
			}

		//再处理整数部分
		iter1 = num1.integer.begin();
		iter2 = num2.integer.begin();
		//从个位开始相加
		while (iter1 != num1.integer.end() && iter2 != num2.integer.end())
		{
			(*iter1) = (*iter1) + (*iter2) + carry;
			carry = ((*iter1) > 9);	//如果大于9则carry=1
			(*iter1) = (*iter1) % 10;
			iter1++;
			iter2++;
		}
		//总会有一个先到达end()
		while (iter1 != num1.integer.end())	//如果被加数更长,处理进位
		{
			(*iter1) = (*iter1) + carry;
			carry = ((*iter1) > 9);	//如果大于9则carry=1
			(*iter1) = (*iter1) % 10;
			iter1++;
		}
		while (iter2 != num2.integer.end())	//加数更长
		{
			char val = (*iter2) + carry;
			carry = (val > 9);
			val %= 10;
			num1.integer.push_back(val);
			iter2++;
		}
		if (carry != 0)	//如果还有进位,则说明要添加一位
		{
			num1.integer.push_back(carry);
		}
		return num1;
	}
	else
	{	//如果异号
		if (num1.tag)	//如果被加数为正,加数为负,相当于减等于
		{
			WFloat temp(-num2);
			return num1 -= temp;
		}
		else
		{
			WFloat temp(-num1);
			return num1 = num2 - temp;
		}
	}
}

可以看到,异号时的加法相当于减法,因此我们的+=定义中只处理同号情况,异号交由-处理。
我们的运算操作几乎都是模仿人们的手算进行的,因此就像草纸演算,我们从后往前进行逐位运算。
在计算时首先应当将位数对其,这主要是针对小数部分。运算由三部分组成,当前位被加数、加数、进位(这有点像用代码实现一个加法器),注意对被加数进行模10来保证取值出于0-9之间。
总体来说加减法没有理解难度,并且我的注释很详细,应该不难掌握。

5.2 operator-=

同理加法,我们只处理同号的情况,异号交由+处理。

WFloat operator-=(WFloat& num1, const WFloat& num2)	//减等于重载
{
 	if (num1.tag == num2.tag)	//只处理同号,异号由+加法处理
	{
		if (num1.tag)	//如果同为正
		{
			if (num1 < num2)	//且被减数小
			{
				WFloat temp(num2 - num1);
				num1 = -temp;
				return num1;
			}
		}
		else
		{
			if (-num1 > -num2)	//如果同为负,且被减数绝对值大
				return num1 = -((-num1) - (-num2));
			else
				return num1 = (-num2) - (-num1);
		}

		//下面是同为正,且减数小的情况
		//小数部分 
		char borrow = 0;  //借位
		int num1_decimal_size = num1.decimal.size();
		int num2_decimal_size = num2.decimal.size();
		vector<char>::iterator it1 = num1.decimal.begin();
		vector<char>::const_iterator it2 = num2.decimal.begin();

		if (num1_decimal_size > num2_decimal_size)	//如果被减数小数部分更长
		{
			num1_decimal_size -= num2_decimal_size;	//长出部分
			it1 = it1 + num1_decimal_size;	//跳过长出部分
		}
		else 
		{	//如果减数的小数部分更长,则需要给被减数补0
			int number = num2_decimal_size - num1_decimal_size;
			while (number != 0)
			{
				num1.decimal.insert(num1.decimal.begin(), 0); //缺少的位数补0
				number--;
			}
			it1 = num1.decimal.begin();	//插入后需要重新指向
			it2 = num2.decimal.begin();
		}
		while ((it1 != num1.decimal.end()) && (it2 != num2.decimal.end()))
		{
			(*it1) = (*it1) - (*it2) - borrow;
			borrow = 0;
			if ((*it1) < 0)
			{
				borrow = 1;
				(*it1) += 10;
			}
			it1++;
			it2++;
		}
		//整数部分
		vector<char>::iterator iter1;
		vector<char>::const_iterator iter2;
		iter1 = num1.integer.begin();
		iter2 = num2.integer.begin();

		while (iter1 != num1.integer.end() && iter2 != num2.integer.end())
		{
			(*iter1) = (*iter1) - (*iter2) - borrow;
			borrow = 0;
			if ((*iter1) < 0) {
				borrow = 1;
				(*iter1) += 10;
			}
			iter1++;
			iter2++;
		}
		while (iter1 != num1.integer.end()) {
			(*iter1) = (*iter1) - borrow;
			borrow = 0;
			if ((*iter1) < 0) 
			{
				borrow = 1;
				(*iter1) += 10;
			}
			else break;
			iter1++;
		}
		num1.trim();	//把多余的0去掉
		return num1;
	}
	else 
	{
		//如果异号
		if (num1 > WFloat::ZERO)
		{
			WFloat temp(-num2);
			return num1 += temp;
		}
		else
		{ 
			WFloat temp(-num1);
			return num1 = -(num2 + temp);
		}
	}
}

减法需要考虑结果的符号问题,最好的解决办法就是将问题尽可能转化成同一类。在最初的一系列条件判断后,我们只需要处理同为正且减数小于被减数的情况。
注意,在小数部分,给被减数补0的操作结束后,一定要重新将迭代器指向decimal.begin()。参考博客中没有这两行代码,我在运行时会报错。
剩下的运算部分与加法大同小异,不再复述。

5.3 operator*=

乘除部分的难度就提高了,尤其是除法还要更加复杂一些。我们先看乘法

WFloat operator*=(WFloat& num1, const WFloat& num2)	//乘等于重载
{
	WFloat result(0);	//储存结果
	if (num1 == WFloat::ZERO || num2 == WFloat::ZERO)	//有0做乘数得0
		result = WFloat::ZERO;
	else
	{
		int size = 0;
		vector<char>temp_num1(num1.integer.begin(), num1.integer.end());	//一个临时变量,用于将整数部分与小数部分合并
		if (num1.decimal.size() != 1 || (num1.decimal.size() == 1 && (*num1.decimal.begin()) != 0)) //如果被乘数有小数部分,插入小数
		{
			temp_num1.insert(temp_num1.begin(), num1.decimal.begin(), num1.decimal.end());
			size += num1.decimal.size();
		}
		
		vector<char>temp_num2(num2.integer.begin(), num2.integer.end());	//一个临时变量,用于将整数部分与小数部分合并
		if (num2.decimal.size() != 1 || (num2.decimal.size() == 1 && (*num2.decimal.begin()) != 0)) //如果被乘数有小数部分,插入小数
		{
			temp_num2.insert(temp_num2.begin(), num2.decimal.begin(), num2.decimal.end());
			size += num2.decimal.size();
		}

		//开始乘法
		vector<char>::const_iterator iter2 = temp_num2.begin();
		while (iter2 != temp_num2.end())
		{
			if (*iter2 != 0)
			{
				deque<char>temp(temp_num1.begin(), temp_num1.end());
				char carry = 0;	//进位
				deque<char>::iterator iter1 = temp.begin();
				while (iter1 != temp.end())	//被乘数乘以某一位乘数
				{
					(*iter1) *= (*iter2);
					(*iter1) += carry;
					carry = (*iter1) / 10;
					(*iter1) %= 10;
					iter1++;
				}
				if (carry != 0)
				{
					temp.push_back(carry);
				}
				int num_of_zeros = iter2 - temp_num2.begin();	//计算错位
				while (num_of_zeros--) 
					temp.push_front(0);	//乘得结果后面添0
				WFloat temp2;
				temp2.integer.clear();
				temp2.integer.insert(temp2.integer.end(), temp.begin(), temp.end());
				temp2.trim();
				result = result + temp2;
			}
			iter2++;
		}
		result.tag = ((num1.tag && num2.tag) || (!num1.tag && !num2.tag));

		//由于我们将小数和整数合并在一起,因此下面要把小数点重新添上
		if (size != 0)
		{
			if (size >= result.integer.size())	//说明需要补前导0
			{
				int n = size-result.integer.size();
				for (int i = 0; i <= n; i++)
					result.integer.insert(result.integer.end(), 0);
			}
			result.decimal.clear();
			result.decimal.insert(result.decimal.begin(), result.integer.begin(), result.integer.begin() + size);
			result.integer.erase(result.integer.begin(), result.integer.begin() + size);
		}
	}
	num1 = result;
	num1.trim();
	return num1;
}

这里我们开始用到最初定义的静态变量的,如果有乘数为0,那么直接返回0。
否则我们开始运算。小数整数混杂着运算很复杂,因此我们将二者归并到一起,在乘法的运算过程中相当于使用一个大整数进行,最后再补上小数点即可。
运算的过程容易理解,但是在最后拆分小数和整数时,参考博客的代码是有问题的。考虑乘法运算0.545*0.102,最后的结果是0.0xxx,这会出现一个问题,那就是我们记录的小数点所在位置size,要大于我们运算结果的长度。这是因为我们需要补充前导0,才能正确的区分整数和小数部分。因此可以看到我再最后添加了一个补充前导0的判断语句。

5.4 operator/=

这部分参考博客的少考虑了一些情况,并且计算结果的小数部分错误的多了一个0,经过我的修正暂时没有发现其他问题。

WFloat operator/=(WFloat& num1, const WFloat& num2)	//除等于重载
{
	if (num2 == WFloat::ZERO)
		throw DividedByZeroException();
	if (num1 == WFloat::ZERO)
		return num1;

	WFloat temp_num1 = num1;
	WFloat temp_num2 = num2;
	if (temp_num1.tag == false || temp_num2.tag == false)	//转换成无符号除法来做
	{
		temp_num1.tag = true;
		temp_num2.tag = true;
	}
	
	int Integer_Size = 0;	//整数部分应为几位
	if ((temp_num2.decimal.size() == 1) && (*(temp_num2.decimal.begin()) == 0)) {} //如果除数没有小数部分,不做操作
	else
	{
		//否则把除数和乘数同时扩大,直到除数为整数(只对Integer部分运算)
		int t = temp_num2.decimal.size();
		while (t--)
		{
			temp_num1 = temp_num1 * WFloat::TEN;
			temp_num2 = temp_num2 * WFloat::TEN;
		}
	}
	if (temp_num1 < temp_num2)	//被除数小于除数,应该是0.xxx
	{
		while (temp_num1 < temp_num2)
		{
			temp_num1 *= WFloat::TEN;
			Integer_Size--;
		}
	}
	else
	{
		while (temp_num1 > temp_num2)
		{
			temp_num1.decimal.push_back(*temp_num1.integer.begin());
			temp_num1.integer.erase(temp_num1.integer.begin());
			Integer_Size++;
		}
	}

	int k = ACCURACY;
	WFloat quotient(0);	//商

	while (k--)
	{
		if (temp_num1 < temp_num2)
		{
			temp_num1 = temp_num1 * WFloat::TEN;
			quotient = quotient * WFloat::TEN;
		}
		else
		{
			int i;
			WFloat compare;
			for (i = 1; i <= 10; i++)	//“试商”
			{
				WFloat BF(i);
				compare = temp_num2 * BF;
				if (compare > temp_num1)
					break;
			}
			compare -= temp_num2;
			temp_num1 -= compare;
			WFloat index(i - 1);
			quotient = quotient + index;
		}
	}

	if (Integer_Size < 0)	//如果是小数除以大数,结果为0.xxx
	{
		vector<char> temp(quotient.integer.begin(), quotient.integer.end());
		quotient.integer.clear();
		quotient.integer.push_back(0);	//整数部分为0

		quotient.decimal.clear();
		int count_zero = -Integer_Size;
		//下面先补充前导0
		while (--count_zero)
		{
			quotient.decimal.insert(quotient.decimal.begin(), 0);
		}
		quotient.decimal.insert(quotient.decimal.begin(), temp.begin(), temp.end());
	}
	else
	{
		if (quotient.integer.size() > Integer_Size)
		{
			vector<char> temp(quotient.integer.begin(), quotient.integer.end());

			quotient.integer.clear();	//这里如果不清空会有错误

			quotient.integer.assign(temp.end() - Integer_Size, temp.end());

			quotient.decimal.clear();	//同理需要清空

			quotient.decimal.insert(quotient.decimal.begin(), temp.begin(), temp.end() - Integer_Size);
		}
		else
		{
			//这一部分意义不明,我觉得不会走到这个分支
			int t = Integer_Size - quotient.integer.size();
			while (t--)
			{
				quotient = quotient * WFloat::TEN;
			}
		}
	}
	quotient.tag = ((num1.tag && num2.tag) || (!num1.tag && !num2.tag));
	num1 = quotient;
	num1.trim();
	return num1;
}

说一下参考博客中的问题:
首先是“试商”的部分,商的结果可以是0-9,参考博客中的写法无法取到0和9,这会导致运算结果的不正确。
另外就是没有考虑到小数除以大数的情况,Integer_Size为负数时说明结果为0.xxx,我们应该补充上前导0才能得到正确的结果。
最后,虽然vector提供的assign函数理论上会清空原始数据,但是我实测,如果不手动clear掉原始数据,那么assign之后会报错。
除法的精度由全局变量ACCURACY决定,这里设置的是100,如果真的要用于算数编码,肯定还是不够的。

总结

以无头苍蝇四处乱撞的方式去写代码总是会走无数的岔路,这次按照参考博客中的思路一步一步来,不断的完善它的错误,也是一种很好的锻炼。所以说,你没必要强迫自己写每一行代码,但你应该读懂自己写下的每一行代码。
本次高精度浮点数内容的具体定义与实现代码可见我的giteeWFloat.h头文件,我也提供了测试用的主函数。

  • 5
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值