存档

‘编程相关’ 分类的存档

任意位数的高精度阶乘算法 C语言版

2008年10月3日 Slyar 7 条评论

文章作者:Slyar 文章来源:Slyar Home (www.slyar.com) 转载请注明,谢谢合作。

今天就研究这个"任意位数的高精度阶乘算法"了,通过和大三的一个学长讨论,最终写出了这个还比较满意的算法:

1、利用C语言的动态数组来达到任意位数,但是首先需要知道数组的长度,也就是N!有多少位。

2、求出N!的结果有多少位,这个公式我就不证明了,是log10(1)+log10(2)+···+log10(n) 取整加1。

3、使用万进制来进位,减少空间的利用,提高运算速度。

4、高精度阶乘算法。

5、因为使用万进制,所以输出各位的时候需要补0。

6、最后发现如果N<1000的话结果的首位会出现0,因此单独输出第一位保证首位没有0。

代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
 
/* 求N!的位数公式 log10(1)+log10(2)+···+log10(n) 取整加1  */
int wei(int n)
{
	int i;
	double sum=0;
	for(i=1;i<=n;i++) sum+=log10((double)i);
	/* 以万为进制,一位可以表示4个数,减少存储空间 */
	return (int)((sum+1)/4+1);
}
 
/* 高精度阶乘核心 */
int main()
{
	int i,j,n,jinwei,weishu=1,temp;
	unsigned int *x;
	scanf("%d",&n);
	/* 依据阶乘位数申请动态数组 */
	x=(unsigned int*) malloc(wei(n)*sizeof(int));
	x[0]=1;
	for(i=2;i<=n;i++)
	{
		jinwei=0;
		for(j=1;j<=weishu;j++)
		{
			temp=x[j-1]*i+jinwei;
			if (temp>=1)
			{
				/* 以万为进制,提高运算速度 */
				x[j-1]=temp%10000;
				jinwei=temp/10000;
			}
		}
		while(jinwei)
		{
			weishu++;
			x[weishu-1]=jinwei%10000;
			jinwei/=10000;
		}
	}
	/* 先输出第一个数,防止首位出现0 */
	printf("%d",x[weishu-1]);
	/* 输出其余的数,因为万进制,需要补0 */
	for(j=weishu-2;j>=0;j--) printf("%04d",x[j]);
	/* 释放申请的内存 */
	free(x);
	system("pause");
	return 0;
}
分类: 编程相关 标签:

C/C++ 不检查数组下标是否越界

2008年10月1日 Slyar 2 条评论

文章作者:Slyar 文章来源:Slyar Home (www.slyar.com) 转载请注明,谢谢合作。

哎,以前都是把下标规定好的,也就没注意这个问题,今天发现这个问题还是在做Vijos的时候。我提交一题的代码时才发现我的数组长度居然少打了一个0,也就是小了10倍。。。我正痛心疾首可怜我的AC率的时候,却发现评测机给出了“Accepted”。。。怀疑、欣喜、不解。。。问Google。。。

原来C/C++是不检查数组下标是否越界的?奇怪的事情。。。不检查下标是否越界可以有效提高程序运行的效率,因为如果你检查,那么编译器必须在生成的目标代码中加入额外的代码用于程序运行时检测下标是否越界,这就会导致程序的运行速度下降,所以为了程序的运行效率,C/C++才不检查下标是否越界。

自己写了一段检测程序测试这个问题,发现如果数组下标越界了,那么它会自动接着那块内存往后写。想了一下明白了,以前说不允许数组下标越界,并不是因为界外没有存储空间,而是因为界外的内容是未知的。也就是说如果界外的空间暂时没有被利用,那么我们可以占用那块内存,但是如果之前界外的内存已经存放了东西,那么我们越界过去就会覆盖那块内存,导致错误的产生。。。

这样就明白了,所以我们还是需要好好规划数组的下标滴。。。

分类: 编程相关 标签:

C语言中 i++ 和 ++i 有什么区别?

2008年9月28日 Slyar 20 条评论

文章作者:Slyar 文章来源:Slyar Home (www.slyar.com) 转载请注明,谢谢合作。

今天有同学问C语言中for循环里那个 i++ 和 ++i 是否有区别,我告诉他在for循环中是没有区别的,现在具体说一下 i++ 和 ++i 的区别。

我们先用while语句写一下 for(i=1;i<10;i++)

int i=0;
while (i<10){
printf("www.slyar.com");
i++;
}

用while语句写一下 for(i=1;i<10;++i)

int i=0;
while (i<10){
printf("www.slyar.com");
++i;
}

可以看到,最后i的值都是10,所以在for循环里,i++ 和 ++i 是没有区别的,那么区别在哪里呢?

现在我们再看一段程序:

#include<stdio.h>
int main(){
int i,x;

i=1;
x=1;
x=i++; //这里先让X变成i的值1,然后i加1
printf("%d ",x);

i=1;
x=1;
x=++i; //这里先让i加1,然后让X变成i的值2
printf("%d ",x);

system("pause");
return 0;
}

试着运行一下这段程序,发现结果是 1 2 ,这就是 i++ 和 ++i 的区别了:

i++  :先引用后增加

++i  :先增加后引用

具体是什么意思呢?就是

i++  :先在i所在的表达式中使用i的当前值,后让i加1

++i  :让i先加1,然后在i所在的表达式中使用i的新值

我想这样说大家就应该明白了。。。

分类: 编程相关 标签:

研究C语言的参数执行顺序

2008年8月23日 Slyar 9 条评论

文章作者:Slyar 文章来源:Slyar Home (www.slyar.com) 转载请注明,谢谢合作。

今天看以前做过的题,发现一段代码,引起了我的研究兴趣。。。

#include <stdio.h>
main()
{
int i=9;
printf("%d %d %d\n",++i,i,--i);
printf("%d %d %d\n",i++,i,i--);
}

这段程序的结果是什么?

可能光给上面那个还真容易迷糊,不过两个都给那就简单了,结果是:

9 8 8
8 8 9

因为书上写着:printf的参数是右集合,也就是从右往左运行,可是为什么呢?

研究了一下,发现关键就在一个字:

计算机当然没有我们聪明了,更没有Slyar聪明了,所以他肯定不会知道看书要从左往右看。当然了,你可以说计算机还停留在古代,因为古人都是从右往左看书滴。。。嘎嘎,就因为这样,所以计算机不知道怎么来传递这个参数,这时就要引入一种数据结构来传递参数了,这个数据结构就是----栈!

关于栈,我们很清楚了,规则是后进先出。。。所以当函数被调用时,参数被压栈,然后调用函数在堆栈中进行计算。。。当我们输出参数的时候是从左向右(--->)输出的,输出时先从栈顶取数据,那么栈顶的数据一定是最后放进去的,这也就是为什么参数要从右向左(<---)压栈并求值的原因。。。

唔,当然也不是所有的参数都这样啦,有的参数是靠寄存器存取的。。。不管那么多了~

分类: 编程相关 标签: ,

ShellExecute 在新窗口中打开网页

2008年7月5日 Slyar 2 条评论

文章作者:Slyar 文章来源:Slyar Home (www.slyar.com) 转载请注明,谢谢合作。

ShellExecute是我们常用的一个API,可以运行程序,打开网页。

ShellExecute(NULL, "open", "http://www.slyar.com/", NULL,NULL,SW_SHOWMAXIMIZED);

这样可以打开一个网页,但不是在新IE中打开,改成下面方式时就可以在一个新的IE中打开网页了

ShellExecute(NULL, "open", "IEXPLORE", "http://www.slyar.com/", NULL,SW_SHOWMAXIMIZED);

分类: 编程相关 标签: ,
bnuep:0801010047