切换到宽版
  • 6547阅读
  • 4回复

什么是高精度运算啊??、谁来帮帮我 [复制链接]

上一主题 下一主题
离线weipengjie
 
只看楼主 倒序阅读 0 发表于: 2006-07-11
从1 到50求阶乘得和
离线stevenjl

只看该作者 1 发表于: 2006-07-11
  1. 阶乘程序:
  2. program jc;
  3. var
  4. m:string;
  5. function jiecheng(m:integer):string;
  6. var
  7. n,s:string;
  8. begin
  9. if m<>1 then
  10. begin
  11. n:=jiecheng(m-1);
  12. end
  13. else
  14. jiecheng:='1';
  15. exit;
  16. end;
  17. <高精度程序段>
  18. end;
  19. begin
  20. read(m)
  21. writeln(jiecheng(m));
  22. end.
  23. 高精度介绍:
  24. 所谓的高精度运算,是指参与运算的数(加数,减数,因子……)范围大大超出了标准数据类型(整型,实型)能表示的范围的运算。例如,求两个200位的数的和。这时,就要用到高精度算法了。在这里,我们先讨论高精度加法。高精度运算主要解决以下三个问题:
  25. 基本方法(如果你已经会了,那就看看优化后的方法)
  26. 1、加数、减数、运算结果的输入和存储
  27. 运算因子超出了整型、实型能表示的范围,肯定不能直接用一个数的形式来表示。在Pascal中,能表示多个数的数据类型有两种:数组和字符串。
  28. (1)数组:每个数组元素存储1位(在优化时,这里是一个重点!),有多少位就需要多少个数组元素;
  29. 用数组表示数的优点:每一位都是数的形式,可以直接加减;运算时非常方便
  30. 用数组表示数的缺点:数组不能直接输入;输入时每两位数之间必须有分隔符,不符合数值的输入习惯;
  31. (2)字符串:字符串的最大长度是255,可以表示255位。
  32. 用字符串表示数的优点:能直接输入输出,输入时,每两位数之间不必分隔符,符合数值的输入习惯;
  33. 用字符串表示数的缺点:字符串中的每一位是一个字符,不能直接进行运算,必须先将它转化为数值再进行运算;运算时非常不方便; (3)因此,综合以上所述,对上面两种数据结构取长补短:用字符串读入数据,用数组存储数据:
  34. var s1,s2:string;
  35. a,b,c:array [1..260] of integer;
  36. i,l,k1,k2:integer;
  37. begin
  38. write('input s1:');readln(s1);
  39. write('input s2:');readln(s2);
  40. {————读入两个数s1,s2,都是字符串类型}
  41. l:=length(s1);{求出s1的长度,也即s1的位数;有关字符串的知识。}
  42. k1:=260;
  43. for i:=l downto 1 do
  44. begin
  45. a[k1]:=ord(s1[i])-48;{将字符转成数值}
  46. k1:=k1-1;
  47. end;
  48. k1:=k1+1;
  49. {————以上将s1中的字符一位一位地转成数值并存在数组a中;低位在后(从第260位开始),高位在前(每存完一位,k1减1)}
  50. 对s2的转化过程和上面一模一样。
  51. 2、运算过程
  52. 在往下看之前,大家先列竖式计算35+86。
  53. 注意的问题:
  54. (1)运算顺序:两个数靠右对齐;从低位向高位运算;先计算低位再计算高位;
  55. (2)运算规则:同一位的两个数相加再加上从低位来的进位,成为该位的和;这个和去掉向高位的进位就成为该位的值;如上例:3+8+1=12,向前一位进1,本位的值是2;可借助MOD、DIV运算完成这一步;
  56. (3)最后一位的进位:如果完成两个数的相加后,进位位值不为0,则应添加一位;
  57. (4)如果两个加数位数不一样多,则按位数多的一个进行计算;
  58. if k1>k2 then k:=k1 else k:=k2;
  59. y:=0;
  60. for i:=260 downto k do
  61. begin
  62. x:=a[i]+b[i]+y;
  63. c[i]:=x mod 10;
  64. y:=x div 10;
  65. end;
  66. if y<>0 then begin k:=k-1;c[k]:=y; end;
  67. 3、结果的输出(这也是优化的一个重点)
  68. 按运算结果的实际位数输出
  69. for i:=k to 260 do write(c[i]);
  70. writeln;
  71. 4、例子:求两个数的加法
  72. program sum;
  73. var s,s1,s2:string;
  74. a,b,c:array [1..260] of integer;
  75. i,l,k1,k2:integer;
  76. begin
  77. write('input s1:');readln(s1);
  78. write('input s2:');readln(s2);
  79. l:=length(s1);
  80. k1:=260;
  81. for i:=l downto 1 do
  82. begin
  83. a[k1]:=ord(s1[i])-48;
  84. k1:=k1-1;
  85. end;
  86. k1:=k1+1;
  87. l:=length(s2);
  88. k2:=260;
  89. for i:=l downto 1 do
  90. begin
  91. b[k2]:=ord(s2[i])-48;
  92. k2:=k2-1;
  93. end;
  94. k2:=k2+1;
  95. if k1>k2 then k:=k2 else k:=k1;
  96. y:=0;
  97. for i:=260 downto k do
  98. begin
  99. x:=a[i]+b[i]+y;
  100. c[i]:=x mod 10;
  101. y:=x div 10;
  102. end;
  103. if y<>0 then begin k:=k-1;c[k]:=y;
  104. end;
  105. for i:=k to 260 do write(c[i]);
  106. writeln;
  107. end.
  108. 优化:
  109. 以上的方法的有明显的缺点:
  110. (1)浪费空间:一个整型变量(-32768~32767)只存放一位(0~9);
  111. (2)浪费时间:一次加减只处理一位;
  112. 针对以上问题,我们做如下优化:一个数组元素存放四位数;(integer的最大范围是32767,5位的话可能导致出界)。具体方法:
  113. l:=length(s1);
  114. k1:=260;
  115. repeat {————有关字符串的知识}
  116. s:=copy(s1,l-3,4);
  117. val(s,a[k1],code);
  118. k1:=k1-1;
  119. s1:=copy(s1,1,l-4);
  120. l:=l-4;
  121. until l<=0;
  122. k1:=k1+1;
  123. 而因为这个改进,算法要相应改变:
  124. (1)运算时:不再逢十进位,而是逢万进位(mod 10000; div 10000);
  125. (2)输出时:最高位直接输出,其余各位,要判断是否足够4位,不足部分要补0;例如:1,23,2345这样三段的数,输出时,应该是100232345而不是1234567。
  126. 改进后的算法:
  127. program sum;
  128. var s1,s2:string;
  129. a,b,c:array [1..260] of integer;
  130. i,l,k1,k2,code:integer;
  131. begin
  132. write('input s1:');readln(s1);
  133. write('input s2:');readln(s2);
  134. l:=length(s1);
  135. k1:=260;
  136. repeat {————有关字符串的知识}
  137. s:=copy(s1,l-3,4);
  138. val(s,a[k1],code);
  139. k1:=k1-1;
  140. s1:=copy(s1,1,l-4);
  141. l:=l-4;
  142. until l<=0;
  143. k1:=k1+1;
  144. l:=length(s2);
  145. k2:=260;
  146. repeat
  147. s:=copy(s2,l-3,4);
  148. val(s,b[k2],code);
  149. k2:=k2-1;
  150. s2:=copy(s2,1,l-4);
  151. l:=l-4;
  152. until l<=0;
  153. k2:=k2+1;
  154. if k1<k2 then k:=k1 else k:=k2;
  155. y:=0;
  156. for i:=260 downto k do
  157. begin
  158. x:=a[i]+b[i]+y;
  159. c[i]:=x mod 10000;
  160. y:=x div 10000;
  161. end;
  162. if y<>0 then begin k:=k-1;c[k]:=y;end;
  163. write(c[k]);
  164. for i:=k+1 to 260 do
  165. begin
  166. ----if c[i]<1000 then write('0');
  167. ----if c[i]<100 then write('0');
  168. ----if c[i]<10 then write('0');
  169. ----write(c[i]);
  170. end;
  171. writeln;
  172. end.
Dream Walker...
离线johnson
只看该作者 2 发表于: 2006-08-17
var
  a       : array[1..50] of byte;  
  i,j,k,l,n : word;  
begin  
  a[1] := 1;  
  for i := 2 to 50 do a[i] := 0;
  l := 1;
  for i := 2 to 50 do begin
    k := 0;
    for j := 1 to l do begin
      k := a[j]*i+k;
      a[j] := k mod 10;
      k := k div 10;
    end;
    while k > 0 do begin
    l := l+1;
    a[l] := k mod 10;
    k := k div 10
    end;
  end;  
  write(i,'! = ');
  for k := l downto 1 do write(a[k]);  
  writeln;    
end.
离线wangvvs
只看该作者 3 发表于: 2006-09-09
我有个问题:‘a[k1]:=ord(s1)-48;’
这个ord不是把一整个串的字符转成数字么?
还有‘-48’是用来干什么的?
离线stevenjl

只看该作者 4 发表于: 2006-09-09
a[k1]:=ord(s1[i])-48;{将字符转成数值}
抱歉,是论坛吃代码了……现在已经修正。
48是“0”的ASCII码
ord('0') = 48,同样的:
ord('1') = 49;
ord('2') = 50;
....
所以,ord('n') -48 = n;
Dream Walker...
快速回复
限100 字节
 
上一个 下一个