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編程語言 |