回 帖 发 新 帖 刷新版面

主题:高精度阶乘的程序出问题了

{$N+}
TYPE
   {Integer type declare}
   I_ = INTEGER;
   SI_ = SHORTINT;
   LI_ = LONGINT;
   BI_ = BYTE;
   WI_ = WORD;
   {Real type declare}
   R_ = REAL;
   SR_ = SINGLE;
   DR_ = DOUBLE;
   ER_ = EXTENDED;
   CR_ = COMP;
   {Other type declare}
   C_ = CHAR;
   B_ = BOOLEAN;
   S_ = STRING;
FUNCTION S_TO_I(s: S_): LI_;
VAR i: LI_; k: I_;
BEGIN
    VAL(s, i, k);
    S_TO_I := i;
END;
FUNCTION XN(x, y: SI_): LI_;
VAR i: SI_; m: LI_;
BEGIN
    m := x;
    FOR i:=2 TO y DO m := m * x;
    XN := m;
END;
FUNCTION I_TO_S(x: WI_): S_;
VAR s: S_;
BEGIN
    STR(x, s);
    I_TO_S := s;
END;
FUNCTION gjdmult(a: S_; b: LI_): S_;
VAR
  l: SI_;
  x: I_;
  v, p: LI_;
  s: S_;
BEGIN
    l := 9 - LENGTH(I_TO_S(b));
    IF l < 1 THEN l := 1;
    p := XN(10, l);
    v := 0;
    s := '';
    x := LENGTH(a) - l + 1;
    WHILE x >= 1 DO BEGIN
        v := S_TO_I(COPY(a, x, l)) * b + v;
        s := COPY(I_TO_S(v), LENGTH(I_TO_S(v)) - l + 1, l) + s;
        v := v DIV p;
        x := x - l;
    END;
    IF x > 1 - l THEN v := S_TO_I(COPY(a, 1, x + l - 1)) * b + v;
    IF v > 0 THEN s := I_TO_S(v) + s;
    gjdmult := s;
END;
VAR
   i, j, n, k: I_;
   s, s0: S_;
BEGIN
    READLN(n);
    s := '1'; k := 0;
    i := n MOD 2 + 1;
    WHILE i <= n DO BEGIN
        s := gjdmult(s, i * i + i);
        i := i + 2;
    END;
    WRITELN(s);
    READLN;
END.
这是我编的高精度阶乘的程序,可是只能算到8!,9!就不行了,请问各位大虾,是思路错了还是程序出了细节问题,谢谢。

[color=800000]我是新手![/color]

回复列表 (共9个回复)

沙发

看得头都晕了

LZ在编pascal时不要把BASIC的习惯都带来了

用变量就直接定义,不要再重新定义多一遍,这样可读性很低

另,高精度最好用数组,用字符串不方便操作,而且很容易出错

板凳

用数组还可以一位保存多位提高效率..呵呵

PS : C++写惯了...看PASCAL越来越不习惯了....

3 楼

对吗?

100!=933262154439441526816992388562667004907159682643816214685929638952175999932299608941463976156518286253697920827223758251185210916864000000000000000000000000

200!=7886578673647905035523632139321850622951359776871732632947425332443594499634032920304284011984623904177212138919638830257642790242637105061926624952829931116285727076331723739698894392244562145166424025403329186413122742829485327752424075739032403212574055795686602260319041703240623517008587961789222227896237037374720000000000000000000000000000000000000000000000000


program test_fact;

var a0,a1,a2 : array [ 0 .. 1023 ] of word;

procedure mul;
var i0,i1,i2 : dword; d0,d1,d2 : byte; carry : boolean;
begin
  for i1 := 1 to a1[0] do
  begin
    d1 := a1[i1]; i0 := i1;
    for i2 := 1 to a2[0] do
    begin
      d2 := a2[i2];
      d0 := d1 * d2;
      a0[i0] := a0[i0] + d0 mod 10;
      i0 := i0 + 1;
      a0[i0] := a0[i0] + d0 div 10;
    end;
    if a0[i0] <> 0 then
      a0[0] := i0 else a0[0] := i0 - 1;
    carry := false;
    for i0 := 1 to a0[0] do
    begin
      if carry then inc(a0[i0]);
      if a0[i0] >= 10 then begin
        a0[i0] := a0[i0] - 10;
        carry := true;
      end else carry := false;
    end;
    if carry then begin
      a0[i0+1] := 1; a0[0] := i0+1;
    end;
  end;
end;

procedure ntoa1 ( n : dword );
var i1 : dword;
begin
  i1 := 0;
  while n > 0 do begin
    i1 := i1 + 1;
    a1[i1] := n mod 10;
    n := n div 10;
  end;
  a1[0] := i1;
end;

procedure a0toa2;
var i1 : dword;
begin
  for i1 := 1 to a0[0] do
    a2[i1] := a0[i1];
  a2[0] := a0[0];
  for i1 := 0 to 1023 do
    a0[i1] := 0;
end;

procedure fact ( n : dword );
var i1 : dword;
begin
  for i1 := 2 to n do
  begin
    ntoa1(i1);
    mul;
    a0toa2;
    if i1 = 146 then
  end;
  for i1 := a2[0] downto 1 do
    write(a2[i1]);
  writeln;
end;


begin
  a2[0] := 1;
  a2[1] := 1;
  //fact(100);
  fact(200);
  readln;
end.

4 楼

楼上的,dword类型是什么?

我用的是TP7.0,不能识别dword。

5 楼

Dword是32位无符号整型数据,可以在FreePascal中使用

6 楼

const z=10000;
var
   a:array[0..z+1]of integer;
   n,j,i,k:longint;
begin
  assign(input,'fac.in');
  assign(output,'fac.out');
  reset(input);
  rewrite(output);
  readln(n);
  begin
    a[1]:=1;
    for i:=1 to n do
      begin
        for j:=1 to z do
          a[j]:=a[j]*i;
        for k:=1 to z do
          begin
            a[k+1]:=a[k+1]+a[k]div 10;
            a[k]:=a[k]mod 10;
          end;
     end;
    i:=z;k:=0;
    repeat
      if a[i]<>0 then k:=1;
      i:=i-1;
    until k=1;
    k:=0;
    for j:=i+1 downto 1 do
      write(a[j]);
    end;
  writeln;
  close(input);
  close(output);
end.
这个求阶乘的程序更简便

7 楼

program sdkj;
var a:array[1..1000]of longint;
var i,w,n:longint;
procedure aaa(k:longint);
var i,x:longint;
begin
for i:=1 to w do begin
a[i]:=a[i]*k+x;
x:=a[i] div 10;
a[i]:=a[i] mod 10;
end;
while x>0 do begin
w:=w+1;
a[w]:=x mod 10;
x:=x div 10;
end;
end;
begin
readln(n);
a[1]:=1;
w:=1;
for i:=1 to n do aaa(i);
for i:=n downto 1 do write(a[i]);
end.

8 楼

uses crt;
var i,j,c,n:integer;
    a:array[0..60000]of integer;
begin
  clrscr;
  readln(n);
  writeln(n,'! =');
  a[1]:=1;
  a[0]:=1;
  c:=0;
  for i:=2 to n do begin
    for j:=1 to a[0] do begin
      a[j]:=a[j]*i+c;
      c:=a[j] div 10;
      a[j]:=a[j] mod 10
    end;
    while (c>0) do begin
      inc(a[0]);
      a[a[0]]:=c;
      c:=c div 10;
      a[a[0]]:=a[a[0]] mod 10
    end
  end;
  for i:=a[0] downto 1 do write(a[i]);
  writeln;
  writeln('Length=',a[0]);
  readln
end.

9 楼


回8楼幽灵密码

原程序计算较大n时会发生a[j]*i+c 溢出(TP7.0下)

略作修改(数组改为Byte)

[font=宋体]
uses crt;
var j,n:integer;
   i,c,d,Na:LongInt;
   a:array[0..32000] of byte;
begin
  clrscr;
  write('N(1..9000)='); readln(n);
  if n>9000 then n:=9000;
  writeln(n,'! =');
  Na:=1;
  a[1]:=1;
  c:=0;
  for i:=2 to n do begin
    for j:=1 to Na do begin
      d:=a[j]*i+c;
      c:=d div 10;
      a[j]:=d-c*10;
    end;
    while (c>0) do begin
      inc(Na);
      a[Na]:=c mod 10;
      c:=c div 10;
    end
  end;
  for i:=Na downto 1 do write(a[i]);
  writeln;
  writeln('Length=',Na);
  readln
end.
[/font]

我来回复

您尚未登录,请登录后再回复。点此登录或注册