powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Ускорить функцию перевода массива байт в число
8 сообщений из 133, страница 6 из 6
Ускорить функцию перевода массива байт в число
    #39929894
Polesov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ВсеРазумный
Polesov,

А ещё решается выравниванием массива до X%8=0 и мы получаем прирост в 1.301539 сек

Не решается.
Массив из 16 байт [0 .. 15].
Начальный индекс 13, конечный индекс 15.

В принципе, можно размер массива брать с запасом в 7 байт.
...
Рейтинг: 0 / 0
Ускорить функцию перевода массива байт в число
    #39929896
Vlad F
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Эк, однако, же вас, парни, всё-таки разобралО.
...
Рейтинг: 0 / 0
Ускорить функцию перевода массива байт в число
    #39929897
Polesov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Vlad F,
я сделал это не в целях правды, а в целях истины (c) )
...
Рейтинг: 0 / 0
Ускорить функцию перевода массива байт в число
    #39929898
Фигасе, вот это да! asm функция хуже компиляторной

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
program Project1;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  Winapi.Windows, System.SysUtils;

function to_num(const arr: array of byte; const i, j: integer): UInt64;
var
  k: integer;
begin
  Result := arr[i];
  for k := (i + 1) to j do
  begin
    Result := Result shl 8;
    Result := Result or arr[k];
  end;
end;

function Convert2(const arr: array of byte; pos, len: integer): UInt64;
{$IF Defined(CPUX86)}
var
  Lo, Hi: Cardinal;
begin
  Result := PUInt64(@arr[pos])^ shl (8 * (8 - len));

  Lo := Int64Rec(Result).Hi;
  Hi := Int64Rec(Result).Lo;
  Int64Rec(Result).Hi := (Hi shr 24) or ((Hi and $00FF0000) shr 8) or
    ((Hi and $0000FF00) shl 8) or (Hi shl 24);
  Int64Rec(Result).Lo := (Lo shr 24) or ((Lo and $00FF0000) shr 8) or
    ((Lo and $0000FF00) shl 8) or (Lo shl 24);
{$ELSEIF Defined(CPUX64)}
asm
  movsxd  rax, pos
  mov     rax, qword ptr [arr + rax]
  lea     ecx, [8*len]
  neg     cl
  shl     rax, cl
  bswap   rax
  {$ENDIF}
end;

{$IF Defined(CPUX64)}

function to_numASMPolesov(var arr; idx, cnt: integer): UInt64;
  assembler; register;
asm
  // если бы не требовалось получать результат по количеству байт,
  // то достаточно было бы следующих 2-х строк
  Add     RCX,   RDX
  Mov     RAX,   QWord Ptr [RCX]
  Bswap   RAX

  Cmp     R8,    01h
  Ja      @@02

  Mov     RCX,   00000000000000FFh
  Jmp     @@and

@@02:
  Cmp     R8,    02h
  Ja      @@03

  Mov     RCX,   000000000000FFFFh
  Jmp     @@and

@@03:
  Cmp     R8,    03h
  Ja      @@04

  Mov     RCX,   0000000000FFFFFFh
  Jmp     @@and

@@04:
  Cmp     R8,    04h
  Ja      @@05

  Mov     RCX,   00000000FFFFFFFFh
  Jmp     @@and

@@05:
  Cmp     R8,    05h
  Ja      @@06

  Mov     RCX,   000000FFFFFFFFFFh
  Jmp     @@and

@@06:
  Cmp     R8,    06h
  Ja      @@07

  Mov     RCX,   0000FFFFFFFFFFFFh
  Jmp     @@and

@@07:
  Cmp     R8,    07h
  Ja      @@ret

  Mov     RCX,   00FFFFFFFFFFFFFFh

@@and:
  And     RAX,   RCX

@@ret:
end;

function to_numBytePolesov(var arr; ofs, fin: integer): UInt64;
  assembler; register;
asm
  Push    RSI

  Mov     RSI,   RCX
  Add     RSI,   RDX

  Mov     RCX,   R8
  Sub     RCX,   RDX
  Inc     RCX
  Xor     RAX,   RAX

@@10:
  Shl     RAX,   08h
  LodsB
  Loop    @@10

  Pop     RSI
end;
{$ENDIF}
var
  arr: array [0 .. 15] of byte = (
    8,
    5,
    2,
    7,
    9,
    2,
    7,
    9,
    2,
    5,
    8,
    5,
    6,
    7,
    8,
    1
  );

var
  T, T1, T3: Int64;
  i, A: integer;

function sprintf(S: PAnsiChar; const Format: PAnsiChar): integer; cdecl;
  varargs; external 'msvcrt.dll';

function PrintTime(T: Int64): AnsiString;
var
  A, b: Int64;
begin
  Result := '';
  if QueryPerformanceCounter(A) and QueryPerformanceFrequency(b) then
  begin
    SetLength(Result, 25);
    SetLength(Result, sprintf(PAnsiChar(Result), '%f', single((A - T) / b)));
  end;
end;

procedure Test_to_num;
begin
  Writeln('Test_to_num');
  QueryPerformanceCounter(T1);
  for A := 1 to 3 do
  begin
    for i := 0 to 100000000 do
      to_num(arr, 5, 5 + 7);
  end;
  Writeln(PrintTime(T1));
end;

procedure Test_to_num2;
begin
  Writeln('Test_to_num2');
  QueryPerformanceCounter(T);
  for A := 1 to 3 do
  begin
    for i := 0 to 100000000 do
      Convert2(arr, 5, 7 + 1);
  end;
  Writeln(PrintTime(T));
end;

{$IF Defined(CPUX64)}

procedure Test_to_numASMPolesov;
begin
  Writeln('Test_to_numASMPolesov');

  QueryPerformanceCounter(T3);
  for A := 1 to 3 do
  begin
    for i := 0 to 100000000 do
      to_numASMPolesov(arr, 5, 8);
  end;
  Writeln(PrintTime(T3));
end;

procedure Test_to_numBytePolesov;
begin
  Writeln('Test_to_numBytePolesov');

  QueryPerformanceCounter(T3);
  for A := 1 to 3 do
  begin
    for i := 0 to 100000000 do
      to_numBytePolesov(arr, 5, 12);
  end;
  Writeln(PrintTime(T3));
end;

{$ENDIF}

begin
  try
{$IF Defined(CPUX64)}Test_to_numASMPolesov; {$ENDIF}
{$IF Defined(CPUX64)}Test_to_numBytePolesov; {$ENDIF}
    Test_to_num;
    Test_to_num2;
  except
    on e: Exception do
      Writeln(e.ClassName, ': ', e.Message);
  end;
  Readln;

end.



64bitTest_to_numASMPolesov - 2.202520Test_to_numBytePolesov - 6.208926Test_to_num - 2.531078Test_to_num2 - 0.900965


Ну вот если такие asm функции писать, то лучше их и вовсе не писать.


А так, вырванивание массива :) И мы не теряем 5.307961 сек
...
Рейтинг: 0 / 0
Ускорить функцию перевода массива байт в число
    #39929899
Картинка не в актуале, на неё не смотреть. Не нашёл как удалить её.
...
Рейтинг: 0 / 0
Ускорить функцию перевода массива байт в число
    #39929900
Polesov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ВсеРазумный,
Код: powershell
1.
Test_to_numBytePolesov - 6.208926


все дело в Shl RAX, 08h и использовании Loop
Да еще и побайтное чтение
...
Рейтинг: 0 / 0
Ускорить функцию перевода массива байт в число
    #39929917
Polesov,

Опа... Докатились.. Оптимизаторы Ассемблерные Мы с вами.....

Давайте больше не трогать ассемблер

В настройках проекта галочка оптимизации включена. Вставляем данный код
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.
251.
252.
253.
254.
255.
256.
257.
258.
259.
260.
261.
262.
263.
264.
265.
266.
267.
268.
269.
270.
271.
272.
273.
274.
275.
276.
277.
278.
279.
280.
281.
282.
283.
284.
285.
286.
287.
288.
289.
290.
291.
292.
293.
294.
program Project1;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  Winapi.Windows, System.SysUtils;

function FastConvertArrToUint64(const arr: array of byte;
  pos, len: integer): UInt64;
type
  TByteArray = array of byte;
var
  p: Pointer;
begin
  Result := 0;

  p := @arr[pos];

  case len - 1 of
    0:
      Result := (UInt64(TByteArray(p)[0]));
    1:
      Result := (UInt64(TByteArray(p)[1]) or (UInt64(TByteArray(p)[0]) shl 8));
    2:
      Result := (UInt64(TByteArray(p)[2]) or (UInt64(TByteArray(p)[1]) shl 8) or
        (UInt64(TByteArray(p)[0]) shl 16));
    3:
      Result := (UInt64(TByteArray(p)[3]) or (UInt64(TByteArray(p)[2]) shl 8) or
        (UInt64(TByteArray(p)[1]) shl 16) or (UInt64(TByteArray(p)[0]) shl 24));
    4:
      Result := (UInt64(TByteArray(p)[4]) or (UInt64(TByteArray(p)[3]) shl 8) or
        (UInt64(TByteArray(p)[2]) shl 16) or (UInt64(TByteArray(p)[1]) shl 24))
        or (UInt64(TByteArray(p)[0]) shl 32);
    5:
      Result := (UInt64(TByteArray(p)[5]) or (UInt64(TByteArray(p)[4]) shl 8) or
        (UInt64(TByteArray(p)[3]) shl 16) or (UInt64(TByteArray(p)[2]) shl 24))
        or (UInt64(TByteArray(p)[1]) shl 32) or
        (UInt64(TByteArray(p)[0]) shl 40);
    6:
      Result := (UInt64(TByteArray(p)[6]) or (UInt64(TByteArray(p)[5]) shl 8) or
        (UInt64(TByteArray(p)[4]) shl 16) or (UInt64(TByteArray(p)[3]) shl 24))
        or (UInt64(TByteArray(p)[2]) shl 32) or
        (UInt64(TByteArray(p)[1]) shl 40) or (UInt64(TByteArray(p)[0]) shl 48);
    7:
      Result := (UInt64(TByteArray(p)[7]) or (UInt64(TByteArray(p)[6]) shl 8) or
        (UInt64(TByteArray(p)[5]) shl 16) or (UInt64(TByteArray(p)[4]) shl 24))
        or (UInt64(TByteArray(p)[3]) shl 32) or
        (UInt64(TByteArray(p)[2]) shl 40) or (UInt64(TByteArray(p)[1]) shl 48)
        or (UInt64(TByteArray(p)[0]) shl 56);
  end;

end;

function to_num(const arr: array of byte; const i, j: integer): UInt64;
var
  k: integer;
begin
  Result := arr[i];
  for k := (i + 1) to j do
  begin
    Result := Result shl 8;
    Result := Result or arr[k];
  end;
end;

function Convert2(const arr: array of byte; pos, len: integer): UInt64;
{$IF Defined(CPUX86)}
var
  Lo, Hi: Cardinal;
begin
  Result := PUInt64(@arr[pos])^ shl (8 * (8 - len));

  Lo := Int64Rec(Result).Hi;
  Hi := Int64Rec(Result).Lo;
  Int64Rec(Result).Hi := (Hi shr 24) or ((Hi and $00FF0000) shr 8) or
    ((Hi and $0000FF00) shl 8) or (Hi shl 24);
  Int64Rec(Result).Lo := (Lo shr 24) or ((Lo and $00FF0000) shr 8) or
    ((Lo and $0000FF00) shl 8) or (Lo shl 24);
{$ELSEIF Defined(CPUX64)}
asm
  movsxd  rax, pos
  mov     rax, qword ptr [arr + rax]
  lea     ecx, [8*len]
  neg     cl
  shl     rax, cl
  bswap   rax
  {$ENDIF}
end;

{$IF Defined(CPUX64)}

function to_numASMPolesov(var arr; idx, cnt: integer): UInt64;
  assembler; register;
asm
  // если бы не требовалось получать результат по количеству байт,
  // то достаточно было бы следующих 2-х строк
  Add     RCX,   RDX
  Mov     RAX,   QWord Ptr [RCX]
  Bswap   RAX

  Cmp     R8,    01h
  Ja      @@02

  Mov     RCX,   00000000000000FFh
  Jmp     @@and

@@02:
  Cmp     R8,    02h
  Ja      @@03

  Mov     RCX,   000000000000FFFFh
  Jmp     @@and

@@03:
  Cmp     R8,    03h
  Ja      @@04

  Mov     RCX,   0000000000FFFFFFh
  Jmp     @@and

@@04:
  Cmp     R8,    04h
  Ja      @@05

  Mov     RCX,   00000000FFFFFFFFh
  Jmp     @@and

@@05:
  Cmp     R8,    05h
  Ja      @@06

  Mov     RCX,   000000FFFFFFFFFFh
  Jmp     @@and

@@06:
  Cmp     R8,    06h
  Ja      @@07

  Mov     RCX,   0000FFFFFFFFFFFFh
  Jmp     @@and

@@07:
  Cmp     R8,    07h
  Ja      @@ret

  Mov     RCX,   00FFFFFFFFFFFFFFh

@@and:
  And     RAX,   RCX

@@ret:
end;

function to_numBytePolesov(var arr; ofs, fin: integer): UInt64;
  assembler; register;
asm
  Push    RSI

  Mov     RSI,   RCX
  Add     RSI,   RDX

  Mov     RCX,   R8
  Sub     RCX,   RDX
  Inc     RCX
  Xor     RAX,   RAX

@@10:
  Shl     RAX,   08h
  LodsB
  Loop    @@10

  Pop     RSI
end;
{$ENDIF}
var
  arr: array [0 .. 15] of byte = (
    8,
    5,
    2,
    7,
    9,
    2,
    7,
    9,
    2,
    5,
    8,
    5,
    6,
    7,
    8,
    1
  );

var
  T, T1, T3: Int64;
  i, A: integer;

function sprintf(S: PAnsiChar; const Format: PAnsiChar): integer; cdecl;
  varargs; external 'msvcrt.dll';

function PrintTime(T: Int64): AnsiString;
var
  A, b: Int64;
begin
  Result := '';
  if QueryPerformanceCounter(A) and QueryPerformanceFrequency(b) then
  begin
    SetLength(Result, 25);
    SetLength(Result, sprintf(PAnsiChar(Result), '%f', single((A - T) / b)));
  end;
end;

procedure Test_to_num;
begin
  Writeln('Test_to_num');
  QueryPerformanceCounter(T1);
  for A := 1 to 3 do
  begin
    for i := 0 to 100000000 do
      to_num(arr, 5, 5 + 7);
  end;
  Writeln(PrintTime(T1));
end;

procedure Test_to_num2;
begin
  Writeln('Test_to_num2');
  QueryPerformanceCounter(T);
  for A := 1 to 3 do
  begin
    for i := 0 to 100000000 do
      Convert2(arr, 5, 7 + 1);
  end;
  Writeln(PrintTime(T));
end;

procedure Test_to_num3;
begin
  Writeln('FastConvertArrayToUint64');
  QueryPerformanceCounter(T);
  for A := 1 to 3 do
  begin
    for i := 0 to 100000000 do
      FastConvertArrToUint64(arr, 5, 7 + 1);
  end;
  Writeln(PrintTime(T));
end;

{$IF Defined(CPUX64)}

procedure Test_to_numASMPolesov;
begin
  Writeln('Test_to_numASMPolesov');

  QueryPerformanceCounter(T3);
  for A := 1 to 3 do
  begin
    for i := 0 to 100000000 do
      to_numASMPolesov(arr, 5, 8);
  end;
  Writeln(PrintTime(T3));
end;

procedure Test_to_numBytePolesov;
begin
  Writeln('Test_to_numBytePolesov');

  QueryPerformanceCounter(T3);
  for A := 1 to 3 do
  begin
    for i := 0 to 100000000 do
      to_numBytePolesov(arr, 5, 12);
  end;
  Writeln(PrintTime(T3));
end;

{$ENDIF}

begin
  try
{$IF Defined(CPUX64)}Test_to_numASMPolesov; {$ENDIF}
{$IF Defined(CPUX64)}Test_to_numBytePolesov; {$ENDIF}
    Test_to_num;
    Test_to_num2;
    Test_to_num3;
  except
    on e: Exception do
      Writeln(e.ClassName, ': ', e.Message);
  end;
  Readln;

end.



64 bitTest_to_numASMPolesov 2.276581Test_to_numBytePolesov 6.273596Test_to_num 2.559063Test_to_num2 0.910266FastConvertArrayToUint64 1.919095

32bitTest_to_num 11.720721Test_to_num2 3.017298FastConvertArrayToUint64 5.115628


То есть быстрее может и мой ASM но коль вы говорите что 1 раз 1000000000000000 может сработать av то лучший вариант FastConvertArrayToUint64
...
Рейтинг: 0 / 0
Ускорить функцию перевода массива байт в число
    #39929980
Но я всё равно рекомендую использовать свою функцию

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
program Project1;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  System.SysUtils;

function to_num(arr: array of byte; const i, j: integer): UInt64;
var
  k: integer;
begin
  Result := arr[i];
  for k := (i + 1) to j do
  begin
    Result := Result shl 8;
    Result := Result or arr[k];
  end;
end;

function Convert2(arr: array of byte; pos, len: integer): UInt64;
{$IF Defined(CPUX86)}
var
  Lo, Hi: Cardinal;
begin
  Result := PUInt64(@arr[pos])^ shl (8 * (8 - len));

  Lo := Int64Rec(Result).Hi;
  Hi := Int64Rec(Result).Lo;
  Int64Rec(Result).Hi := (Hi shr 24) or ((Hi and $00FF0000) shr 8) or
    ((Hi and $0000FF00) shl 8) or (Hi shl 24);
  Int64Rec(Result).Lo := (Lo shr 24) or ((Lo and $00FF0000) shr 8) or
    ((Lo and $0000FF00) shl 8) or (Lo shl 24);
{$ELSEIF Defined(CPUX64)}
asm
  movsxd  rax, pos
  mov     rax, qword ptr [arr + rax]
  lea     ecx, [8*len]
  neg     cl
  shl     rax, cl
  bswap   rax
  {$ENDIF}
end;

function to_num2(arr: array of byte; const i, j: integer): UInt64;
begin
  Result := Convert2(arr, i, j - i + 1);
end;

begin
  try

    Writeln('Фикс функции');

    Writeln(to_num([8, 5, 2, 7, 9, 2, 7, 9, 2, 5, 8, 5, 6, 7, 8, 1], 5, 5 + 2));

    Writeln('Новая функция Convert2');

    Writeln(to_num2([8, 5, 2, 7, 9, 2, 7, 9, 2, 5, 8, 5, 6, 7, 8, 1], 5, 5 + 2));

  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;

end.



Просто выделив на 8 элементов больше, и никогда их не использовать.
Код: pascal
1.
countElements := Length(arr) - 8; 
...
Рейтинг: 0 / 0
8 сообщений из 133, страница 6 из 6
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Ускорить функцию перевода массива байт в число
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]