Thema: HugeInt_Div

Einzelnen Beitrag anzeigen

gammatester

Registriert seit: 6. Dez 2005
999 Beiträge
 
#6

AW: HugeInt_Div

  Alt 11. Jan 2012, 14:21
BTW, für HugeInt_Mod konnte ich außer daß das Ergebnis negativ ist, wenn A negativ ist, bisher keinen Fehler feststellen(Der "Oops-Fehler"). Kann man ein A div X iregndwie als mod casten und zurückrechnen, ansonsten bleibt nur Result[I]:= R div B gesondert zu behandeln (N* Subtraktion).
Das mit dem casten verstehe ich nicht. Man hat bei richtiger Implementation von div und mod die Formel A = (A div B)*B + A mod B also A div B = (A - A mod B) div B ohne Rest, aber das könnte die Sache noch verschlimmern, weil dann eventuell ja eine weitere 0 weggeshiftet wird. Ansonsten ist hier ein Fix ohne Garantie für die Original-Routine. Die Anzahl der R-Stellen wird vorher berechet und damit eine for-Schleife durchlaufen:
Delphi-Quellcode:
procedure HugeInt_DivMod(var A: HugeInt; B: HugeInt; var R: HugeInt);
{ R := A div B; A := A mod B }
var
  MaxShifts, S, Q, I: integer;
  D, E: HugeInt;
  A_IsNeg, B_IsNeg: boolean;
begin
  A_IsNeg:= HugeInt_IsNeg(A);
  B_IsNeg:= HugeInt_IsNeg(B);
  if A_IsNeg then HugeInt_Min(A);
  if B_IsNeg then HugeInt_Min(B);
  if HugeInt_Comp(A, B) < 0 then
    { A<B; no need to divide }
    FillChar(R, SizeOf(R), 0)
  else
  begin
    FillChar(R, SizeOf(R), 0);
    Move(B, D, SizeOf(HugeInt));
    { first work out the number of shifts }
    MaxShifts:= HugeInt_HCD(A)- HugeInt_HCD(B);
    S:= 0;
    while (S <= MaxShifts) and (HugeInt_Comp(A, D) >= 0) do
    begin
      Inc(S);
      HugeInt_SHL(D, 1);
    end; { while }
    Dec(S);
    for I:=S downto 0 do begin
      { Make A new copy of B }
      Move(B, D, SizeOf(HugeInt));
      { Shift D as needed }
      HugeInt_ShL(D, I);
      { Use E = -D for addition, faster then subtracting D }
      Move(D, E, SizeOf(HugeInt));
      HugeInt_Min(E);
      Q:= 0;
      { while A >= D do A := A+-D and keep trek of # in Q}
      while HugeInt_Comp(A, D) >= 0 do
      begin
        HugeInt_Add(A, E, A);
        Inc(Q);
      end; { while }
      { OOps!, one too many subtractions; correct }
      if HugeInt_IsNeg(A) then
      begin
        HugeInt_Add(A, D, A);
        Dec(Q);
      end; { if }
      R[I]:= Q;
    end;
    if A_IsNeg Xor B_IsNeg then HugeInt_Min(R);
  end; { else }
end; { HugeInt_Div }
Für die bisherigen Fälle und zB für (456*123456+78) div 456 scheint's zu laufen, aber ...! Die minimale Änderung hat den undurchsichtigen Code nicht klarer gemacht.
  Mit Zitat antworten Zitat