Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2010.02.21;
Скачать: [xml.tar.bz2];

Вниз

Длинное деление: проблема с остатком   Найти похожие ветки 

 
AssemblerIA64   (2009-03-25 23:02) [0]

Имеется код, выполняющий деление длинных чисел (взят из книги Уоррена):

...
Num = record
    x: Digit;
    l: Word;
end;
...
function LongDiv(u, v: Num; var q: Num; var r: Num): byte;
label again;
const
 b = 4294967296;
var
 s: Cardinal;
 un, vn: Num;
 i, j: Word;
 qhat: int64;
 rhat: int64;
 p, t: int64;
 temp1, temp2, k: uint64;
 owf: Boolean;

begin
 if (v.l <= 0) or (v.x[v.l-1] = 0) then
 begin
   LongDiv := 1;
   exit;
 end;
 if More(v, u) then
 begin
   SetLngth(q, 1);
   q.x[0] := 0;
   Move(r, u);
   LongDiv := 0;
   exit;
 end;
 SetLngth(q, u.l);
 for i := 0 to u.l - 1 do q.x[i] := 0;
 SetLngth(r, v.l);
 SetTo0(r, v.l);

 if v.l = 1 then
 begin
     {$Q-}
     {$R-}
     k := 0;
     for j := u.l-1 downto 0 do
     begin
       q.x[j] := (k*b+u.x[j]) div v.x[0];
       k := (k*b+u.x[j]) - q.x[j]*v.x[0];
     end;
     SetLngth(r, 1);
     r.x[0] := k;
     {$Q+}
     {$R+}
     LongDiv := 0;
     exit;
 end;
//--------------------------
 {$R-}
 s := nlz(v.x[v.l-1]);
 {$R+}
 SetLngth(vn, v.l);
 if s <> 0 then
 begin
   for j := v.l-1 downto 1 do
     vn.x[j] := (v.x[j] shl s) or (v.x[j-1] shr (32-s));
   vn.x[0] := v.x[0] shl s;
   SetLngth(un, u.l+1);
   un.x[u.l] := u.x[u.l-1] shr (32-s);
   for j := u.l-1 downto 1 do
     un.x[j] := (u.x[j] shl s) or (u.x[j-1] shr (32-s));
  un.x[0] := u.x[0] shl s;
 end
 else
 begin
   for j := v.l-1 downto 0 do
     vn.x[j] := v.x[j];
   SetLngth(un, u.l+1);
   for j := u.l-1 downto 0 do
     un.x[j] := u.x[j];
 end;
//--------------------------
 {$Q-}
 {$R-}
 for j := u.l-v.l downto 0 do
 begin
   qhat := (un.x[j+v.l]*b + un.x[j+v.l-1]) div vn.x[v.l-1];
   rhat := (un.x[j+v.l]*b + un.x[j+v.l-1]) - qhat*vn.x[v.l-1];
again:
   temp1 := qhat*vn.x[v.l-2];
   temp2 := b*rhat + un.x[j+v.l-2];
   if ((qhat >= b) or (temp1 > temp2)) then
   begin
     dec(qhat);
     rhat := rhat + vn.x[v.l-1];
     if (rhat < b) then goto again;
   end;
   k := 0;

   for i := 0 to v.l - 1 do
   begin
     p := qhat*vn.x[i];
     t := un.x[i+j] - k - (p and $0FFFFFFFF);
     un.x[i+j] := t;
     k :=  (p shr 32) - (t shr 32) ;
   end;

   t := un.x[j+v.l] - k;
   un.x[j+v.l] := t;
   q.x[j] := qhat;
   if t < 0 then
   begin
     q.x[j] := q.x[j] - 1;
     k := 0;
     for i := 0 to v.l-1 do
     begin
       t := un.x[i+j] + vn.x[i] + k;
       un.x[i+j] := t;
       k := t shr 32;
     end;
     un.x[j+v.l] := un.x[j+v.l] + k;
   end;
 end;
 {$R+}
 {$Q+}
 for j := 0 to v.l - 1 do
 begin
     r.x[j] := (un.x[j] shr s) or (un.x[j+1] shl (32-s));
 end;

 SetLngth(q, GetLngth(q.x, q.l));
 SetLngth(r, GetLngth(r.x, r.l));
 LongDiv := 0;
end;

В нём при делении (2851389442 + 2361951239*2^32 + 2247011709*2^64 + 50788274*2^96)/(4294967295 + 536870911*2^32) остаток определяется неправильно. Последнее значение un (это ещё не денормализованный остаток) равняется (3411107704 + 671223006*2^32 + 1*2^64), а должно быть (3411107704 + 671223006*2^32). Ошибка происходит на 3-ей итерации главного цикла в блоке
for i := 0 to v.l - 1 do
begin
     p := qhat*vn.x[i];
     t := un.x[i+j] - k - (p and $0FFFFFFFF);
     un.x[i+j] := t;
     k :=  (p shr 32) - (t shr 32) ;
end;

А в чём именно, я понять не могу. Подскажите, кто знает.
Спасибо.

+ вспомогательные функции

...
type
...
Digit = array of Cardinal;
...

function GetLngth(x : Digit; m: Word): Word;
var i : Integer;
begin
 i := m-1;
 while (i > 0) and (x[i] = 0) do
   i := i - 1;
 GetLngth := i+1;
end;

procedure SetLngth(var a: Num; m: Word);
begin
 SetLength(a.x, m);
 a.l := m;
end;

procedure Move(var a: Num; b: Num);
var
 i: Word;
begin
 SetLngth(a, b.l);
 a.l := b.l;
 for i := 0 to a.l - 1 do
   a.x[i] := b.x[i];
end;

procedure SetTo0(var a: Num; m: Word); overload;
var
 i: Word;
begin
 for i := 0 to a.l - 1 do a.x[i] := 0;
 SetLngth(a, m);
end;

function Eq(a, b: Num): Boolean;
var i: Word;
begin
   Eq:=False;
   if a.l <> b.l then exit
   else
   begin
       i := 0;
       while (i <= a.l) and (a.x[i] = b.x[i]) do
         Inc(i);
       Eq := (i = a.l) ;
   end;
end;

function More(a, b: Num): Boolean;
var i:Integer;
begin
 if a.l < b.l then
   More := false
 else if a.l > b.l then
   More := true
 else
 begin
   i := a.l - 1 ;
   while (i > 1) and (a.x[i] = b.x[i]) do dec(i);
   if a.x[i] > b.x[i] then
       More := true
   else
       More := false;
 end;
end;


+ upd
Нашёл одну ошибку: при вычислении qhat возникало переполнение. Надо писать
qhat := un.x[j+v.l];
qhat := (qhat*b + un.x[j+v.l-1]) div vn.x[v.l-1];
rhat := un.x[j+v.l];
rhat := (rhat*b + un.x[j+v.l-1]) - qhat*vn.x[v.l-1];


 
Slym ©   (2009-03-26 05:00) [1]

Чем готовый FGInt не угодил?


 
AssemblerIA64   (2009-03-26 23:29) [2]

Всё, проблема исчерпала себя.
Ошибки, в основном, были в операторах присвоения, в которых в левой части стояла переменная типа int64, а в правой выражение, в котором были переменные типа Cardinal. Из-за этого не происходило приведения младшего типа данных к старшиму до вычисления.


 
Германн ©   (2009-03-27 00:28) [3]


> а в правой выражение, в котором были переменные типа Cardinal

Уж сколько раз твердили миру!  Особенно АП.



Страницы: 1 вся ветка

Форум: "Основная";
Текущий архив: 2010.02.21;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.47 MB
Время: 0.006 c
15-1260658521
Германн
2009-12-13 01:55
2010.02.21
Blacklist в почтовых (email) сообщениях.


2-1261410151
Aleks
2009-12-21 18:42
2010.02.21
Динамически создавать каждый компонент или копировать объект


15-1260394219
Юрий
2009-12-10 00:30
2010.02.21
С днем рождения ! 10 декабря 2009 четверг


3-1234876925
Дукам
2009-02-17 16:22
2010.02.21
Просмотр объектов, привязанных к таблице


2-1261476735
Евгений11111
2009-12-22 13:12
2010.02.21
Обход в цикле элементов (Edit1, Edit2, Edit3 и т.д.)одного класса





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский