您的位置:首页 > 其它

高精度4位压缩法原理与实现

2016-01-11 22:18 232 查看
我们都知道 int类型占32bit 可表示范围: [-2147483648,2147483647] long long类型 64bit可表示范围:[-9223372036854775808,9223372036854775807]

int可以完整表达9位数字,long long可以完整表达18位。(完整表达的意思是能表示到该位的任意数字)

当我们想表达到成千上万位的数时,int、long long都不再适合。所以我们便引入高精度的概念。

所谓高精度就是用数组来充当数字的容器。开辟若干个空间,每个单元内存放固定数目的数据。

高精度常用的方法主要有:不压缩法、压缩4位法、和压缩9位的方法。

不压缩法:主要是用char类型开辟的数组,每个元素内存放一位数字。

例如:

2156897546

用普通不压缩方法存储,其数据结构为:

6457986512
注意:此时数组中存放的是数值并不是ASCll对应的字符!之所以倒序存放是为了便于以后进行运算时溢位的情况。

 

压缩4位法:用int类型开辟的数组,每个元素内存放四位数字。

ps:为什么是四位呢?因为int类型能完整表达9位以内的任何数字。而存储四位数字是因为在进行乘法运算时,很可能会存在四位×四位的情况,而其结果不会超过八位。int类型完全可以存储。如果存放四位以上的数字的时候,int不能完整的存放其结果,因而无法正确计算。

例如:

2156897546

用压缩4方法存储,其数据结构为:

7546568921
 特点:自右向左每选取4位存放至数组一个单元内。最后不够的单独放一个空间。(四位内部还是正序的,总体是逆序的)

压缩9位法:与压缩4位法大致相同,区别在于存放的数组是用long long类型开辟的,每个元素内存放9位数字。

例如:

2156897546

用压缩9方法存储,其数据结构为:

15689754621
三种方式归根结底都是进制的转换问题:普通不压缩法相当于十进制,四位压缩法相当于一万进制,九位压缩法相当于十亿进制。

三种方法的时间效率不同:假设两个数进行四则运算。运用普通法存储拥有最多的单位,其次是四位压缩法,最少是九位压缩法。进行加法运算时,两个数组中,以其中一个数组为起点,使其各个单元与另一个数组的各个单元进行相加运算。其时间复杂度为O(n^2)级。因此压缩9位存储法开辟的单元少,所以消耗的时间最少。

在此我们仅此介绍四位压缩法的构造以及乘法与加法计算样例(有可能的话,以后会补齐其他的四则运算=_=)

int StrToNum(const char str[], int num[])//从字符串的最后一位倒序向,int数组正序方向赋值(int数组是倒序的大数)
{
int len=strlen(str),i,j=0;
for(i=len-1;i>2;i-=4)//倒序每4个数字存放一个单位内
{
if(i-3>=0)
num[j++]=(str[i-3]-'0')*1000+(str[i-2]-'0')*100+(str[i-1]-'0')*10+(str[i]-'0');
}
if(i==0)//如果剩余1个数字
num[j++]=str[0]-'0';
else if(i==1)//剩余2个数字
num[j++]=(str[0]-'0')*10+(str[1]-'0');
else if(i==2)//剩余3个数字
num[j++]=(str[0]-'0')*100+(str[1]-'0')*10+(str[2]-'0');
while(j>0&&num[j-1]==0)	//j返回num的长度
j--;
return j;
}


int Add(int num1[],int num2[],int num3[],int len1,int len2,int& num3_begin)//加法  num1,num2是原始数据的数组,num3用来存放结果
{
int i=0,j=len1>len2?len1:len2;			//len1,len2分别代表数组num1,num2的长度,num3_begin返回结果中数值开始的下标。
if(len1==0&&len2==0)		//原始数据是0的情况讨论。  0:num1、num2都是0;   1:num1是0    2:num2是0
return 0;
else if(len1==0)
return 1;
else if(len2==0)
return 2;
else
{
while(i<j)	//循环次数是取len1,和len2中最大的数
{
num3[i]+=num1[i]+num2[i];//相加
if(num3[i]>=10000)		//若数值大于进制进行进位操作
num3[i+1]+=num3[i]/10000,num3[i]%=10000;
i++;
}
if(num3[i]==0)//返回结果中数值开始的下标
num3_begin=i-1;
else
num3_begin=i;
}	return -1;
}
int Multiply(int num1[], int num2[], int num3[], int len1, int len2,int &num3_begin)//乘法    存储在num1,num2中的数是从下标0开始倒序存放的。
{
int i=0,j=0,k=0;
if(len1==0||len2==0)		//num1、num2有一方是0
return 0;
else
{
while(i<len1)
{
k=i;
j=0;
while(j<len2)
{
num3[k]+=num1[i]*num2[j];		//本位原来可能有数字,所以用+=
if(num3[k]>=10000)
num3[k+1]+=num3[k]/10000,num3[k]%=10000;
k++,j++;
}
i++;
}
}
if(num3[k]!=0)		//返回数中最高位不为0的下标
num3_begin=k;
else
num3_begin=k-1;
return 1;
}


  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息