PROCEDURE Divide(n,d : T; VAR q,r : T) : Sign = VAR nsize,dsize,qsize,rsize : SizeT; nsign,dsign,qsign : Sign; np,dp,qp,rp : MPNum.T; qdgt : DigitT; norm_steps : Ctypes.unsigned_long_int; BEGIN dsign:=GetSign(d); dsize:=NumDigits(d); IF dsign = MP_ZERO THEN Wr.PutText(Stdio.stdout,"******* Division by ZERO ******\n"); Wr.Flush(Stdio.stdout); WITH c=0 DO EVAL 1 DIV c (* to abort the program *) END END; nsign:=GetSign(n); nsize:=NumDigits(n); CASE CompAbs(n,d) OF | -1 => BEGIN (* |n| < |d| *) q:=FromInteger(0); r:=Copy(n); RETURN MP_ZERO; END; | 0 => BEGIN (* |y| = |z| *) q:=FromInteger(1); SetSign(q,nsign*dsign); r:=FromInteger(0); RETURN MP_POS END; | +1 => BEGIN (* |y| > |z| *) (* Ensure space is enough for quotient and remainder. We need space for an extra limb in the remainder, because it's up-shifted (normalized) below. *) rsize:=nsize+1; qsize:=rsize-dsize; qsign:=nsign*dsign; q:=Create(qsize); np:=IntToNum(n); qp:=IntToNum(q); IF dsize = 1 THEN WITH ddgt = GetDigit(d,dsize), rdgt = MPNum.DivMod_1(qp,np,nsize,ddgt) DO r:=Create(dsize); SetDigit(r,dsize,rdgt); END ELSE dp:=IntToNum(d); WITH ddgt = GetDigit(d,dsize) DO norm_steps := CountLeadingZerosInDigit(ddgt); END; (* Normalize the denominator, i.e. make its most significant bit set by shifting it "norm_steps" bits to the left. Also shift the numerator the same number of steps (to keep the quotient the same!). *) IF norm_steps # 0 THEN (* Shift up the denominator setting the most significant bit OF the most significant word. Use temporary storage not to clobber the original contents of the denominator. *) WITH t = Create(dsize), tp = IntToNum(t), dgt = MPNum.LShift(tp,dp,dsize,norm_steps) DO SetSign(t,dsign); Wr.PutText(Stdio.stdout,"norm_steps = "&Fmt.Int(norm_steps)&"\n"); Wr.PutText(Stdio.stdout,"d = "&ToString(d)&"\n"); Wr.PutText(Stdio.stdout,"t = "&ToString(t)&"\n"); Wr.Flush(Stdio.stdout); d:=t; END; (* Shift up the numerator, possibly introducing a new most significant word. Move the shifted numerator in the remainder meanwhile. *) Wr.PutText(Stdio.stdout,"n = "&ToString(n)&"\n"); Wr.Flush(Stdio.stdout); r:=Create(nsize); rp:=IntToNum(r); Wr.PutText(Stdio.stdout,"n (antes de shift)= "&ToString(n)&" norm_steps = "&Fmt.Int(norm_steps)&"\n"); WITH dgt = MPNum.LShift(rp,np,nsize,norm_steps) DO SetSign(r,nsign); Wr.PutText(Stdio.stdout,"r (antes de SET) = "&ToString(r)&" dgt = "&Fmt.Int(dgt)&"\n"); Wr.Flush(Stdio.stdout); IF dgt # 0 THEN WITH newr = Create(nsize+1) DO Assign(newr,r,nsize); SetDigit(newr,nsize+1,dgt); r:=newr END; END; Wr.PutText(Stdio.stdout,"r (depois de SET) = "&ToString(r)&" dgt = "&Fmt.Int(dgt)&"\n"); Wr.Flush(Stdio.stdout); END; ELSE (* The denominator is already normalized, as required. Move the numerator to the remainder. *) r:=Copy(n) END; (* Since "r" may has been modified, atualize the pointer to digits of "r" and its (new) size. *) rp:=IntToNum(r); dp:=IntToNum(d); rsize:=NumDigits(r); qsize:=rsize-dsize; Wr.PutText(Stdio.stdout,"Antes de DIV \n"); Wr.PutText(Stdio.stdout,"q = "&ToString(r)&"\n"); Wr.PutText(Stdio.stdout,"d = "&ToString(d)&"\n"); Wr.Flush(Stdio.stdout); WITH qdgt = MPNum.DivMod(qp,0,rp,rsize,dp,dsize) DO SetSign(q,qsign); Wr.PutText(Stdio.stdout,"q (depois de DIV) = "&ToString(q)&" qdgt = "&Fmt.Int(qdgt)&"\n"); (* Includes "qdgt" in "q" *) IF qdgt # 0 THEN WITH newq = Create(qsize+1) DO Assign(newq,q,qsize); SetDigit(newq,qsize+1,qdgt); q:=newq END END; END; Wr.PutText(Stdio.stdout,"q (depois de SET) = "&ToString(q)&"\n\n"); Wr.PutText(Stdio.stdout,"r (antes da desnormalizacao) = "&ToString(r)&"\n"); Wr.Flush(Stdio.stdout); (* Rebuilds the remainder "r" *) WITH tr = Create(dsize) DO Assign(tr,r,dsize); (* Copies the value of "tr" to "r" eliminating leading zeros. *) r:=Copy(tr); rp:=IntToNum(r); rsize:=NumDigits(r) END; IF norm_steps # 0 THEN WITH rdgt = MPNum.RShift(rp,rp,rsize,norm_steps) DO (* Eliminates leading zeros introduced by "rshift" *) r:=Copy(r) END END; END; SetSign(r,nsign); SetSign(q,qsign); RETURN qsign END; END END Divide;