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

Вниз

Поиск совпадений цифр в списке чисел. Есть ли мысли?   Найти похожие ветки 

 
Sha ©   (2005-10-26 16:22) [40]

Если из цикла вынести лишнее, простой перебор ускоряется в 2 раза

procedure TForm1.Button3Click(Sender: TObject);
//попарное сравнение (чуть быстрее)
var
A: array of Int64;
l1, l2: Int64;
i, j, k, ii, jj, Cnt, Mx: Integer;
t: DWord;
md: array[1..14] of integer;
begin
SetLength(A, N);
RandSeed := 2;
for i := 0 to N - 1 do begin
  A[i] := 10000000000000 + Int64(1000000) * Random(90000000) +
    Random(1000000);
//  Memo1.Lines.Add(Format("%d  %d", [i, A[i]]));
end;
t := GetTickCount;
Mx := 0;
ii := 0;
jj := 0;
for i := 0 to N - 2 do begin
  l1 := A[i];
  for k := 1 to 14 do begin
    md[k]:=l1 mod 10;
    l1 := l1 div 10;
    end;
  for j := i + 1 to N - 1 do begin
    l2 := A[j];
    Cnt := 0;
    for k := 1 to 14 do begin
      Inc(Cnt,ord(l2 mod 10=md[k]));
      l2 := l2 div 10;
    end;
    if Cnt > Mx then begin
      Mx := Cnt;
      ii := i;
      jj := j;
    end;
  end;
end;
Memo1.Lines.Add(Format("%d мс:", [GetTickCount - t]));
Memo1.Lines.Add(Format("%d совпадений:", [Mx]));
Memo1.Lines.Add(Format("%d %d", [ii, A[ii]]));
Memo1.Lines.Add(Format("%d %d", [jj, A[jj]]));
end;


 
MBo ©   (2005-10-26 16:55) [41]

>Sha ©   (26.10.05 15:55) [39]

На P3-600 разница еще больше - в 200 раз
Самые глубоковложенный цикл выполняется в переборном методе примерно 7*N^2 раз, а во втором случае 0.7 * N^2 раз.

В матричном методе в цикле просто инкремент байта идет.
А в переборе в цикле выполняются 4 деления Int64 - это, конечно, маразм, и нужно оптимизировать, переходя к сравнению строковых значений.
Тогда разница всего в 1.6-2 раза будет, так что  увы, овчинка с использованием доп. памяти в моей реализации выделки не стоит ;(


procedure TForm1.Button1Click(Sender: TObject);
var
A: array of Int64;
B: array of string;
i, j, k, ii, jj, Cnt, Mx: Integer;
t: DWord;
begin
SetLength(A, N);
SetLength(B, N);
RandSeed := 2;
for i := 0 to N - 1 do begin
  A[i] := 10000000000000 + Int64(1000000) * Random(90000000) +
    Random(1000000);
  B[i] := IntToStr(A[i]);
//  Memo1.Lines.Add(Format("%d  %d", [i, A[i]]));
end;
t := GetTickCount;
Mx := 0;
ii := 0;
jj := 0;
for i := 0 to N - 2 do
  for j := i + 1 to N - 1 do begin
    Cnt:=0;
    for k:=1 to 14 do begin
      if B[i,k]=B[j,k] then
        Inc(Cnt);
    end;
    if Cnt > Mx then begin
      Mx := Cnt;
      ii := i;
      jj := j;
    end;
  end;
Memo1.Lines.Add(Format("%d мс:", [GetTickCount - t]));
Memo1.Lines.Add(Format("%d совпадений:", [Mx]));
Memo1.Lines.Add(Format("%d %d", [ii, A[ii]]));
Memo1.Lines.Add(Format("%d %d", [jj, A[jj]]));
end;



 
Sha ©   (2005-10-26 16:59) [42]

Еще немного улучшил полный перебор:
- вычисляю модули один раз
- оптимизировал работу с индексами

Результат превосходит ожидания

657 мс:
10 совпадений:
3814 35129365269927
4733 28047279209345

procedure TForm1.Button4Click(Sender: TObject);
//попарное сравнение (еще быстрее)
var
A: array of Int64;
l1, l2: Int64;
i, j, k, ii, jj, Cnt, Mx, jmax: Integer;
t: DWord;
md: array of integer;
begin
if N<2 then exit;
SetLength(A, N);
RandSeed := 2;
for i := 0 to N - 1 do begin
  A[i] := 10000000000000 + Int64(1000000) * Random(90000000) +
    Random(1000000);
//  Memo1.Lines.Add(Format("%d  %d", [i, A[i]]));
end;
SetLength(md,14 * N);
t := GetTickCount;
Mx := 0;
ii := 0;
jj := 0;

j:=14*N;
for i:=0 to N-1 do begin
  l1 := A[i];
  for k := 1 to 14 do begin
    dec(j);
    md[j]:=l1 mod 10;
    l1 := l1 div 10;
  end;
end;

i:=(N-1)*14-1;
jmax:=N*14-1;
repeat
  j:=jmax;
  repeat
    k:=-13;
    Cnt := 0;
    repeat
      Inc(Cnt,ord(md[i+k]=md[j+k]));
      inc(k);
    until k>0;
    if Cnt > Mx then begin
      Mx := Cnt;
      ii := i;
      jj := j;
    end;
    dec(j,14);
  until j=i;
  dec(i,14);
until i<0;
Memo1.Lines.Add(Format("%d мс:", [GetTickCount - t]));
Memo1.Lines.Add(Format("%d совпадений:", [Mx]));
Memo1.Lines.Add(Format("%d %d", [ii div 14, A[ii div 14]]));
Memo1.Lines.Add(Format("%d %d", [jj div 14, A[jj div 14]]));
end;


 
Sha ©   (2005-10-26 17:10) [43]

Можно еще ускорить ~10..15% если в цикле перебора пар
вместо типа целочисленных индексов i, j использовать
указатели pIntegerArray.


 
MBo ©   (2005-10-26 17:25) [44]

>Sha ©   (26.10.05 16:59) [42]
Мощно ускорилось. Но со сравнением строк быстрее будет.

Матричный алгоритм переделал, отказавшись от списков в пользу массивов  - еще в полтора раза разогнал.

P600, 5000 элементов:

Перебор, сравнение строк - 2914
Матричный, TList 1813
Матричный, массивы 1342
Sha [42]   5909


 
Sha ©   (2005-10-26 17:39) [45]

> MBo ©   (26.10.05 17:25) [44]
> Мощно ускорилось. Но со сравнением строк быстрее будет.

На моем P4 сравнение строк медленнее:

797 мс:
10 совпадений:
253 52449711333529
2212 52449701333918


Но его тоже можно значительно ускорить,
если все данные хранить в одной строке


 
Sha ©   (2005-10-26 18:03) [46]

594 мс: !

procedure TForm1.Button6Click(Sender: TObject);
var
A: array of Int64;
B, s: string;
i, j, k, Cnt, Mx: Integer;
t: DWord;
p, q, r, ii, jj: pchar;
begin
SetLength(A, N);
SetLength(s, N*14); p:=pointer(s);
RandSeed := 2;
for i := 0 to N - 1 do begin
 A[i] := 10000000000000 + Int64(1000000) * Random(90000000) +
   Random(1000000);
 B:= IntToStr(A[i]);
 move(b[1], p^, 14); inc(p,14);
//  Memo1.Lines.Add(Format("%d  %d", [i, A[i]]));
end;
t := GetTickCount;
Mx := 0;
//ii := 0;
//jj := 0;
p:=pointer(s); r:=p+14*(N-2);
repeat
 q:=p;
 repeat
   inc(q,14);
   Cnt:=0;
   k:=13;
   repeat
     inc(Cnt,ord(p[k]=q[k]));
     dec(k);
   until k<0;
   if Cnt > Mx then begin
     Mx := Cnt;
     ii := p;
     jj := q;
     end;
   until q>r;
 inc(p,14);
 until p>r;
Memo1.Lines.Add(Format("%d мс:", [GetTickCount - t]));
Memo1.Lines.Add(Format("%d совпадений:", [Mx]));
//Memo1.Lines.Add(Format("%d %d", [ii, A[ii]]));
//Memo1.Lines.Add(Format("%d %d", [jj, A[jj]]));
end;


 
SergP.   (2005-10-26 18:24) [47]


> Sha ©   (26.10.05 18:03) [46]


А чему у Вас равно N ?


 
Sha ©   (2005-10-26 18:30) [48]

> SergP.   (26.10.05 18:24) [47]
> А чему у Вас равно N ?
5000


 
Sha ©   (2005-10-26 18:39) [49]

> Sha ©   (26.10.05 18:03) [46]
Было бы еще заметно быстрее, если б компилятор оптимально распределил
регистры.
Он r держит на регистре, а p - на стеке, а надо наоборот.
В общем, на BASMе можно еще процентов 15 отжать.


 
Sha ©   (2005-10-26 18:54) [50]

Если развернуть внутренний цикл, получим 500 мс:

p:=pointer(s); r:=p+14*(N-2);
repeat
 q:=p;
 repeat
   inc(q,14);
   Cnt:=0;
     inc(Cnt,ord(p[00]=q[00]));
     inc(Cnt,ord(p[01]=q[01]));
     inc(Cnt,ord(p[02]=q[02]));
     inc(Cnt,ord(p[03]=q[03]));
     inc(Cnt,ord(p[04]=q[04]));
     inc(Cnt,ord(p[05]=q[05]));
     inc(Cnt,ord(p[06]=q[06]));
     inc(Cnt,ord(p[07]=q[07]));
     inc(Cnt,ord(p[08]=q[08]));
     inc(Cnt,ord(p[09]=q[09]));
     inc(Cnt,ord(p[10]=q[10]));
     inc(Cnt,ord(p[11]=q[11]));
     inc(Cnt,ord(p[12]=q[12]));
     inc(Cnt,ord(p[13]=q[13]));
   if Cnt > Mx then begin
     Mx := Cnt;
     //ii := p;
     //jj := q;
     end;
   until q>r;
 inc(p,14);
 until p>r;


 
Sha ©   (2005-10-27 01:38) [51]

Еще в 4 раза быстрее

//С использованием Lookup-таблицы
//(в 4 раза быстрее ускоенного строкового)
procedure TForm1.Button2Click(Sender: TObject);
type
 pWord = ^tWord;
 tWord = array[0..MaxInt div 4] of word;
const
 DigitsInNumber = 14;
 DigitsRounded = (DigitsInNumber+3) and -4; //16
 Bytes = DigitsRounded div sizeof(word); //8
 Words = Bytes div sizeof(word); //4
 WordsTotal = N * Words;
var
 Data: array of word;
 LookupTable: array[word] of byte;
 Distance, MaxDistance: byte;
 t: integer;
 p, q, r: pWord;
begin;

 //Генерируем десятичные цифры
 //Храним в упакованном двоично-десятичном формате
 //Одно 16-значное число занимает 8 байт (4 слова)
 SetLength(Data, WordsTotal);
 p:=pointer(Data);
 pointer(r):=@p[WordsTotal-Words];
 RandSeed:=183;
 q:=r;
 repeat;
   t:=Random(10);
   t:=t shl 4 + Random(10);
   t:=t shl 4 + Random(10);
   t:=t shl 4 + Random(10);
   q[0]:=t;
   dec(cardinal(q),sizeof(word));
   until cardinal(p)>cardinal(q);

 //Заполняем lookup-таблицу
 for t:=0 to $FFFF do
   LookupTable[t]:=ord(t and $000F=0)
                 + ord(t and $00F0=0)
                 + ord(t and $0F00=0)
                 + ord(t and $F000=0);

 //Ищем минимальное расстояние между числами чисел
 t:=GetTickCount;
 MaxDistance:=0;
 repeat;
   q:=r;
   repeat;
     Distance:=LookupTable[p[0] xor q[0]]
             + LookupTable[p[1] xor q[1]]
             + LookupTable[p[2] xor q[2]]
             + LookupTable[p[3] xor q[3]];
     dec(cardinal(q),Bytes);
     if MaxDistance<Distance then MaxDistance:=Distance;
     until cardinal(p)>=cardinal(q);
   inc(cardinal(p),Bytes);
   until cardinal(p)>=cardinal(r);
 t:=integer(GetTickCount)-t;

 //Выводим результат
 Memo1.Lines.Add(Format("%d мс, %d совпадений", [t, MaxDistance]));
 end;


 
Sha ©   (2005-10-27 01:41) [52]

Только заменить идентификаторы надо :)
Distance -> Matched
MaxDistance -> MaxMatched


 
MBo ©   (2005-10-27 07:03) [53]

>Sha ©   (27.10.05 01:38) [51]

Офигеть! ;)


 
Sandman29 ©   (2005-10-27 09:22) [54]

Sha ©   (27.10.05 01:38) [51]

Красивая идея!
Эх, если бы можно было сделать таблицу не до $FFFF, а до 99 999 999 999 999, тогда получалось бы готовое число совпадений по одному xor.


 
Sha ©   (2005-10-27 09:47) [55]

> Sandman29 ©   (27.10.05 09:22) [54]

Для CPU xor-ов dword-ов все равно будет не меньше 2-х,
поэтому таблица длиннее $FFFFFFFF (что тоже нереально)
не требуется.

Жаль время заполнения такой таблицы будет очень нехилое.


 
Sandman29 ©   (2005-10-27 09:52) [56]

Sha ©   (27.10.05 09:47) [55]

Для CPU xor-ов dword-ов все равно будет не меньше 2-х,
поэтому таблица длиннее $FFFFFFFF (что тоже нереально)
не требуется.


Согласен, стормозил. Даешь 128-битные процессоры! :)

>Жаль время заполнения такой таблицы будет очень нехилое.

Можно в ПЗУ записать. Теоретически


 
Sha ©   (2005-10-27 15:23) [57]

Компилятор генерит более эффективный код (в 1.6 раза)
если ему немного помочь :)

Итого 78 мс:

//С использованием Lookup-таблицы
//(в ~5-6 раз быстрее ускоенного строкового)
//Оптимизировано с целью использования компилятором movzx
procedure TForm1.Button10Click(Sender: TObject);
type
pWord = ^tWord;
tWord = array[0..MaxInt div 4] of word;
const
DigitsInNumber = 14;
DigitsRounded = (DigitsInNumber+3) and -4; //16
DigitsInByte = 2;
Bytes = DigitsRounded div DigitsInByte; //8
Words = Bytes div sizeof(word); //4
WordsTotal = N * Words;
var
Data: array of word;
LookupTable: array[word] of byte;
Matched, MaxMatched: integer;
t, w: integer;
p, q, r: pWord;
begin;

//Генерируем десятичные цифры
//Храним в упакованном двоично-десятичном формате
//Одно 16-значное число занимает 8 байт (4 слова)
SetLength(Data, WordsTotal);
p:=pointer(Data);
pointer(r):=@p[WordsTotal-Words];
RandSeed:=183;
q:=r;
repeat;
  t:=Random(10);
  t:=t shl 4 + Random(10);
  t:=t shl 4 + Random(10);
  t:=t shl 4 + Random(10);
  q[0]:=t;
  dec(cardinal(q),sizeof(word));
  until cardinal(p)>cardinal(q);

//Заполняем lookup-таблицу
for t:=0 to $FFFF do
  LookupTable[t]:=ord(t and $000F=0)
                + ord(t and $00F0=0)
                + ord(t and $0F00=0)
                + ord(t and $F000=0);

//Ищем минимальное расстояние между числами
t:=GetTickCount;
MaxMatched:=0;
repeat;
  q:=r;
  repeat;
    w:=p[0]; w:=w xor q[0]; Matched:=LookupTable[w];
    w:=p[1]; w:=w xor q[1]; Matched:=Matched+LookupTable[w];
    w:=p[2]; w:=w xor q[2]; Matched:=Matched+LookupTable[w];
    w:=p[3]; w:=w xor q[3]; Matched:=Matched+LookupTable[w];
    dec(cardinal(q),Bytes);
    if MaxMatched<Matched then MaxMatched:=Matched;
    until cardinal(p)>=cardinal(q);
  inc(cardinal(p),Bytes);
  until cardinal(p)>=cardinal(r);
t:=integer(GetTickCount)-t;

//Выводим результат
Memo1.Lines.Add(Format("%d мс, %d совпадений", [t, MaxMatched]));
end;



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

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

Наверх




Память: 0.58 MB
Время: 0.052 c
14-1130262345
Bogdan1024
2005-10-25 21:45
2005.11.20
Как приделать кулер?


1-1130527472
Arazel
2005-10-28 23:24
2005.11.20
TabControl > TabsScroll (CUSTOMDRAW)


2-1130744171
abu
2005-10-31 10:36
2005.11.20
Целые числа в TDate


3-1128661433
syte_ser78
2005-10-07 09:03
2005.11.20
Перевод БД на другой язык


14-1130506982
Руслан
2005-10-28 17:43
2005.11.20
Можно ли узнать





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский