特化的大数类:只支持与无符号四字整数的乘法运算

在这里插入图片描述
效率:对于一万的阶乘,可以瞬间出结果。

#include<cstdio>
#include <cassert>
//特化的计算。若乘0,则会出错。
//采用int_max进制。恰好可以直接分解为16进制。
//检验了几十的阶乘,结果是正确的。
//缺点:内存有连续依赖。
class mutiee
{
	static const int maxlen = 1000000;//100万位的intmax进制,可以容纳2^(3200万)的数字,也就是一千多万位十进制。这对应于一个正常情况下不会算到的数。这是一个足够大的空间。
	unsigned long long* nummem;
	//mem[i]的高32位与下一个单元的低32位实际为同义词。(或者说,nummem[i]实际表示nummem[i]*unitmax^i,而nummem[i]的容量则是ullmax~uintmax^2。)
	//即每个单元的高32位都是计算缓冲区。这使得每次乘法计算只用实现一次调整。当然,只有使用特定的计算顺序才能保证正确。
	int maxat;//最高有数字位。
	mutiee& correct(void)//调整函数。在这个特化实现中,*=结合correct不会导致出错。
	{
		assert(maxat < maxlen - 1);
		for (int i = 0; i <= maxat; i++)
		{
			nummem[i + 1] += nummem[i] >> 32;//高位加到上边去。
			nummem[i] &= 0xffffffff;//高位清除。
		}
		assert(nummem[maxat + 1] <= 0xffffffff);//最高位+1处不应出现进位的情况。
		if (nummem[maxat + 1])maxat += 1;//每次乘法至多会导致进一位。
		return *this;
	}
public:
	mutiee(void)
	{
		nummem = new unsigned long long[maxlen]();
		maxat = 0,nummem[0] = 1;
	}
	~mutiee(void) { delete[]nummem; }
	mutiee& clear(void)
	{
		for (int i = 0; i <= maxat; i++)
			nummem[i] = 0;
		maxat = 0,nummem[0] = 1;
		return *this;
	}
	mutiee& operator*=(unsigned num)
	{
		assert(num && maxat < maxlen - 1);//否则会导致调整函数出错。
		assert(num && maxat < maxlen - 1);//否则会导致调整函数出错。
		for (int j = 0; j <= maxat; j++)//只有一位运算的话,高位乘不影响低位。
			nummem[j] *= num;//在此处,原来的nummem[j]总会是一个小于umax的数。
		//可以大胆地这么写而不会导致溢出。考虑(0xffffffff*0xffffffff),(0xffffffff*0xffffffff)的进位。可以看到低位的缓冲区(高32位)截入(加到)高位上时,不会导致高位溢出。
		//即:[(2^32-1)*(2^32-1)]+{[(2^32-1)*(2^32-1)]/(2^32)}小于(2^64-1),因而不会引发截断。(%2^32留在原位。)
		return this->correct();
	}
	//没有专门的输出优化。
	//与16进制顺序直接匹配。
	mutiee& become_fact(int num)//利用特殊的循环展开:代数式循环展开。对于0,也可以呈现出正确的结果。
	{
		this->clear();
		int i = 1;
		while (i < 65536 && i <= num - 1)//二阶的代数循环展开。
		{
			(*this) *= (i * (i + 1));//可以节省一般的。之所以要小于65536,是为了避免这里的整数溢出。
			i += 2;
		}
		while (i <= num)(*this) *= i++;
		return *this;
		//进一步优化:将一串数字流【因式分解(简单的,例如偶数分解)并重组为一串接近intmax的乘法流】再进行累乘。即使在大于65536的地方,也可以实现大于一阶,小于二阶的循环展开。
	}
	void print(void)
	{
		printf("ox_%llx", nummem[maxat]);//表示的是一个大端十六进制数。
		for (int j = maxat-1; j >= 0; j--)
		{
			printf("%.8llx", nummem[j]);
		}
		putchar('\n');
	}
};
int main()
{
	mutiee ee;//1。
	/*
	ee.clear();
	for (int i = 1; i <= 30; i++) {
		(ee *= i).print();
	}
	*/
	
	ee.clear();
	for (int i = 1; i <= 10000; i++)ee *= i;
	ee.print();//可以不到一秒出结果。

	//ee.clear().become_fact(65536).print();//3秒出结果。
	
	/*//50万-1的阶乘:
	ee.clear();
	for (int i = 1; i < 500000; i++){
		ee *= i;
	}
	freopen("fac(499999).txt", "wb", stdout);
	ee.print();
	*///release64下用了几分钟的时间。
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值