標籤:

c語言我想求21!, 但是long int超出了範圍,怎麼寫?


如果僅僅是限於21!,可以用64位無符號整數,把10跳過,這樣64位無符號數可以表示,最後列印在輸出個0。

#include &
void main()
{
unsigned long long r;
r=21ll*20*19*18*17*16*15*14*13*12*11*9*8*7*6*5*4*3*2;
printf("%lld0",r);
}

結果是:51090942171709440000


如果需要精確數值,需要手動實現高精度演算法,用字元串來表示數字,這樣就可以存儲並計算大於long int範圍的數值。理論上只要用字元串保存的數值不超過內存的容量都能進行計算。

如果只需要近似值,可以用Stirlings approximation公式

[公式]


能不能用一個struct結構體來裝載 long int,然後用malloc來申請足夠的空間(純屬個人想法)


第一,可以使用GMP大數運算庫;

第二,可以自己編寫階乘演算法:

#include "stdafx.h"

#include "math.h"

#define MAX_N 10000000.00 //能夠計算的最大的n值,如果你想計算更大的數對數,可將其改為更大的值

#define MAX_MANTISSA (1e308/MAX_N) //最大尾數

typedef unsigned short WORD;

struct bigNum

{

double n1; //表示尾數部分

int n2; //表示階碼部分

};

short GetExpBase2(double a) // 獲得 a 的階碼
{

// 按照IEEE 754浮點數格式,取得階碼,僅僅適用於Intel 系列 cpu

WORD *pWord=(WORD *)(a)+3;

WORD rank = ( (*pWord 0x7fff) &>&>4 );

return (short)(rank-0x3ff);

}

double GetMantissa(double a) // 獲得 a 的 尾數

{

// 按照IEEE 754浮點數格式,取得尾數,僅僅適用於Intel 系列 cpu

WORD *pWord=(WORD *)(a)+3;

*pWord = 0x800f; //清除階碼

*pWord |= 0x3ff0; //重置階碼

return a;

}

void calcFac(struct bigNum *p,int n)

{

int i;

p-&>n1=1;

p-&>n2=0;

for (i=1;i&<=n;i++) { if (p-&>n1&>=MAX_MANTISSA) //繼續相乘可能溢出,調整之

{

p-&>n2 += GetExpBase2(p-&>n1);

p-&>n1 = GetMantissa(p-&>n1);

}

p-&>n1 *=(double)i;

}

}

void printfResult(struct bigNum *p,char buff[])

{

double logx=log10(p-&>n1)+ p-&>n2 * log10(2);//求計算結果的常用對數

int logxN=(int)(floor(logx)); //logx的整數部分

sprintf(buff,"%.14fe%d",pow(10,logx-logxN),logxN);//轉化為科學計演算法形式的字元串

}

int main(int argc, char* argv[])

{

struct bigNum r;

char buff[32];

int n;

printf("n=?");

scanf("%d",n);

calcFac(r,n); //計算n的階乘

printfResult(r,buff); //將結果轉化一個字元串

printf("%d!=%s/n",n,buff);

return 0;

}


最簡的方式,可以重寫一下乘法的方式嘛,彙編能處理的長度更短,不過依舊可以辦到,所以辦法還是很多的,我用數組的方式寫了一下,想算多少算多少,算1000的階乘也可以呀,僅供參考,代碼架構不好勿噴

#define MAX_LENGTH 1000

#include &

int main(){
int sum[MAX_LENGTH];
int i, j;
int flag;
int temp;
int count;
flag = 0;
printf("?!:");
scanf("%d", count);
for (i = 0; i &< MAX_LENGTH; i++){ sum[i] = 0; } sum[0] = 1; for (i = 1; i &<= count; i++){ for (j = 0; j &< MAX_LENGTH; j++){ temp = flag; flag = (sum[j] * i + flag) / 10; sum[j] = (sum[j] * i + temp) % 10; } } flag = 0; for (i = MAX_LENGTH - 1; i &> -1; i--){
if (flag == 0 sum[i] == 0){
continue;
}else{
flag = 1;
printf("%d", sum[i]);
}
}
return 0;
}

其中define的是數組的長度,至於算誰的階乘,用scanf輸入~


20的階層沒超吧??先把20的階層算出來。。然後除以100。。。最後乘個21。。。然後後面再補兩個0。。。或者20的階層算出來。。然後直接筆算啊。。。


這種可以用字元去模擬,利用小學學的乘法知識用字元模擬乘法,就可以精確的求出21!了。


數組,別說21,就是31都給你存儲了


推薦閱讀:

TAG:C編程語言 |