- 大鱼炖火锅
-
Logo 语言因为是少儿的学习语言,阶乘方法要复杂一些,而且时间较慢,下面是低精度、高精度、统计位数的阶乘算法:
TO DJDJC :N ;低精度阶乘
MAKE S 1;累乘器开始的值是1
FOR I 1 :N[MAKE S :S * :I]
(PR :N [!=] :S)
END
TO GJDJC :N;高精度阶乘
IF :N>=1000 THEN PR 请输入不大于999的数! STOP
MAKE PRECISION 6;计算显示位数设定为六位
MAKE A ARRAY 860;定义数组空间0-859组
ASET :A 1 1;乘法数组第1空间赋值为1
FOR I 2 859[ASET :A :I 0] ;其他数组空间赋值为0
FOR I 1 :N [JC :I];调用阶乘过程
MAKE K 0;数组空间是0的标记
MAKE Z 0;总共有多少组数字的标记
MAKE WS 0;累加总共有多少位的计数器
TYPE :N TYPE[!=];从高位到低位显示计算结果
FOR M 1 859[XXS 860-:M]
PR[ ] TYPE[这是一个]TYPE :WS TYPE[位数]PR[]
END
TO JC :I;计算阶乘的过程
FOR J 1 858[CF :I :J] ;对所有数组空间逐一计算乘法
FOR J 1 858[CLJW :J];处理乘法过程中的进位
END
TO CF :I :J ;计算乘法的过程
MAKE ZJ AGET :A :J
MAKE ZJ :ZJ * :I;I是阶乘中需要累乘的数
ASET :A :J :ZJ
END
TO CLJW :J;处理进位的过程
MAKE X AGET :A :J
IF :X<1000 THEN GO XXX;处理没有进位的数组
MAKE JINWEI INT (:X / 1000);截取小于1000的尾数
MAKE WEISHU :X - :JINWEI * 1000 ;截取进位的数字
ASET :A :J :WEISHU;存储尾数
MAKE Y AGET :A :J+1
MAKE Y :Y + :JINWEI
ASET :A :J+1 :Y;向上进位
LABEL XXX
END
TO XXS :P;显示计算结果的过程
MAKE NN AGET :A :P
IF (AND :NN=0 :K=0) THEN[GO END_]ELSE[MAKE K 1 MAKE Z :Z+1] ;避开无效数组
IF :Z=1 THEN MAKE WS :WS+(COUNT :NN) GO UP;计算头一个有效数组的位数
IF :Z>1 THEN MAKE WS :WS+3;累计数值的总位数
IF :NN < 10 THEN TYPE [0];填充空位0
IF :NN < 100 THEN TYPE [0]
LABEL UP
TYPE :NN
LABEL END_ ;越过开头的空数组
END
TO JC :N ;求解任意数的阶乘是多少位数
MAKE S 0;先赋值位数为0
FOR I 1 :N[MAKE S :S+LOG10 :I]
TYPE[:S=]PR :S
END 在 C 语言中,使用循环语句可以很方便的求出阶乘的值,下面介绍一个很简单的阶乘例子。(因为网上多数是比较麻烦的方法)
【计算出“ 1!+ 2!+ 3!+ …… + 10!”的值是多少?】 #include<stdio.h>int main(){ int x; long j=1,sum=0; for(x=1;x<=10;x++) { j*=x; sum+=j; } printf(1!+2!+...+10!=%ld ,sum); return 0;}/*结果:4037913*/ #include<iostream>using namespace std;long long f(int n){ long long e=1; if(n>0) e=n*f(n-1); cout<<n<<!=<<e<<endl; return e;}int main(){ int m=20; f(m); return 0;}以上使用 C++ 11 标准
也可以利用积分求浮点数阶乘: #include<cstdio>#include<cmath>double s;const double e=exp(1.0);double F(double t){ return pow(t,s)*pow(e,-t);}double simpson(double a,double b){ double c=a+(b-a)/2; return (F(a)+4*F(c)+F(b))*(b-a)/6;}double asr(double a,double b,double eps,double A){ double c=a+(b-a)/2; double L=simpson(a,c),R=simpson(c,b); if(fabs(L+R-A)<=15*eps) return L+R+(L+R-A)/15.0; return asr(a,c,eps/2,L)+asr(c,b,eps/2,R);}double asr(double a,double b,double eps){ return asr(a,b,eps,simpson(a,b));}int main(){ scanf(%lf,&s); printf(%lf ,asr(0,1e2,1e-10)); return 0;} "本代码使用了斯特林(Stirling)逼近的方式计算较大数值的阶乘和有小数位数的数值的阶乘。详细过程请参见《用Stirling逼近近似计算阶乘的探讨与应用》一书。
"根据验算,结果与Windows 7的计算器结果有出入,但是还能忍受。特别是可以计算较大数值的阶乘,例如 36000,Windows计算器溢出。当然无法考证我的结果与真实结果的差距,没有比较……^.^
Private Sub 计算按钮_Click(sender As Object, e As EventArgs) Handles 计算按钮.Click Dim 阶乘数 As Decimal = CDec(InputBox(请输入一个数值,将得到它的阶乘结果。)) " 因为要计算比较大的数值,因此将较小的整数值按照阶乘的定义来计算得到准确值,但 VBULong整数的最大范围能计算到 20的阶乘,21将溢出;较大的数值或者小数按照 Stirling 逼近的方式计算。 If 阶乘数 >= 0 And 阶乘数 <= 20 And Fix(阶乘数) = 阶乘数 Then MsgBox(阶乘数 & 的阶乘结果是: & 小阶乘(CInt(阶乘数))) Else MsgBox(阶乘数 & 的阶乘结果是: & 大数阶乘(CDbl(阶乘数)) & E & 大数阶乘指数(阶乘数)) End If End Sub
"这是小数值阶乘的过程,标准计算方式,结果精确。
Private Function 小阶乘(阶乘数 As Integer) As ULong If 阶乘数 = 0 Or 阶乘数 = 1 Then"如果数值是 0或者 1,直接返回 1。 Return 1 Else 小阶乘 = 1 For 阶乘次数 As Integer = 1 To CInt(阶乘数) 小阶乘 *= CULng(阶乘次数) Next Return 小阶乘 End If End Function
""" <summary> """ 这个过程用 Stirling 逼近的方式计算较大数值和有小数点的值的阶乘结果的前 15 位。详细过程见《用 Stirling 逼近近似计算阶乘的探讨与应用》一书。 """ </summary> """ <param name=阶乘数></param> """ <returns></returns> """ <remarks></remarks> Private Function 大数阶乘(阶乘数 As Double) As Double Dim X As Double = 0.5 * Math.Log(2 * 阶乘数 * Math.PI) / Math.Log(10) + 阶乘数 * Math.Log(阶乘数 / Math.Exp(1)) / Math.Log(10) Dim XDouble As Double = X - Math.Truncate(X) Dim Y As Double = Math.Exp(XDouble * Math.Log(10)) Dim Z As Double = Math.Exp(1 / 12 / 阶乘数 - 1 / 360 / 阶乘数 / 阶乘数) Return Y * Z End Function
""" <summary> """ 这个过程用 Stirling 逼近的方式计算较大数值和有小数点的值的阶乘结果的小数点位数。详细过程见《用 Stirling 逼近近似计算阶乘的探讨与应用》一书。 """ </summary> """ <param name=阶乘数></param> """ <returns></returns> """ <remarks></remarks>
Private Function 大数阶乘指数(阶乘数 As Double) As ULong Dim X As Double = 2 * Math.PI * 阶乘数 Dim Y As Double = 0.5 * Math.Log10(X) Dim A As Double = 阶乘数 * Math.Log10(阶乘数 / Math.E) Return CULng(Math.Truncate(Y + A)) End Function var a:array[1..10000] of integer; b,c,d,t,x:integer;begin readln (x); if (x<0) then begin writeln ("error!"); readln; halt; end; for t:=1 to 10000 do a[t]:=0; d:=1; a[1]:=1; for c:=1 to x do {一直乘到x} begin t:=1; b:=0; {t:第几位数 b:进位 d:总位数} repeat a[t]:=a[t]*c+b; {数组每位均乘上c,同时加上进位} b:=a[t] div 10; {分离出进位} if a[t]>=10 then if (t=d) then d:=d+1; {假如最后一位乘时有} {进位,则总位数加1} a[t]:=a[t] mod 10; inc (t); {数组下一位} until (t>d); {直到乘完数组的每一位数字} end; for t:=d downto 1 do write (a[t]); {输出}end.