C语言编程题,求5!+16!+27!,定义函数求n! 用程序流程图表示出算法,代码编写带点注释。

如题所述

如果需要精确计算16和27的阶乘需要编写大整数计算,至少要实现大整数加法,大整数乘以短整数,大整数除以短整数,大整数转换为字符串用于显示结果。当然如果不需要精确计算可以使用浮点数来计算。

#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <ctype.h>



typedef int            BOOL;

typedef unsigned short LINT_B;
typedef unsigned long  LINT_B2;
typedef LINT_B *       LINT;
typedef const LINT_B * CLINT;

#define TRUE           1
#define FALSE          0
#define BASE           0x10000ul
#define BASEDIV2       0x8000ul
#define BASEMINONE     0xFFFFul
#define DIGITLEN       64 // 当 DIGITLEN = 64 时可以实现200以内的阶乘
#define Max(a, b)      ((a) < (b) ? (b) : (a))
#define Rmldzrs(l, h)  do {while(*(--h) == 0); ++h; h = Max(l, h);} while(0);

const int sBitperdgt = sizeof(LINT_B) * 8;

// 复制大数
LINT copy(CLINT f, CLINT l, LINT x)
{
while(f != l) *x++ = *f++;
return x;
}

// 大数是否为0
inline BOOL isZero(CLINT l, CLINT h)
{
Rmldzrs(l, h);
return (l == h) ? TRUE : FALSE;
}

// 调换字符串的顺序
void reverse(char *s)
{
char t;
char *sl = s;
char *sh = sl + strlen(s);
while(sl < sh) {t = *sl; *sl++ = *(--sh) ; *sh = t;}
}

// 交换大数指针
void swapCLINT(CLINT *a, CLINT *b)
{
CLINT t;
t = *a; *a = *b; *b = t;
}

// 加法 C = A + B
LINT add(CLINT al, CLINT ah, CLINT bl, CLINT bh, LINT cl)
{
LINT_B2 carry = (LINT_B2)0;
LINT ch = cl;
if((ah - al) < (bh - bl)) swapCLINT(&al, &bl), swapCLINT(&ah, &bh); // 保证A的长度大于或等于B
// 两个数相加
while (bl < bh)
*ch++ = (LINT_B)(carry = (LINT_B2)*al++ + (LINT_B2)*bl++ + (LINT_B2)(LINT_B)(carry >> sBitperdgt));
// 处理 A 比 B 多出的长度
while (al < ah)
{
if(carry >= BASE) *ch++ = (LINT_B)(carry = (LINT_B2)*al++ + (LINT_B2)(LINT_B)(carry >> sBitperdgt));
else *ch++ = *al++;
}
// 处理进位
if(carry & BASE) *ch++ = (LINT_B)1;
return ch;
}

// 短乘法 C = A * b
LINT umul(CLINT al, CLINT ah, LINT_B b, LINT cl)
{
LINT     ch;
LINT_B2 *pc;
CLINT    pa;
LINT_B2  carry, bv;

if(b == 0 || isZero(al, ah)) {if(cl) *cl = 0; return cl;}
if(ah - al == 1) // A 的长度只有一个数字
{
pc  = (LINT_B2 *)cl;
*pc = (LINT_B2)*al * (LINT_B2)b;
ch = cl + 2;
Rmldzrs(cl, ch);
return ch;
}
ch = cl;
pa = al;
carry = (LINT_B2)0, bv = (LINT_B2)b;
// 循环计算
while(pa < ah) *ch++ = (LINT_B)(carry = bv * (LINT_B2)*pa++ + (LINT_B2)(LINT_B)(carry >> sBitperdgt));
// 处理进位
*ch++ = (LINT_B)(carry >> sBitperdgt);
Rmldzrs(cl, ch);
return ch;
}

// 短除 A = b * C + d
// cl 或 d 可以是空指针
LINT udiv(CLINT al, CLINT ah, LINT_B b, LINT cl, LINT d)
{
int lenA, lenC;
LINT    bufC = NULL, ch, pch;
LINT_B  c;
CLINT   pah;
LINT_B2 rdach, bv, rv;

// 处理特殊情况
if(b == 0)
{
printf("带余短除出现除以0错误");
if(d)  *d  = 0;
if(cl) *cl = 0; 
return cl;
}
lenA = ah - al;
if(lenA == 0) {if(d) *d = 0; if(cl) *cl = 0; return cl;} // 被除数等于0,结果商等于0,余数等于0
if(lenA == 1) // 被除数也只有1位
{
if(*al < b) {if(d) *d = *al; if(cl) *cl = 0;} // 被除数小于除数,商等于0,余数等于被除数
else
{
c = *al / b;
if(cl) *cl++ = c;
if(d)  *d    = *al - c * b;
}
return cl;
}

lenC = lenA - 1; // 计算长度
if(cl == NULL)
{
bufC = (LINT)malloc((lenC + 1) * sizeof(LINT_B)); // 申请内存,保证cl不为NULL
if(bufC == NULL)
{
printf("带余短除申请临时内存发生错误!\n");
if(d) *d = 0;
return NULL;
}
cl = bufC;
}
ch = cl + lenC;

// 开始计算
pah = ah - 1;
pch = ch;
bv  = b, rv = 0;
while(al <= pah)
{
*pch = (LINT_B)((rdach = ((rv << sBitperdgt) + (LINT_B2)*pah--)) / bv);
rv   = (rdach - bv * (LINT_B2)*pch--);
}
if(d) *d = (LINT_B)rv;
if(bufC)
{
free(bufC);
return NULL;
}
return (*ch == 0) ? ch : ++ch;
}

// 大整数变成数字串
const char * LInt2Str(char * o, CLINT l, CLINT h, LINT_B base, BOOL uppercase)
{
const char * sVecUpper = "0123456789ABCDEF";
const char * sVecLower = "0123456789abcdef", *Vec;
char *po;

LINT_B x, t[DIGITLEN], ii[DIGITLEN];
LINT   th, tl, il, ih;
CLINT  xl, xh;
BOOL   flag = TRUE;

po  = o;
il  = ii;
ih  = copy(l, h, il);
Rmldzrs(il, ih);
if(isZero(il, ih))
{
*o++ = '0';
*o++ = 0;
return po;
}

Vec = uppercase ? sVecUpper : sVecLower;
xl  = &x;
xh  = xl + 1;
th  = tl = t;

switch(base)
{
case 2: case 8: case 10: case 16: break;
default: base = 10;
}

while(1)
{
if(flag)
{
th   = udiv(il, ih, base, tl, &x);
flag = FALSE;
}
else
{
ih   = udiv(tl, th, base, il, &x);
flag = TRUE;
}
*o++ = Vec[x];
if(th == tl || ih == il) break;
}
*o++ = 0;
reverse(po);
return po;
}

// 阶乘,可以精确计算200以内的阶乘,定义更大的DIGITLEN可以实现更大数字的阶乘
LINT jiecheng(LINT l, LINT_B x)
{
LINT h = l + 1, tl, th;
LINT_B i = 1, t[DIGITLEN];
BOOL   flag = TRUE;
*l = 1;
th = tl = t;

while(i <= x)
{
if(flag) {flag = FALSE; th = umul( l,  h, i++, tl);}
else     {flag =  TRUE; h  = umul(tl, th, i++,  l);}
}
if(!flag) h = copy(tl, th, l);
return h;
}

int main()
{
char buf[512];
LINT_B a[DIGITLEN], b[DIGITLEN], c[DIGITLEN], i = 5;
LINT al, ah, bl, bh, cl, ch;
ah = al = a, bh = bl = b, ch = cl = c;
while(i < 30)
{
printf("%d! ", i);
ch  = add(al, ah, bl, jiecheng(bl, i), cl);
ah  = copy(cl, ch, al);
i  += 11;
if(i < 30) printf("+ ");
}
printf("= %s\n", LInt2Str(buf, al, ah, 10, FALSE));

return 0;
}

温馨提示:答案为网友推荐,仅供参考
第1个回答  2016-07-06
#include<stdio.h>
double fac(int n) //计算n的阶乘
{double x=1.0;
int i;
for(i=2;i<=n;i++)
x*=i;
return x;
}
int main()
{printf("%.0lf\n",fac(5)+fac(16)+fac(27));
return 0;
}本回答被提问者采纳
第2个回答  2016-07-06
void main(void)
{
    uint sum;
    sum = f_JieCheng(n);
}
uint f_JieCheng(uint n)
{
    uint temp = 1;
    for(i=1;i<(n+1);i++)
    {
        temp *= i;  
    }
    return temp;
}

相关了解……

你可能感兴趣的内容

本站内容来自于网友发表,不代表本站立场,仅表示其个人看法,不对其真实性、正确性、有效性作任何的担保
相关事宜请发邮件给我们
© 非常风气网