bigbig.red 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836
  1. % BIGBIG.RED - Vector based BIGNUM package with INUM operations
  2. % M. L. Griss & B Morrison
  3. % 25 June 1982.
  4. %
  5. % Revision log:
  6. % 20 Dec:
  7. % MLG, changed TrimBigNUM to TrimBigNum1 in BhardDivide
  8. % 14 Dec:
  9. % Changed by MLG to put LOAD and IMPORTS in BUILD file
  10. % A. C . Norman - adjstments to many routines!
  11. % in particular corrections to BHardDivide (case D6 utterly wrong),
  12. % and adjustments to BExpt (for performance) and all logical
  13. % operators (for treatment of negative inputs);
  14. % 31 August 1982:
  15. % Copyright (C) 1982, A. C. Norman, B. Morrison, M. Griss
  16. % ---------------------------------------------------------------
  17. % -----------------------
  18. % A bignum will be a VECTOR of Bigits: (digits in base BigBase):
  19. % [BIGPOS b1 ... bn] or [BIGNEG b1 ... bn]. BigZero is thus [BIGPOS]
  20. % All numbers are positive, with BIGNEG as 0 element to indicate negatives.
  21. Fluid '(BBase!* BBits!* LogicalBits!* WordHi!* WordLow!* Digit2Letter!*
  22. FloatHi!* FloatLow!* SysHi!* SysLo!* Carry!* OutputBase!*);
  23. % --------------------------------------------------------------------------
  24. % --------------------------------------------------------------------------
  25. % Support functions:
  26. %
  27. % U, V, V1, V2 for arguments are Bignums. Other arguments are usually
  28. % fix/i-nums.
  29. lisp procedure setbits x;
  30. %
  31. % This function sets the globals for big bignum package.
  32. % "x" should be total # of bits per word.
  33. <<BBits!*:=iquotient(isub1 x,2); % Total number of bits per word used.
  34. BBase!*:=TwoPower BBits!*; % "Beta", where n=A0 + A1*beta + A2*(beta^2)...
  35. WordHi!*:=BNum Isub1 BBase!*; % Highest value of Ai
  36. WordLow!*:=BMinus WordHi!*; % Lowest value of Ai
  37. LogicalBits!*:=ISub1 BBase!*; % Used in LAnd,Lor, etc.
  38. SysHi!*:=bsub1 btwopower isub1 x; % Largest representable Syslisp integer.
  39. SysLo!*:=BMinus BAdd1 SysHi!*; % Smallest representable Syslisp integer.
  40. BBase!*>>;
  41. lisp procedure BignumP (V);
  42. VectorP V and ((V[0] eq 'BIGPOS) or (V[0] eq 'BIGNEG));
  43. lisp procedure NonBigNumError(V,L);
  44. StdError BldMsg(" Expect a BIGNUM in %r, given %p%n",L,V);
  45. lisp procedure BSize V;
  46. (BignumP V and UpbV V) or 0;
  47. lisp procedure GtPOS N; % Creates a positive Bignum with N "Bigits".
  48. Begin Scalar B;
  49. B:=MkVect N;
  50. IPutV(B,0,'BIGPOS);
  51. Return B;
  52. End;
  53. lisp procedure GtNeg N; % Creates a negative Bignum with N "Bigits".
  54. Begin Scalar B;
  55. B:=MkVect N;
  56. IPutV(B,0,'BIGNEG);
  57. Return B;
  58. End;
  59. lisp procedure TrimBigNum V3; % Truncate trailing 0.
  60. If Not BignumP V3 then NonBigNumError(V3,'TrimBigNum)
  61. else TrimBigNum1(V3,BSize V3);
  62. lisp procedure TrimBigNum1(V3,L3);
  63. % V3 is a bignum and L3 is the position in it of the highest
  64. % possible non-zero digit. Truncate V3 to remove leading zeros,
  65. % and if this leaves V3 totally zero make its sign positive;
  66. Begin
  67. While IGreaterP(L3,0) and IZeroP IGetV(V3,L3) do L3:=ISub1 L3;
  68. If IZerop Bsize TruncateVector(V3,L3) then IPutV(V3,0,'BIGPOS);
  69. return V3;
  70. end;
  71. lisp procedure big2sys U;
  72. if BLessP(U, SysLo!*) or BGreaterP(U, SysHi!*) then
  73. Error(99,list(U," is too large to be a Syslisp integer for BIG2SYS"))
  74. else begin scalar L,Sn,res,I;
  75. L:=BSize U;
  76. if IZeroP L then return 0;
  77. Sn:=BMinusP U;
  78. res:=IGetV(U,L);
  79. I:=ISub1 L;
  80. while not IZeroP I do <<res:=ITimes2(res, bbase!*);
  81. res:=IPlus2(res, IGetV(U,I));
  82. I:=ISub1 I>>;
  83. if Sn then Res:=IMinus Res;
  84. return Res;
  85. end;
  86. lisp procedure TwoPower N; %fix/i-num 2**n
  87. 2**n;
  88. lisp procedure BTwoPower N; % gives 2**n; n is fix/i-num; result BigNum
  89. if not (fixp N or BignumP N) then NonIntegerError(N, 'BTwoPower)
  90. else begin scalar quot, rem, V;
  91. if bignump N then n:=big2sys n;
  92. quot:=Quotient(N,Bbits!*);
  93. rem:=Remainder(N,Bbits!*);
  94. V:=GtPOS(IAdd1 quot);
  95. IFor i:=1:quot do IPutV(v,i,0);
  96. IPutV(V,IAdd1 quot,twopower rem);
  97. return TrimBigNum1(V,IAdd1 quot);
  98. end;
  99. lisp procedure BZeroP V1;
  100. IZerop BSize V1 and not BMinusP V1;
  101. lisp procedure BOneP V1;
  102. Not BMinusP V1 and IOneP (BSize V1) and IOneP IGetV(V1,1);
  103. lisp procedure BAbs V1;
  104. if BMinusP V1 then BMinus V1 else V1;
  105. lisp procedure BMax(V1,V2);
  106. if BGreaterP(V2,V1) then V2 else V1;
  107. lisp procedure BMin(V1,V2);
  108. if BLessP(V2,V1) then V2 else V1;
  109. lisp procedure BExpt(V1,N); % V1 is Bignum, N is fix/i-num
  110. if not fixp N then NonIntegerError(N,'BEXPT)
  111. else if IZeroP N then int2B 1
  112. else if IOneP N then V1
  113. else if IMinusP N then BQuotient(int2B 1,BExpt(V1,IMinus N))
  114. else begin scalar V2;
  115. V2 := BExpt(V1,IQuotient(N,2));
  116. if IZeroP IRemainder(N,2) then return BTimes2(V2,V2)
  117. else return BTimes2(BTimes2(V2,V1),V2)
  118. end;
  119. % ---------------------------------------
  120. % Logical Operations
  121. %
  122. % All take Bignum arguments
  123. lisp procedure BLOr(V1,V2);
  124. % The main body of the OR code is only obeyed when both arguments
  125. % are positive, and so the result will be positive;
  126. if BMinusp V1 or BMinusp V2 then BLnot BLand(BLnot V1,BLnot V2)
  127. else begin scalar L1,L2,L3,V3;
  128. L1:=BSize V1;
  129. L2:=BSize V2;
  130. IF L2>L1 then <<L3:=L2; L2:=L1;L1:=L3;
  131. V3:=V2; V2:=V1;V1:=V3>>;
  132. V3:=GtPOS L1;
  133. IFor I:=1:L2 do IPutV(V3,I,ILor(IGetV(V1,I),IGetV(V2,I)));
  134. IFor I:=(IAdd1 L2):L1 do IPutV(V3,i,IGetV(V1,I));
  135. Return V3
  136. end;
  137. lisp procedure BLXor(V1,V2);
  138. % negative arguments are coped with using the identity
  139. % LXor(a,b) = LNot LXor(Lnot a,b) = LNor LXor(a,Lnot b);
  140. begin scalar L1,L2,L3,V3,S;
  141. if BMinusp V1 then << V1 := BLnot V1; S := t >>;
  142. if BMinusp V2 then << V2 := BLnot V2; S := not S >>;
  143. L1:=BSize V1;
  144. L2:=BSize V2;
  145. IF L2>L1 then <<L3:=L2; L2:=L1;L1:=L3;
  146. V3:=V2; V2:=V1;V1:=V3>>;
  147. V3:=GtPOS L1;
  148. IFor I:=1:L2 do IPutV(V3,I,ILXor(IGetV(V1,I),IGetV(V2,I)));
  149. IFor I:=(IAdd1 L2):L1 do IPutV(V3,i,IGetV(V1,I));
  150. V1:=TrimBigNum1(V3,L1);
  151. if S then V1:=BLnot V1;
  152. return V1
  153. end;
  154. % Not Used Currently:
  155. %
  156. % lisp Procedure BLDiff(V1,V2);
  157. % ***** STILL NEEDS ADJUSTING WRT -VE ARGS *****
  158. % begin scalar V3,L1,L2;
  159. % L1:=BSize V1;
  160. % L2:=BSize V2;
  161. % V3:=GtPOS(max(L1,L2));
  162. % IFor i:=1:min(L1,L2) do
  163. % IPutV(V3,i,ILAnd(IGetV(V1,i),ILXor(LogicalBits!*,IGetV(V2,i))));
  164. % if IGreaterP(L1,L2) then IFor i:=(IAdd1 L2):L1 do IPutV(V3,i,IGetV(V1,i));
  165. % if IGreaterP(L2,L1) then IFor i:=(IAdd1 L1):L2 do IPutV(V3,i,0);
  166. % return TrimBigNum1(V3,max(L1,L2));
  167. % end;
  168. lisp procedure BLAnd(V1,V2);
  169. % If both args are -ve the result will be too. Otherwise result will
  170. % be positive;
  171. if BMinusp V1 and BMinusp V2 then BLnot BLor(BLnot V1,BLnot v2)
  172. else begin scalar L1,L2,L3,V3;
  173. L1:=BSize V1;
  174. L2:=BSize V2;
  175. L3:=Min(L1,L2);
  176. V3:=GtPOS L3;
  177. if BMinusp V1 then
  178. IFor I:=1:L3 do IPutV(V3,I,ILand(ILXor(Logicalbits!*,IGetV(V1,I)),
  179. IGetV(V2,I)))
  180. else if BMinusp V2 then
  181. IFor I:=1:L3 do IPutV(V3,I,ILand(IGetV(V1,I),
  182. ILXor(Logicalbits!*,IGetV(V2,I))))
  183. else IFor I:=1:L3 do IPutV(V3,I,ILand(IGetV(V1,I),IGetV(V2,I)));
  184. return TrimBigNum1(V3,L3);
  185. End;
  186. lisp procedure BLNot(V1);
  187. BMinus BSmallAdd(V1,1);
  188. lisp procedure BLShift(V1,V2);
  189. % This seems a grimly inefficient way of doing things given that
  190. % the representation of big numbers uses a base that is a power of 2.
  191. % However it will do for now;
  192. if BMinusP V2 then BQuotient(V1, BTwoPower BMinus V2)
  193. else BTimes2(V1, BTwoPower V2);
  194. % -----------------------------------------
  195. % Arithmetic Functions:
  196. %
  197. % U, V, V1, V2 are Bignum arguments.
  198. lisp procedure BMinus V1; % Negates V1.
  199. if BZeroP V1 then V1
  200. else begin scalar L1,V2;
  201. L1:=BSize V1;
  202. if BMinusP V1 then V2 := GtPOS L1
  203. else V2 := GtNEG L1;
  204. IFor I:=1:L1 do IPutV(V2,I,IGetV(V1,I));
  205. return V2;
  206. end;
  207. % Returns V1 if V1 is strictly less than 0, NIL otherwise.
  208. %
  209. lisp procedure BMinusP V1;
  210. if (IGetV(V1,0) eq 'BIGNEG) then V1 else NIL;
  211. % To provide a conveninent ADD with CARRY.
  212. lisp procedure AddCarry A;
  213. begin scalar S;
  214. S:=IPlus2(A,Carry!*);
  215. if IGeq(S,BBase!*) then <<Carry!*:= 1; S:=IDifference(S,BBase!*)>>
  216. else Carry!*:=0;
  217. return S;
  218. end;
  219. lisp procedure BPlus2(V1,V2);
  220. begin scalar Sn1,Sn2;
  221. Sn1:=BMinusP V1;
  222. Sn2:=BMinusP V2;
  223. if Sn1 and Not Sn2 then return BDifference2(V2,BMinus V1,Nil);
  224. if Sn2 and Not Sn1 then return BDifference2(V1,BMinus V2,Nil);
  225. return BPlusA2(V1,V2,Sn1);
  226. end;
  227. lisp procedure BPlusA2(V1,V2,Sn1); % Plus with signs pre-checked and
  228. begin scalar L1,L2,L3,V3,temp; % identical.
  229. L1:=BSize V1;
  230. L2:=BSize V2;
  231. If IGreaterP(L2,L1) then <<L3:=L2; L2:=L1;L1:=L3;
  232. V3:=V2; V2:=V1;V1:=V3>>;
  233. L3:=IAdd1 L1;
  234. If Sn1 then V3:=GtNeg L3
  235. else V3:=GtPOS L3;
  236. Carry!*:=0;
  237. IFor I:=1:L2 do <<temp:=IPlus2(IGetV(V1,I),IGetV(V2,I));
  238. IPutV(V3,I,AddCarry temp)>>;
  239. temp:=IAdd1 L2;
  240. IFor I:=temp:L1 do IPutV(V3,I,AddCarry IGetV(V1,I));
  241. IPutV(V3,L3,Carry!*); % Carry Out
  242. Return TrimBigNum1(V3,L3);
  243. end;
  244. lisp procedure BDifference(V1,V2);
  245. if BZeroP V2 then V1
  246. else if BZeroP V1 then BMinus V2
  247. else begin scalar Sn1,Sn2;
  248. Sn1:=BMinusP V1;
  249. Sn2:=BMinusP V2;
  250. if (Sn1 and Not Sn2) or (Sn2 and Not Sn1)
  251. then return BPlusA2(V1,BMinus V2,Sn1);
  252. return BDifference2(V1,V2,Sn1);
  253. end;
  254. lisp procedure SubCarry A;
  255. begin scalar S;
  256. S:=IDifference(A,Carry!*);
  257. if ILessP(S,0) then <<Carry!*:=1; S:=IPlus2(BBase!*,S)>> else Carry!*:=0;
  258. return S;
  259. end;
  260. Lisp procedure BDifference2(V1,V2,Sn1); % Signs pre-checked and identical.
  261. begin scalar i,L1,L2,L3,V3;
  262. L1:=BSize V1;
  263. L2:=BSize V2;
  264. if IGreaterP(L2,L1) then <<L3:=L1;L1:=L2;L2:=L3;
  265. V3:=V1;V1:=V2;V2:=V3; Sn1:=not Sn1>>
  266. else if L1 Eq L2 then <<i:=L1;
  267. while (IGetV(V2,i) Eq IGetV(V1,i) and IGreaterP(i,1))
  268. do i:=ISub1 i;
  269. if IGreaterP(IGetV(V2,i),IGetV(V1,i))
  270. then <<L3:=L1;L1:=L2;L2:=L3;
  271. V3:=V1;V1:=V2;V2:=V3;Sn1:=not Sn1>> >>;
  272. if Sn1 then V3:=GtNEG L1
  273. else V3:=GtPOS L1;
  274. carry!*:=0;
  275. IFor I:=1:L2 do IPutV(V3,I,SubCarry IDifference(IGetV(V1,I),IGetV(V2,I)));
  276. IFor I:=(IAdd1 L2):L1 do IPutV(V3,I,SubCarry IGetV(V1,I));
  277. return TrimBigNum1(V3,L1);
  278. end;
  279. lisp procedure BTimes2(V1,V2);
  280. begin scalar L1,L2,L3,Sn1,Sn2,V3;
  281. L1:=BSize V1;
  282. L2:=BSize V2;
  283. if IGreaterP(L2,L1)
  284. then <<V3:=V1; V1:=V2; V2:=V3; % If V1 is larger, will be fewer
  285. L3:=L1; L1:=L2; L2:=L3>>; % iterations of BDigitTimes2.
  286. L3:=IPlus2(L1,L2);
  287. Sn1:=BMinusP V1;
  288. Sn2:=BMinusP V2;
  289. If (Sn1 and Sn2) or not(Sn1 or Sn2) then V3:=GtPOS L3 else V3:=GtNEG L3;
  290. IFor I:=1:L3 do IPutV(V3,I,0);
  291. IFor I:=1:L2 do BDigitTimes2(V1,IGetV(V2,I),L1,I,V3);
  292. return TrimBigNum1(V3,L3);
  293. end;
  294. Lisp procedure BDigitTimes2(V1,V2,L1,I,V3);
  295. % V1 is a bignum, V2 a fixnum, L1=BSize L1, I=position of V2 in a bignum,
  296. % and V3 is bignum receiving result. I affects where in V3 the result of
  297. % a calculation goes; the relationship is that positions I:I+(L1-1)
  298. % of V3 receive the products of V2 and positions 1:L1 of V1.
  299. % V3 is changed as a side effect here.
  300. begin scalar J,carry,temp1,temp2;
  301. if zerop V2 then return V3
  302. else <<
  303. carry:=0;
  304. IFor H:=1:L1 do <<
  305. temp1:=ITimes2(IGetV(V1,H),V2);
  306. temp2:=IPlus2(H,ISub1 I);
  307. J:=IPlus2(IPlus2(temp1,IGetV(V3,temp2)),carry);
  308. IPutV(V3,temp2,IRemainder(J,BBase!*));
  309. carry:=IQuotient(J,BBase!*)>>;
  310. IPutV(V3,IPlus2(L1,I),carry)>>; % carry should be < BBase!* here
  311. return V3;
  312. end;
  313. Lisp procedure BSmallTimes2(V1,C); % V1 is a BigNum, C a fixnum.
  314. % Assume C positive, ignore sign(V1)
  315. % also assume V1 neq 0.
  316. if ZeroP C then return GtPOS 0 % Only used from BHardDivide, BReadAdd.
  317. else begin scalar J,carry,L1,L2,L3,V3;
  318. L1:=BSize V1;
  319. L2:=IPlus2(IQuotient(C,BBase!*),L1);
  320. L3:=IAdd1 L2;
  321. V3:=GtPOS L3;
  322. carry:=0;
  323. IFor H:=1:L1 do <<
  324. J:=IPlus2(ITimes2(IGetV(V1,H),C),carry);
  325. IPutV(V3,H,IRemainder(J,BBase!*));
  326. carry:=IQuotient(J,BBase!*)>>;
  327. IFor H:=(IAdd1 L1):L3 do <<
  328. IPutV(V3,H,IRemainder(J:=carry,BBase!*));
  329. carry:=IQuotient(J,BBase!*)>>;
  330. return TrimBigNum1(V3,L3);
  331. end;
  332. lisp procedure BQuotient(V1,V2);
  333. car BDivide(V1,V2);
  334. lisp procedure BRemainder(V1,V2);
  335. cdr BDivide(V1,V2);
  336. % BDivide returns a dotted pair, (Q . R). Q is the quotient and R is
  337. % the remainder. Both are bignums. R is of the same sign as V1.
  338. %;
  339. smacro procedure BSimpleQuotient(V1,L1,C,SnC);
  340. car BSimpleDivide(V1,L1,C,SnC);
  341. smacro procedure BSimpleRemainder(V1,L1,C,SnC);
  342. cdr BSimpleDivide(V1,L1,C,SnC);
  343. lisp procedure BDivide(V1,V2);
  344. begin scalar L1,L2,Q,R,V3;
  345. L2:=BSize V2;
  346. If IZerop L2 then error(99, "Attempt to divide by 0 in BDIVIDE");
  347. L1:=BSize V1;
  348. If ILessP(L1,L2) or (L1 Eq L2 and ILessP(IGetV(V1,L1),IGetV(V2,L2)))
  349. % This also takes care of case
  350. then return (GtPOS 0 . V1); % when V1=0.
  351. if IOnep L2 then return BSimpleDivide(V1,L1,IGetV(V2,1),BMinusP V2);
  352. return BHardDivide(V1,L1,V2,L2);
  353. end;
  354. % C is a fixnum (inum?); V1 is a bignum and L1 is its length.
  355. % SnC is T if C (which is positive) should be considered negative.
  356. % Returns quotient . remainder; each is a bignum.
  357. %
  358. lisp procedure BSimpleDivide(V1,L1,C,SnC);
  359. begin scalar I,P,R,RR,Sn1,V2;
  360. Sn1:=BMinusP V1;
  361. if (Sn1 and SnC) or not(Sn1 or SnC) then V2:=GtPOS L1 else V2:=GtNEG L1;
  362. R:=0;
  363. I:=L1;
  364. While not IZeroP I do <<P:=IPlus2(ITimes2(R,BBase!*),IGetV(V1,I));
  365. % Overflow.
  366. IPutV(V2,I,IQuotient(P, C));
  367. R:=IRemainder(P, C);
  368. I:=ISub1 I>>;
  369. If Sn1 then RR:=GtNeg 1 else RR:=GtPOS 1;
  370. IPutV(RR,1,R);
  371. return (TrimBigNum1(V2,L1) . TrimBigNum1(RR,1));
  372. end;
  373. lisp procedure BHardDivide(U,Lu,V,Lv);
  374. % This is an algorithm taken from Knuth.
  375. begin scalar U1,V1,A,D,LCV,LCV1,f,f2,J,K,Lq,carry,temp,
  376. LL,M,N,N1,P,Q,QBar,SnU,SnV,U2;
  377. N:=Lv;
  378. N1:=IAdd1 N;
  379. M:=IDifference(Lu,Lv);
  380. Lq:=IAdd1 M;
  381. % Deal with signs of inputs;
  382. SnU:=BMinusP U;
  383. SnV:=BMinusp V; % Note that these are not extra-boolean, i.e.
  384. % for positive numbers MBinusP returns nil, for
  385. % negative it returns its argument. Thus the
  386. % test (SnU=SnV) does not reliably compare the signs of
  387. % U and V;
  388. if SnU then if SnV then Q := GtPOS Lq else Q := GtNEG Lq
  389. else if SnV then Q := GtNEG Lq else Q := GtPOS Lq;
  390. U1 := GtPOS IAdd1 Lu; % U is ALWAYS stored as if one digit longer;
  391. % Compute a scale factor to normalize the long division;
  392. D:=IQuotient(BBase!*,IAdd1 IGetV(V,Lv));
  393. % Now, at the same time, I remove the sign information from U and V
  394. % and scale them so that the leading coefficeint in V is fairly large;
  395. carry := 0;
  396. IFor i:=1:Lu do <<
  397. temp := IPlus2(ITimes2(IGetV(U,I),D),carry);
  398. IPutV(U1,I,IRemainder(temp,BBase!*));
  399. carry := IQuotient(temp,BBase!*) >>;
  400. Lu := IAdd1 Lu;
  401. IPutV(U1,Lu,carry);
  402. V1:=BSmallTimes2(V,D); % So far all variables contain safe values,
  403. % i.e. numbers < BBase!*;
  404. IPutV(V1,0,'BIGPOS);
  405. if ILessp(Lv,2) then NonBigNumError(V,'BHARDDIVIDE); % To be safe;
  406. LCV := IGetV(V1,Lv);
  407. LCV1 := IGetv(V1,ISub1 Lv); % Top two digits of the scaled V accessed once
  408. % here outside the main loop;
  409. % Now perform the main long division loop;
  410. IFor I:=0:M do <<
  411. J:=IDifference(Lu,I); % J>K; working on U1[K:J]
  412. K:=IDifference(J,N1); % in this loop.
  413. A:=IGetV(U1,J);
  414. P := IPlus2(ITimes2(A,BBase!*),IGetv(U1,Isub1 J));
  415. % N.B. P is up to 30 bits long. Take care! ;
  416. if A Eq LCV then QBar := ISub1 BBase!*
  417. else QBar := Iquotient(P,LCV); % approximate next digit;
  418. f:=ITimes2(QBar,LCV1);
  419. f2:=IPlus2(ITimes2(IDifference(P,ITimes2(QBar,LCV)),BBase!*),
  420. IGetV(U1,IDifference(J,2)));
  421. while IGreaterP(f,f2) do << % Correct most overshoots in Qbar;
  422. QBar:=ISub1 QBar;
  423. f:=IDifference(f,LCV1);;
  424. f2:=IPlus2(f2,ITimes2(LCV,BBase!*)) >>;
  425. carry := 0; % Ready to subtract QBar*V1 from U1;
  426. IFor L:=1:N do <<
  427. temp := IPlus2(
  428. Idifference(
  429. IGetV(U1,IPlus2(K,L)),
  430. ITimes2(QBar,IGetV(V1,L))),
  431. carry);
  432. carry := IQuotient(temp,BBase!*);
  433. temp := IRemainder(temp,BBase!*);
  434. if IMinusp temp then <<
  435. carry := ISub1 carry;
  436. temp := IPlus2(temp,BBase!*) >>;
  437. IPutV(U1,IPlus2(K,L),temp) >>;
  438. % Now propagate borrows up as far as they go;
  439. LL := IPlus2(K,N);
  440. while (not IZeroP carry) and ILessp(LL,J) do <<
  441. LL := IAdd1 LL;
  442. temp := IPlus2(IGetV(U1,LL),carry);
  443. carry := IQuotient(temp,BBase!*);
  444. temp := IRemainder(temp,BBase!*);
  445. if IMinusP temp then <<
  446. carry := ISub1 carry;
  447. temp := IPlus2(temp,BBase!*) >>;
  448. IPutV(U1,LL,temp) >>;
  449. if not IZerop carry then <<
  450. % QBar was still wrong - correction step needed.
  451. % This should not happen very often;
  452. QBar := ISub1 QBar;
  453. % Add V1 back into U1;
  454. carry := 0;
  455. IFor L := 1:N do <<
  456. carry := IPlus2(
  457. IPlus2(IGetV(U1,Iplus2(K,L)),
  458. IGetV(V1,L)),
  459. carry);
  460. IPutV(U1,IPlus2(K,L),IRemainder(carry,BBase!*));
  461. carry := IQuotient(carry,BBase!*) >>;
  462. LL := IPlus2(K,N);
  463. while ILessp(LL,J) do <<
  464. LL := IAdd1 LL;
  465. carry := IPlus2(IGetv(U1,LL),carry);
  466. IPutV(U1,LL,IRemainder(carry,BBase!*));
  467. carry := IQuotient(carry,BBase!*) >> >>;
  468. IPutV(Q,IDifference(Lq,I),QBar)
  469. >>; % End of main loop;
  470. U1 := TrimBigNum1(U1,IDifference(Lu,M));
  471. f := 0; f2 := 0; % Clean up potentially wild values;
  472. if not BZeroP U1 then <<
  473. % Unnormalize the remainder by dividing by D
  474. if SnU then IPutV(U1,0,'BIGNEG);
  475. if not IOnep D then <<
  476. Lu := BSize U1;
  477. carry := 0;
  478. IFor L:=Lu step -1 until 1 do <<
  479. P := IPlus2(ITimes2(carry,BBase!*),IGetV(U1,L));
  480. IPutv(U1,L,IQuotient(P,D));
  481. carry := IRemainder(P,D) >>;
  482. P := 0;
  483. if not IZeroP carry then BHardBug("remainder when unscaling",
  484. U,V,TrimBigNum1(U1,Lu),TrimBigNum1(Q,Lq));
  485. U1 := TrimBigNum1(U1,Lu) >> >>;
  486. Q := TrimBigNum1(Q,Lq); % In case leading digit happened to be zero;
  487. P := 0; % flush out a 30 bit number;
  488. % Here, for debugging purposes, I will try to validate the results I
  489. % have obtained by testing if Q*V+U1=U and 0<=U1<V. I Know this slows things
  490. % down, but I will remove it when my confidence has improved somewhat;
  491. % if not BZerop U1 then <<
  492. % if (BMinusP U and not BMinusP U1) or
  493. % (BMinusP U1 and not BMinusP U) then
  494. % BHardBug("remainder has wrong sign",U,V,U1,Q) >>;
  495. % if not BAbs U1<BAbs V then BHardBug("remainder out of range",U,V,U1,Q)
  496. % else if not BZerop(BDifference(BPlus2(BTimes2(Q,V),U1),U)) then
  497. % BHardBug("quotient or remainder incorrect",U,V,U1,Q);
  498. return (Q . U1)
  499. end;
  500. lisp procedure BHardBug(msg,U,V,R,Q);
  501. % Because the inputs to BHardDivide are probably rather large, I am not
  502. % going to rely on BldMsg to display them;
  503. << Prin2T "***** Internal error in BHardDivide";
  504. Prin2 "arg1="; Prin2T U;
  505. Prin2 "arg2="; Prin2T V;
  506. Prin2 "computed quotient="; Prin2T Q;
  507. Prin2 "computed remainder="; Prin2T R;
  508. StdError msg >>;
  509. lisp procedure BGreaterP(U,V);
  510. if BMinusP U then
  511. if BMinusP V then BUnsignedGreaterP(V,U)
  512. else nil
  513. else if BMinusP V then U
  514. else BUnsignedGreaterP(U,V);
  515. lisp procedure BLessp(U,V);
  516. if BMinusP U then
  517. if BMinusP V then BUnsignedGreaterP(U,V)
  518. else U
  519. else if BMinusP V then nil
  520. else BUnsignedGreaterP(V,U);
  521. lisp procedure BGeq(U,V);
  522. if BMinusP U then
  523. if BMinusP V then BUnsignedGeq(V,U)
  524. else nil
  525. else if BMinusP V then U
  526. else BUnsignedGeq(U,V);
  527. lisp procedure BLeq(U,V);
  528. if BMinusP U then
  529. if BMinusP V then BUnsignedGeq(U,V)
  530. else U
  531. else if BMinusP V then nil
  532. else BUnsignedGeq(V,U);
  533. lisp procedure BUnsignedGreaterP(U,V);
  534. % Compare magnitudes of two bignums;
  535. begin
  536. scalar Lu,Lv,I;
  537. Lu := BSize U;
  538. Lv := BSize V;
  539. if not (Lu eq Lv) then <<
  540. if IGreaterP(Lu,Lv) then return U
  541. else return nil >>;
  542. while IGetV(U,Lv) eq IGetV(V,Lv) and IGreaterP(Lv,1) do Lv := ISub1 Lv;
  543. if IGreaterP(IGetV(U,Lv),IGetV(V,Lv)) then return U
  544. else return nil
  545. end;
  546. symbolic procedure BUnsignedGeq(U,V);
  547. % Compare magnitudes of two unsigned bignums;
  548. begin
  549. scalar Lu,Lv;
  550. Lu := BSize U;
  551. Lv := BSize V;
  552. if not (Lu eq Lv) then <<
  553. if IGreaterP(Lu,Lv) then return U
  554. else return nil >>;
  555. while IGetV(U,Lv) eq IGetV(V,Lv) and IGreaterP(Lv,1) do Lv := ISub1 Lv;
  556. If IGreaterP(IGetV(V,Lv),IGetV(U,Lv)) then return nil
  557. else return U
  558. end;
  559. lisp procedure BAdd1 V;
  560. BSmallAdd(V,1);
  561. lisp procedure BSub1 U;
  562. BSmallDiff(U,1);
  563. % ------------------------------------------------
  564. % Conversion to Float:
  565. lisp procedure FloatFromBigNum V;
  566. if BZeroP V then 0.0
  567. else if BGreaterP(V, FloatHi!*) or BLessp(V, FloatLow!*)
  568. then Error(99,list("Argument, ",V," to FLOAT is too large"))
  569. else begin scalar L,Res,Sn,I;
  570. L:=BSize V;
  571. Sn:=BMinusP V;
  572. Res:=float IGetv(V,L);
  573. I:=ISub1 L;
  574. While not IZeroP I do << Res:=res*BBase!*;
  575. Res:=Res +IGetV(V,I);
  576. I:=ISub1 I>>;
  577. if Sn then Res:=minus res;
  578. return res;
  579. end;
  580. % ------------------------------------------------
  581. % Input and Output:
  582. Digit2Letter!* := % Ascii values of digits and characters.
  583. '[48 49 50 51 52 53 54 55 56 57 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
  584. 80 81 82 83 84 85 86 87 88 89 90];
  585. % OutputBase!* is assumed to be positive and less than 37.
  586. lisp procedure BChannelPrin2(Channel,V);
  587. If not BignumP V then NonBigNumError(V, 'BPrin) %need?
  588. else begin scalar quot, rem, div, result, resultsign, myobase;
  589. myobase:=OutputBase!*;
  590. resultsign:=BMinusP V;
  591. div:=BSimpleDivide(V,Bsize V,OutputBase!*,nil);
  592. quot:=car div;
  593. rem:=cdr div;
  594. if Bzerop rem then rem:=0 else rem:=IGetV(rem,1);
  595. result:=rem . result;
  596. while Not BZeroP quot do
  597. <<div:=BSimpleDivide(quot,Bsize quot,OutputBase!*,nil);
  598. quot:=car div;
  599. rem:=cdr div;
  600. if Bzerop rem then rem:=0 else rem:=IGetV(rem,1);
  601. result:=rem . result>>;
  602. if resultsign then channelwritechar(Channel,char !-);
  603. if myobase neq 10 then <<ChannelWriteSysInteger(channel,myobase,10);
  604. ChannelWriteChar(Channel, char !#)>>;
  605. For each u in result do ChannelWriteChar(Channel, IGetV(digit2letter!*,u));
  606. OutputBase!*:=myobase;
  607. return;
  608. end;
  609. lisp procedure BRead(s,radix,sn); % radix is < Bbase!*
  610. %s=string of digits, radix=base, sn=1 or -1
  611. begin scalar sz, res, ch;
  612. sz:=size s;
  613. res:=GtPOS 1;
  614. ch:=indx(s,0);
  615. if IGeq(ch,char A) and ILeq(ch,char Z)
  616. then ch:=IPlus2(IDifference(ch,char A),10);
  617. if IGeq(ch,char 0) and ILeq(ch,char 9)
  618. then ch:=IDifference(ch,char 0);
  619. IPutV(res,1,ch);
  620. IFor i:=1:sz do <<ch:=indx(s,i);
  621. if IGeq(ch,char A) and ILeq(ch,char Z)
  622. then ch:=IDifference(ch,IDifference(char A,10));
  623. if IGeq(ch,char 0) and ILeq(ch,char 9)
  624. then ch:=IDifference(ch,char 0);
  625. res:=BReadAdd(res, radix, ch)>>;
  626. if iminusp sn then res:=BMinus res;
  627. return res;
  628. end;
  629. lisp procedure BReadAdd(V, radix, ch);
  630. << V:=BSmallTimes2(V, radix);
  631. V:=BSmallAdd(V,ch)>>;
  632. lisp procedure BSmallAdd(V,C); %V big, C fix.
  633. if IZerop C then return V
  634. else if Bzerop V then return int2B C
  635. else if BMinusp V then BMinus BSmallDiff(BMinus V, C)
  636. else if IMinusP C then BSmallDiff(V, IMinus C)
  637. else begin scalar V1,L1;
  638. Carry!*:=C;
  639. L1:=BSize V;
  640. V1:=GtPOS(IAdd1 L1);
  641. IFor i:=1:L1 do IPutV(V1,i,addcarry IGetV(V,i));
  642. if IOneP carry!* then IPutV(V1,IAdd1 L1,1) else return TrimBigNum1(V1,L1);
  643. return V1
  644. end;
  645. lisp procedure BNum N; % temporary? Creates a Bignum of one digit, value N.
  646. begin scalar B;
  647. if IZerop n then return GtPOS 0
  648. else if IMinusp N then <<b:=GtNEG 1; n:= IMinus n>> else b:=GtPos 1;
  649. IPutV(b,1,N);
  650. Return b;
  651. end;
  652. lisp procedure BSmallDiff(V,C); %V big, C fix
  653. if IZerop C then V
  654. else if BZeroP V then int2B IMinus C
  655. else if BMinusP V then BMinus BSmallAdd(BMinus V, C)
  656. else if IMinusP C then BSmallAdd(V, IMinus C)
  657. else begin scalar V1,L1;
  658. Carry!*:=C;
  659. L1:=BSize V;
  660. V1:=GtPOS L1;
  661. IFor i:=1:L1 do IPuTV(V1,i,subcarry IGetV(V,i));
  662. if not IZeroP carry!* then
  663. StdError BldMsg(" BSmallDiff V<C %p %p%n",V,C);
  664. return TrimBigNum1(V1,L1);
  665. end;
  666. lisp procedure int2B n; % Temporary? Creates BigNum of value N.
  667. if not fixp n then NonIntegerError(n, 'int2B)
  668. else if ILessP(n,Bbase!*) then BNum n
  669. else begin scalar Str,ind,rad,Sn,r;
  670. Str:=bldmsg("%w",n); % like an "int2string"
  671. if indx(str,0)=char '!- then <<Sn:=-1;
  672. str:=sub(str,1,ISub1 (size str))>>
  673. else Sn:=1;
  674. IFor i:=0:size str do
  675. if indx(str,i)=char '!# then ind:=i;
  676. if ind then <<r:=sub(str,0,ISub1 ind);
  677. rad:=0;
  678. IFor i:=0:size r do
  679. rad:=IPlus2(ITimes2(rad,10),IDifference(indx(r,i),char 0));
  680. str:=sub(str,IAdd1 ind,IDifference(size str,IAdd1 ind))>>
  681. else rad:=10;
  682. return Bread(str,rad,sn);
  683. end;
  684. %-----------------------------------------------------
  685. % "Fix" for Bignums
  686. lisp procedure bigfromfloat X;
  687. if fixp x or bigp x then x
  688. else begin scalar bigpart,floatpart,power,sign,thispart;
  689. if minusp X then <<sign:=-1; X:=minus X>> else sign:=1;
  690. bigpart:=bnum 0;
  691. while neq(X, 0) and neq(x,0.0) do <<
  692. if X < bbase!* then << bigpart:=bplus2(bigpart, bnum fix x);
  693. X:=0 >>
  694. else <<floatpart:=x;
  695. power:=0;
  696. while floatpart>=bbase!* do % get high end of number.
  697. <<floatpart:=floatpart/bbase!*;
  698. power:=power + bbits!* >>;
  699. thispart:=btimes2(btwopower power, bnum fix floatpart);
  700. X:=X- floatfrombignum thispart;
  701. bigpart:=bplus2(bigpart, thispart) >> >>;
  702. if minusp sign then bigpart := bminus bigpart;
  703. return bigpart;
  704. end;
  705. if_system(VAX,
  706. <<setbits 32;
  707. FloatHi!*:=btimes2(bdifference(btwopower 67, btwopower 11),
  708. btwopower 60);% Largest representable float.
  709. FloatLow!*:=BMinus FloatHi!*>>);
  710. if_system(PDP10,
  711. <<setbits 36;
  712. FloatHi!*:=btimes2(bsub1 btwopower 62, btwopower 65);
  713. FloatLow!*:=BMinus FloatHi!*>>);
  714. % End of BIGBIG.RED ;