算法:如何储存大数据 (精确计算)(第二篇)

引入问题:求2+22+222+2222+…+222…222(n个2)+…的值(精确计算)

	当n取很大时,该如何储存每个加数以及他们的和?
	考虑是用字符数组还是数值数组储存每个加数,
	每个数组元素存一位数还是多位数?

如果不考虑n取很大时,程序其实很简单,有几种方法,既可以用循环,也可以用递归。

#include<stdio.h>
void main()
{
    long a[256],s;
    int n,i;
    printf("请输入n:");
    scanf("%d",&n);
    a[1]=2;
    s=2;
    printf("2");
    for(i=2;i<=n;i++)
    {
        a[i]=10*a[i-1]+a[1];
        printf("+%ld",a[i]);
        s=s+a[i];
    }
    printf("=%ld",s);
}

这里采用虽然是long类型,其实256个长度没有必要,因为当n取10的时候,就已经溢出了,即使是long long类型,我试过,当n取20时,也溢出了

下面是各种类型的取值范围:
unsigned   int   0~4294967295   
int   2147483648~2147483647 
unsigned long 0~4294967295
long   2147483648~2147483647
long long的最大值:9223372036854775807
long long的最小值:-9223372036854775808
unsigned long long的最大值:18446744073709551615

__int64的最大值:9223372036854775807
__int64的最小值:-9223372036854775808
unsigned __int64的最大值:18446744073709551615
其实int64位也就是long long

那如果考虑n取很大的值时,应该怎么保存呢
这里采用的是用long类型数组,每个数组元素储存6位数
直接上代码:

#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:4996)
//编译环境是vs2019,如果不是,可以忽略上面两行
#include<stdio.h>

void main()
{
	long a[100], s[256] = { 0 },b,d;	//a数组储存加数,s数组储存结果
								//进位变量d,中间结果b
	int n, i, j, x, m = 1;	//m记录当前的位数
	int k = 2;
	long p;	//p为中间变量
	printf("请输入n:");
	scanf("%d", &n);
	s[1] = 2;
	a[1] = 2;
	d = 0;
	printf("2");
	for (i = 2; i <= n; i++)
	{
		if (a[k - 1] * 10 > 1000000)
		{
			p = (a[k - 1] * 10 + 2) / 1000000;
			a[k] = p;
			k++;
		}
		else
		{
			a[k - 1] = a[k - 1] * 10 + 2;
		}
		printf("+");
		for (x = 1; x <= k - 1; x++)
		{
			printf("%ld", a[x]);
		}

		if (k - 1 > m)
		{
			m++;
		}

		for (j = 1; j <= m; j++)
		{
			
			if (j <= (k - 1))
			{
				b = a[j] + s[j] + d;
				s[j] = b % 1000000;
				d = b / 1000000;
			}
			else
			{
				b = s[j] + d;
				s[j] = b % 1000000;
				d = b / 1000000;
			}
		}
		if (d != 0)
		{
			s[j] = d;
			m++;
		}
	}
	printf("\n=");
	//for (x = m; x >=1; x--)
	//{
	//	printf("%ld",s[x]);
	//}
	printf("%ld",s[m]);
	for (x = m; x >= 2; x--)
	{
		if (s[x] > 0)
		{
			if (s[x - 1] < 100000)	//如果是5位数
			{
				printf("0");
				if (s[x - 1] < 10000)
				{
					printf("0");
					if (s[x - 1] < 1000)
					{
						printf("0");
						if (s[x - 1] < 100)
						{
							printf("0");
							if (s[x - 1] < 10)
							{
								printf("0");
							}
						}
					}
				}
				printf("%ld", s[x - 1]);
			}
			else			//若6位数全占满了
			{
				printf("%ld", s[x - 1]);
			}
			
		}
	}
	
	puts("");
	printf("m=%d", m);
	//for (x = 1; x <= k - 1; x++)
	//{
	//	printf("%ld\n", a[x]);
	//}
}

这里在写代码的时候其实有个问题,那就是累加计算的和,与下一次相加的加数,到底哪一个比较大,其实就是数列A(n+1)-A(n)=2*10^(n+1),求出Sn?A(n+1),当n取前面几个,很显然是A(n+1)大,但是当n取很大呢,我没有仔细算,如果不管n取多大,A(n+1)始终是大于Sn的,那程序中间有一部分可以简化。具体没有算。如果有人知道的话,欢迎指出。

后面输出的时候,也有个问题,不能直接for循环,倒着输出s[]。因为若当s[]
记录的和为123456 001234时,这样输出的是123456 1234,中间的0没有输出
来,因为这是当成一个六位数保存,所以输出的格式要用if语句判断是几位数,
然后补0
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值