powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Программирование [игнор отключен] [закрыт для гостей] / IntToPChar на ASM для DELPHI
25 сообщений из 54, страница 2 из 3
IntToPChar на ASM для DELPHI
    #39380088
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Aleksandr Sharahov1. Заменить деление умножением, умножать на обратный.
Путаешь. Вычитание можно заменить на сложение с обратным, но к делению это неприменимо.
Aleksandr Sharahov2. Заменить деление вычитанием, делить в столбик.
Быстрее не станет, слишком много операций.
...
Рейтинг: 0 / 0
IntToPChar на ASM для DELPHI
    #39380097
Midgard90
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
На похмельную голову вышло как-то так:
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
function Int64ToText(Arg: PAnsiChar; Value: Int64):integer; assembler;
var
  Ch2 : array [0..10] of Char;
  PCh1,Pch2 :PAnsiChar;
  Val : int64;
  part, n, count1,count2: integer;
begin
  Ch2 := ('          ');
  val := value;
  PCh2 := @Ch2;
  part := val mod 1000000000;
  n := val div 1000000000;
  Count1 := intToText(Arg,n);
  Count2 := intToText(PCh2,abs(part));
  Result := Count1 + Count2;
  StrCopy(StrEnd(Arg), PCh2);
end;



Сама IntToText(та самая самоделка):
Код: 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.
function IntToText(Arg: PAnsiChar; Value: Integer):integer; assembler;
asm
//Подготовка:
    push eax
    push ebx
    push ecx
    push edx
    push esi
    mov esi,eax
    mov eax,edx
    mov ebx,10               //;В BX делитель (10 для десятичной системы)
    xor ecx,ecx               //;Обнуление CX
    mov byte [esi],0
//Проверяем знак:
    test eax,eax              //;Проверка знака AX
    jns @wtsds_no_sign       //;Если >= 0, преобразуем как беззнаковое
    mov byte[esi],'-'        //;Добавление знака в начало строки
    inc esi                  //;Инкремент DI
    neg eax                  //;Изменение знака значения AX
@wtsds_no_sign:
@wtuds_lp1:                  //;Цикл получения остатков от деления
    xor edx,edx               //;Обнуление старшей части двойного слова
    div ebx                  //;Деление AX=(DX:AX)/BX, остаток в DX
    add dl,'0'              //;Преобразование остатка в код символа
    push edx                 //;Сохранение в стеке
    inc ecx                  //;Увеличение счетчика символов
    test eax,eax              //;Проверка AX
    jnz @wtuds_lp1           //;Переход к началу цикла, если частное не 0.
    mov Result,ecx
@wtuds_lp2:                  //;Цикл извлечения символов из стека
    pop edx                  //;Восстановление символа из стека
    mov [esi],edx             //;Сохранение символа в буфере
    inc esi                  //;Инкремент адреса буфера
    loop @wtuds_lp2          //;Команда цикла
    pop esi
    pop edx
    pop ecx
    pop ebx
    pop eax
end;



Погонял на числах, вроде работает. По скорости отпишу после 9го числа, все тесты на работе)
Всем спасибо за советы! Код ещё в порядок надо будет привести и сделать owerlode, но это мелочи.
Ещё раз благодарен всем за помощь! и с прошедшими и наступающими)
...
Рейтинг: 0 / 0
IntToPChar на ASM для DELPHI
    #39380098
Aleksandr Sharahov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TAleksandr Sharahov1. Заменить деление умножением, умножать на обратный.
Путаешь. Вычитание можно заменить на сложение с обратным, но к делению это неприменимо.


Не путаю.
1. Можно погуглить на тему "замена целочисленного деления умножением" или глянуть Уоррена, например.
2. Можно посмотреть, во что преобразует деление на 10 любой сишный компилятор.
3. До кучи тут есть немного http://guildalfa.ru/alsha/node/31
...
Рейтинг: 0 / 0
IntToPChar на ASM для DELPHI
    #39380105
Aleksandr Sharahov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Midgard90,

внезапно переполнение:

val : int64;
n : integer;
n := val div 1000000000;
...
Рейтинг: 0 / 0
IntToPChar на ASM для DELPHI
    #39380111
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Посмотрел во что мой код скомпилировался, похоже компилятор MSVС сам заменил деление
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
		itoa_d(buf, i);
000A1C42  mov         ecx,edi  
		itoa_d(buf, i);
000A1C44  mov         esi,0Ah  
000A1C49  nop         dword ptr [eax]  
000A1C50  mov         eax,0CCCCCCCDh  
000A1C55  dec         esi  
000A1C56  mul         eax,ecx  
000A1C58  shr         edx,3  
000A1C5B  mov         al,dl  
000A1C5D  shl         al,2  
000A1C60  lea         ebx,[eax+edx]  
000A1C63  add         bl,bl  
000A1C65  sub         cl,bl  
000A1C67  add         cl,30h  
000A1C6A  mov         byte ptr buf[esi],cl  
000A1C6E  mov         ecx,edx  
000A1C70  test        esi,esi  
000A1C72  jne         test+40h (0A1C50h)
		if(atoi(buf) != i) {
...
Рейтинг: 0 / 0
IntToPChar на ASM для DELPHI
    #39380118
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: plaintext
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.
typedef uint32_t fix4_28;
void itoaZ(char *buf, uint64_t val)
{
	fix4_28 const f1_10000 = (1 << 28) / 10000;
	fix4_28 tmp0, tmp1, tmp2, tmp3;

	uint32_t v0 = val % 100000;
	uint32_t v1 = (val / 100000) % 100000;
	uint32_t v2 = (val / 10000000000) % 100000;;
	uint32_t v3 = (val / 1000000000000000) % 100000;;

	tmp0 = v0 * (f1_10000 + 1) - (v0 / 4);
	tmp1 = v1 * (f1_10000 + 1) - (v1 / 4);
	tmp2 = v2 * (f1_10000 + 1) - (v2 / 4);
	tmp3 = v3 * (f1_10000 + 1) - (v3 / 4);

	for (size_t i = 0; i < 5; i++)
	{
		buf[i + 0] = '0' + (char)(tmp3 >> 28);
		buf[i + 5] = '0' + (char)(tmp2 >> 28);
		buf[i + 10] = '0' + (char)(tmp1 >> 28);
		buf[i + 15] = '0' + (char)(tmp0 >> 28);
		tmp0 = (tmp0 & 0x0fffffff) * 10;
		tmp1 = (tmp1 & 0x0fffffff) * 10;
		tmp2 = (tmp2 & 0x0fffffff) * 10;
		tmp3 = (tmp3 & 0x0fffffff) * 10;
	}
}


аргумент беззнаковый, на выходе лидирующие нули
...
Рейтинг: 0 / 0
IntToPChar на ASM для DELPHI
    #39380120
Midgard90
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Странно) скорее всего старая дельфа топорная, потому как в их исходниках IntToStr похожий код с делением, что на выходе в асме не смотрел, но работает. В новой всё заменено уже сями и fastcall, да и работать в новой проще.

Насчёт переполнения думаю не проблема, разбить не на 2 а на 4 части и каждую прогнать, потом сложить PCharы. Конечный вариант кину после 9го) работы для праздников хватит))
...
Рейтинг: 0 / 0
IntToPChar на ASM для DELPHI
    #39380222
Midgard90
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
погонял. переполнения не встретил. приведи пример?
...
Рейтинг: 0 / 0
IntToPChar на ASM для DELPHI
    #39380237
Пётр Седов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Aleksandr SharahovПётр СедовЕсли Delphi-йский компилятор для кода типа «n mod 10 ... n div 10» генерирует 2 инструкции div, то да :).
если немного подумать, а не переводить стрелки на компилятор, то легко понять, что есть алгоритм с одним делением:
d:=n div 10;
r:=n - d * 10;Деление, умножение, вычитание. Три операции в машинном коде. При том, что достаточно одной, потому что x86-инструкция div выдаёт 2 результата: частное (в регистре eax) и остаток (в регистре edx), и хороший оптимизирующий компилятор должен этим пользоваться. Ну это как для кода «cos(x) ... sin(x)» генерировать одну инструкцию fsincos. Или для кода «(n << 16) | (n >> 16)» генерировать одну инструкцию циклического сдвига. А так-то понятно, что руками много чего можно сделать, например беззнаковое деление на степень двойки заменить на битовый сдвиг.

Aleksandr SharahovПётр СедовМне удалось разбить только на 3 части.
если проявить смекалку, например, перейти к беззнаковым числам и поработать со старшими битами и с обратными числами, то удается получить 2 части.int64 (максимум 19 цифр) можно разбить на 3 части (9 цифр, 9 цифр, 1 цифра) или на 4 части (5 цифр, 5 цифр, 5 цифр, 4 цифры). А на 2 части как разбить? (чтобы каждая часть гарантированно влезала в 32 бита)

ИзопропилПётр Седов
Код: pascal
1.
2.
// если что-то осталось
      // дописываем вторую часть, чтобы было ровно 9 цифр


этого можно избежать изначально заполнив весь буфер нулямиДа, но длинные последовательности нулей редко встречаются, так что этим особо не ускоримся.

Изопропил
Код: plaintext
1.
void itoaZ(char *buf, uint64_t val)

Проверил, работает правильно. Пара мелочей:

Изопропил
Код: plaintext
1.
	uint32_t v3 = (val / 1000000000000000) % 100000;;

Похоже, не нужно.

Если работаем со строками в C-шном стиле, то хорошо бы писать завершающий нулевой char:
Код: plaintext
1.
2.
3.
4.
5.
void itoaZ(char *buf, uint64_t val)
{
	...
	buf[20] = '\0';
}


Я переписал ваш код на Pascal:
Код: 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.
type
  fix4_28 = cardinal;

const
  f1_10000: fix4_28 = (1 shl 28) div 10000;

function int32_to_text_fix(buf: pchar; buf_len: integer; value: integer): integer;
const
  buf2_len = 11; // самое длинное, что может быть -- это '-2147483648' = -pow(2, 31)
var
  buf2: array [0 .. buf2_len - 1] of char;
  abs_value: cardinal;
  v0, v1: cardinal;
  tmp0, tmp1: fix4_28;
  i, p, result_len: integer;
begin
  // считаем abs(value)
  if value >= 0 then begin
    abs_value := value;
  end else begin
    abs_value := cardinal(-(value + 1)) + 1; // единицы, чтобы не было переполнения, когда value = -2147483648
  end;

  // разбиваем число на 2 части, по 5 цифр в каждой
  v0 := abs_value mod 100000;
  v1 := abs_value div 100000;

  tmp0 := v0 * (f1_10000 + 1) - (v0 shr 2);
  tmp1 := v1 * (f1_10000 + 1) - (v1 shr 2);
  for i := 0 to 4 do begin
    buf2[i + 1] := chr(ord('0') + byte(tmp1 shr 28));
    buf2[i + 6] := chr(ord('0') + byte(tmp0 shr 28));
    tmp0 := (tmp0 and $0fffffff) * 10;
    tmp1 := (tmp1 and $0fffffff) * 10;
  end;

  // пропускаем начальные нули
  p := 1;
  while (p < 10) and (buf2[p] = '0') do begin
    inc(p);
  end;

  if value < 0 then begin
    dec(p);
    buf2[p] := '-';
  end;

  result_len := buf2_len - p;
  if result_len <= buf_len then begin
    move(buf2[p], buf^, result_len);
    result := result_len;
  end else begin
    result := -1;
  end;
end;

function int64_to_text_fix(buf: pchar; buf_len: integer; value: int64): integer;
const
  buf2_len = 20; // самое длинное, что может быть -- это '-9223372036854775808' = -pow(2, 63)
var
  buf2: array [0 .. buf2_len - 1] of char;
  abs_value: int64; // в Delphi 7 нет uint64
  v0, v1, v2, v3: cardinal;
  tmp0, tmp1, tmp2, tmp3: fix4_28;
  i, p, result_len: integer;
begin
  // считаем abs(value)
  if value >= 0 then begin
    abs_value := value;
  end else begin
    // hardcode для минимального значения, потому что не можем сделать '-value'
    if value = -9223372036854775807 - 1 then begin
      result_len := 20;
      if result_len <= buf_len then begin
        move('-9223372036854775808', buf^, result_len);
        result := result_len;
      end else begin
        result := -1;
      end;
      exit;
    end;
    abs_value := -value;
  end;

  // разбиваем число на 4 части, по 5 цифр в каждой
  v0 := abs_value mod 100000;
  v1 := (abs_value div 100000) mod 100000;
  v2 := (abs_value div 10000000000) mod 100000;
  v3 := abs_value div 1000000000000000;

  tmp0 := v0 * (f1_10000 + 1) - (v0 shr 2);
  tmp1 := v1 * (f1_10000 + 1) - (v1 shr 2);
  tmp2 := v2 * (f1_10000 + 1) - (v2 shr 2);
  tmp3 := v3 * (f1_10000 + 1) - (v3 shr 2);
  for i := 0 to 4 do begin
    buf2[i + 0] := chr(ord('0') + byte(tmp3 shr 28));
    buf2[i + 5] := chr(ord('0') + byte(tmp2 shr 28));
    buf2[i + 10] := chr(ord('0') + byte(tmp1 shr 28));
    buf2[i + 15] := chr(ord('0') + byte(tmp0 shr 28));
    tmp0 := (tmp0 and $0fffffff) * 10;
    tmp1 := (tmp1 and $0fffffff) * 10;
    tmp2 := (tmp2 and $0fffffff) * 10;
    tmp3 := (tmp3 and $0fffffff) * 10;
  end;

  // пропускаем начальные нули
  assert(buf2[0] = '0');
  p := 1;
  while (p < 19) and (buf2[p] = '0') do begin
    inc(p);
  end;

  if value < 0 then begin
    dec(p);
    buf2[p] := '-';
  end;

  result_len := buf2_len - p;
  if result_len <= buf_len then begin
    move(buf2[p], buf^, result_len);
    result := result_len;
  end else begin
    result := -1;
  end;
end;


Midgard90погонял. переполнения не встретил. приведи пример?Ваш код:
Midgard90
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
function Int64ToText(...; Value: Int64) ...
var
  ...
  Val : int64;
  ..., n, ...: integer;
begin
  ...
  val := value;
  ...
  n := val div 1000000000;
  ...
end;

Если value = val = 9223372036854775807 (максимальное значение), то:
val div 1000000000 = 9223372036 -- не влезает в integer (максимальное значение -- 2147483647). И в cardinal тоже не влезает (максимальное значение -- 4294967295).
...
Рейтинг: 0 / 0
IntToPChar на ASM для DELPHI
    #39380247
Aleksandr Sharahov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Пётр СедовДеление, умножение, вычитание. Три операции в машинном коде. При том, что достаточно одной, потому что x86-инструкция div выдаёт 2 результата: частное (в регистре eax) и остаток (в регистре edx)

Ты же понимаешь, что мое замечание касалось ненужности второго деления в твоем коде?
И компилятор тут ни при чем.

На самом деле не нужно и первое деление. Или нужно, но другое.

Пётр Седовint64 (максимум 19 цифр) можно разбить на 3 части (9 цифр, 9 цифр, 1 цифра) или на 4 части (5 цифр, 5 цифр, 5 цифр, 4 цифры). А на 2 части как разбить? (чтобы каждая часть гарантированно влезала в 32 бита)


Идея в том, чтобы отделить часть работы,
которая формально соответствует очень маленькой третьей части данных,
и выполнить эту часть работы независимо от обработки двух других больших кусков.

Ну, когда, например, мы обрабатываем знак числа, мы же не называем это третьей частью данных,
хотя формально так оно и есть.
...
Рейтинг: 0 / 0
IntToPChar на ASM для DELPHI
    #39380262
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: plaintext
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.
void _ui64toa10( uint64_t const val,char *  obuf )
{
	uint32_t const f1_10001 = (1 << 28) / 10000 + 1;
	uint32_t tmp0, tmp1, tmp2, tmp3;
	char buf[21];

	uint64_t _vr,_vq;
	_vq = val / 10000000000;
	_vr = val % 10000000000;
	uint32_t v0 = _vr % 100000;
	uint32_t v1 = _vr / 100000;
	uint32_t v2 = _vq % 100000;
	uint32_t v3 = _vq / 100000;
	
	tmp0 = v0 * (f1_10001)-(v0 >> 2);
	tmp1 = v1 * (f1_10001)-(v1 >> 2);
	tmp2 = v2 * (f1_10001)-(v2 >> 2);
	tmp3 = v3 * (f1_10001)-(v3 >> 2);

	for (size_t i = 0; i < 5; i++) { buf[i     ] = '0' | (char)(tmp3 >> 28); tmp3 = (tmp3 & 0x0fffffff) * 10; }
	for (size_t i = 0; i < 5; i++) { buf[i + 5 ] = '0' | (char)(tmp2 >> 28); tmp2 = (tmp2 & 0x0fffffff) * 10; }
	for (size_t i = 0; i < 5; i++) { buf[i + 10] = '0' | (char)(tmp1 >> 28); tmp1 = (tmp1 & 0x0fffffff) * 10; }
	for (size_t i = 0; i < 5; i++) { buf[i + 15] = '0' | (char)(tmp0 >> 28); tmp0 = (tmp0 & 0x0fffffff) * 10; }

	buf[20] = 0;
	char  *p = buf;
	while (p < buf+19 && *p == '0')p++;
	memcpy(obuf, p, buf + 21 - p);
}



быстрее, чем библиотечный _ui64toa

глядя на ассемблерное порождение - сильно больше на 32 бит x86 - вряд ли получится выжать

Код: sql
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.
; Function compile flags: /Ogtp
; File c:\vc\consoleapplication4\consoleapplication4\consoleapplication4.cpp
;	COMDAT ?_ui64toa10@@YAX_KPAD@Z
_TEXT	SEGMENT
_buf$ = -28						; size = 21
_obuf$1$ = -4						; size = 4
_val$ = 8						; size = 8
_tmp0$1$ = 12						; size = 4
_v2$1$ = 12						; size = 4
?_ui64toa10@@YAX_KPAD@Z PROC				; _ui64toa10, COMDAT
; _obuf$ = ecx

; 239  : {

	push	ebp
	mov	ebp, esp
	sub	esp, 28					; 0000001cH
	push	ebx
	push	esi
	push	edi
	push	ebx

; 240  : 	uint32_t const f1_10001 = (1 << 28) / 10000 + 1;
; 241  : 	uint32_t tmp0, tmp1, tmp2, tmp3;
; 242  : 	char buf[21];
; 243  : 
; 244  : 	uint64_t _vr,_vq;
; 245  : 	_vq = val / 10000000000;

	push	2
	push	1410065408				; 540be400H
	push	DWORD PTR _val$[ebp+4]
	mov	DWORD PTR _obuf$1$[ebp], ecx
	push	DWORD PTR _val$[ebp]
	call	__aulldvrm
	mov	esi, ebx
	pop	ebx

; 246  : 	_vr = val % 10000000000;
; 247  : 	uint32_t v0 = _vr % 100000;

	push	0
	push	100000					; 000186a0H
	mov	ebx, ecx
	mov	DWORD PTR _v2$1$[ebp], eax
	push	esi
	push	ebx
	mov	edi, edx
	call	__aulldiv

; 248  : 	uint32_t v1 = _vr / 100000;
; 249  : 	uint32_t v2 = _vq % 100000;

	push	0
	mov	esi, eax
	imul	ecx, esi, 100000
	push	100000					; 000186a0H
	push	edi
	mov	edi, DWORD PTR _v2$1$[ebp]
	push	edi
	sub	ebx, ecx
	call	__aulldiv
	imul	ecx, eax, 100000
	sub	edi, ecx

; 250  : 	uint32_t v3 = _vq / 100000;
; 251  : 	
; 252  : 	tmp0 = v0 * (f1_10001)-(v0 >> 2);

	imul	ecx, ebx, 26844
	shr	ebx, 2

; 253  : 	tmp1 = v1 * (f1_10001)-(v1 >> 2);
; 254  : 	tmp2 = v2 * (f1_10001)-(v2 >> 2);

	imul	edx, edi, 26844
	shr	edi, 2
	sub	ecx, ebx
	imul	ebx, esi, 26844
	mov	DWORD PTR _tmp0$1$[ebp], ecx

; 255  : 	tmp3 = v3 * (f1_10001)-(v3 >> 2);

	imul	ecx, eax, 26844
	sub	edx, edi
	shr	eax, 2
	shr	esi, 2
	sub	ebx, esi
	sub	ecx, eax

; 256  : 
; 257  : 	for (size_t i = 0; i < 5; i++) { buf[i     ] = '0' | (char)(tmp3 >> 28); tmp3 = (tmp3 & 0x0fffffff) * 10; }

	mov	eax, ecx
	and	ecx, 268435455				; 0fffffffH
	shr	eax, 28					; 0000001cH
	or	al, 48					; 00000030H
	mov	BYTE PTR _buf$[ebp], al
	lea	ecx, DWORD PTR [ecx+ecx*4]
	add	ecx, ecx
	mov	eax, ecx
	and	ecx, 268435455				; 0fffffffH
	shr	eax, 28					; 0000001cH
	or	al, 48					; 00000030H
	mov	BYTE PTR _buf$[ebp+1], al
	lea	ecx, DWORD PTR [ecx+ecx*4]
	add	ecx, ecx
	mov	eax, ecx
	and	ecx, 268435455				; 0fffffffH
	shr	eax, 28					; 0000001cH
	or	al, 48					; 00000030H
	mov	BYTE PTR _buf$[ebp+2], al
	lea	ecx, DWORD PTR [ecx+ecx*4]
	add	ecx, ecx
	mov	eax, ecx
	and	ecx, 268435455				; 0fffffffH
	shr	eax, 28					; 0000001cH
	or	al, 48					; 00000030H
	mov	BYTE PTR _buf$[ebp+3], al
	lea	eax, DWORD PTR [ecx+ecx*4]
	add	eax, eax
	shr	eax, 28					; 0000001cH
	or	al, 48					; 00000030H
	mov	BYTE PTR _buf$[ebp+4], al

; 258  : 	for (size_t i = 0; i < 5; i++) { buf[i + 5 ] = '0' | (char)(tmp2 >> 28); tmp2 = (tmp2 & 0x0fffffff) * 10; }

	mov	eax, edx
	shr	eax, 28					; 0000001cH
	or	al, 48					; 00000030H
	and	edx, 268435455				; 0fffffffH
	mov	BYTE PTR _buf$[ebp+5], al
	lea	ecx, DWORD PTR [edx+edx*4]
	add	ecx, ecx
	mov	eax, ecx
	and	ecx, 268435455				; 0fffffffH
	shr	eax, 28					; 0000001cH
	or	al, 48					; 00000030H
	mov	BYTE PTR _buf$[ebp+6], al
	lea	ecx, DWORD PTR [ecx+ecx*4]
	add	ecx, ecx
	mov	eax, ecx
	and	ecx, 268435455				; 0fffffffH
	shr	eax, 28					; 0000001cH
	or	al, 48					; 00000030H
	mov	BYTE PTR _buf$[ebp+7], al
	lea	ecx, DWORD PTR [ecx+ecx*4]
	add	ecx, ecx
	mov	eax, ecx
	and	ecx, 268435455				; 0fffffffH
	shr	eax, 28					; 0000001cH
	or	al, 48					; 00000030H
	mov	BYTE PTR _buf$[ebp+8], al
	lea	eax, DWORD PTR [ecx+ecx*4]
	add	eax, eax
	shr	eax, 28					; 0000001cH
	or	al, 48					; 00000030H
	mov	BYTE PTR _buf$[ebp+9], al

; 259  : 	for (size_t i = 0; i < 5; i++) { buf[i + 10] = '0' | (char)(tmp1 >> 28); tmp1 = (tmp1 & 0x0fffffff) * 10; }

	mov	eax, ebx
	shr	eax, 28					; 0000001cH
	and	ebx, 268435455				; 0fffffffH
	or	al, 48					; 00000030H
	mov	BYTE PTR _buf$[ebp+10], al
	lea	ecx, DWORD PTR [ebx+ebx*4]
	add	ecx, ecx
	mov	eax, ecx
	and	ecx, 268435455				; 0fffffffH
	shr	eax, 28					; 0000001cH
	or	al, 48					; 00000030H
	mov	BYTE PTR _buf$[ebp+11], al
	lea	ecx, DWORD PTR [ecx+ecx*4]
	add	ecx, ecx
	mov	eax, ecx
	and	ecx, 268435455				; 0fffffffH
	shr	eax, 28					; 0000001cH
	or	al, 48					; 00000030H
	mov	BYTE PTR _buf$[ebp+12], al
	lea	ecx, DWORD PTR [ecx+ecx*4]
	add	ecx, ecx
	mov	eax, ecx
	and	ecx, 268435455				; 0fffffffH
	shr	eax, 28					; 0000001cH
	or	al, 48					; 00000030H
	mov	BYTE PTR _buf$[ebp+13], al
	lea	eax, DWORD PTR [ecx+ecx*4]

; 260  : 	for (size_t i = 0; i < 5; i++) { buf[i + 15] = '0' | (char)(tmp0 >> 28); tmp0 = (tmp0 & 0x0fffffff) * 10; }

	mov	ecx, DWORD PTR _tmp0$1$[ebp]
	add	eax, eax
	shr	eax, 28					; 0000001cH
	or	al, 48					; 00000030H
	mov	BYTE PTR _buf$[ebp+14], al
	mov	eax, ecx
	and	ecx, 268435455				; 0fffffffH
	shr	eax, 28					; 0000001cH
	or	al, 48					; 00000030H
	mov	BYTE PTR _buf$[ebp+15], al
	lea	ecx, DWORD PTR [ecx+ecx*4]
	add	ecx, ecx
	mov	eax, ecx
	and	ecx, 268435455				; 0fffffffH
	shr	eax, 28					; 0000001cH
	or	al, 48					; 00000030H
	mov	BYTE PTR _buf$[ebp+16], al
	lea	ecx, DWORD PTR [ecx+ecx*4]
	add	ecx, ecx
	mov	eax, ecx
	and	ecx, 268435455				; 0fffffffH
	shr	eax, 28					; 0000001cH
	or	al, 48					; 00000030H
	mov	BYTE PTR _buf$[ebp+17], al
	lea	ecx, DWORD PTR [ecx+ecx*4]
	add	ecx, ecx
	mov	eax, ecx
	shr	eax, 28					; 0000001cH
	or	al, 48					; 00000030H

; 261  : 
; 262  : 	buf[20] = 0;

	mov	BYTE PTR _buf$[ebp+20], 0
	and	ecx, 268435455				; 0fffffffH
	mov	BYTE PTR _buf$[ebp+18], al
	lea	eax, DWORD PTR [ecx+ecx*4]
	add	eax, eax
	shr	eax, 28					; 0000001cH
	or	al, 48					; 00000030H
	mov	BYTE PTR _buf$[ebp+19], al

; 263  : 	char  *p = buf;

	lea	eax, DWORD PTR _buf$[ebp]
$LL14@ui64toa10:

; 264  : 	while (p < buf+19 && *p == '0')p++;

	cmp	BYTE PTR [eax], 48			; 00000030H
	jne	SHORT $LN15@ui64toa10
	inc	eax
	lea	ecx, DWORD PTR _buf$[ebp+19]
	cmp	eax, ecx
	jb	SHORT $LL14@ui64toa10
$LN15@ui64toa10:

; 265  : 	memcpy(obuf, p, buf + 21 - p);

	lea	ecx, DWORD PTR _buf$[ebp+21]
	sub	ecx, eax
	push	ecx
	push	eax
	push	DWORD PTR _obuf$1$[ebp]
	call	_memcpy
	add	esp, 12					; 0000000cH

; 266  : }

	pop	edi
	pop	esi
	pop	ebx
	mov	esp, ebp
	pop	ebp
	ret	0
?_ui64toa10@@YAX_KPAD@Z ENDP				; _ui64toa10
_TEXT	ENDS

...
Рейтинг: 0 / 0
IntToPChar на ASM для DELPHI
    #39380388
__Avenger__
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Еще можно itoa и atoi собрать в obj файл на с++ и затем использовать в проекте на Delphi.
...
Рейтинг: 0 / 0
IntToPChar на ASM для DELPHI
    #39380392
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
__Avenger__в obj файл на с++
что означает этот набор слов?
...
Рейтинг: 0 / 0
IntToPChar на ASM для DELPHI
    #39380394
__Avenger__
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Изопропил__Avenger__в obj файл на с++
что означает этот набор слов?

Скомпилировать c++ файл в obj файл, а затем использовать его в delphi через директиву {$LINK *.obj}. ZLib так например в дельфи подключен.
...
Рейтинг: 0 / 0
IntToPChar на ASM для DELPHI
    #39380395
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
__Avenger__Изопропилпропущено...

что означает этот набор слов?

Скомпилировать c++ файл в obj файл, а затем использовать его в delphi через директиву {$LINK *.obj}. ZLib так например в дельфи подключен.
ну лучше С, а не С++ и внимательно следить чтоб из рантайма лишку не зацепить.

проще dll сделать
...
Рейтинг: 0 / 0
IntToPChar на ASM для DELPHI
    #39380416
Пётр Седов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Изопропил
Код: plaintext
1.
2.
3.
4.
	uint64_t ...,_vq;
	...
	uint32_t v2 = _vq % 100000;
	uint32_t v3 = _vq / 100000;

Код: sql
1.
2.
3.
4.
5.
6.
7.
; 249  : 	uint32_t v2 = _vq % 100000;
	...
	call	__aulldiv
	imul	ecx, eax, 100000
	sub	edi, ecx

; 250  : 	uint32_t v3 = _vq / 100000;

Visual C++ сгенерировал такой код, как предлагал Aleksandr Sharahov: деление, умножение, вычитание. Хотя вполне мог сгенерировать код типа:
edx:eax ← _vq
div 100000
v3 ← eax (частное)
v2 ← edx (остаток)

Изопропил
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
	tmp0 = v0 * (f1_10001)-(v0 >> 2);
	tmp1 = v1 * (f1_10001)-(v1 >> 2);
	tmp2 = v2 * (f1_10001)-(v2 >> 2);
	tmp3 = v3 * (f1_10001)-(v3 >> 2);

	for (size_t i = 0; i < 5; i++) { buf[i     ] = '0' | (char)(tmp3 >> 28); tmp3 = (tmp3 & 0x0fffffff) * 10; }
	for (size_t i = 0; i < 5; i++) { buf[i + 5 ] = '0' | (char)(tmp2 >> 28); tmp2 = (tmp2 & 0x0fffffff) * 10; }
	for (size_t i = 0; i < 5; i++) { buf[i + 10] = '0' | (char)(tmp1 >> 28); tmp1 = (tmp1 & 0x0fffffff) * 10; }
	for (size_t i = 0; i < 5; i++) { buf[i + 15] = '0' | (char)(tmp0 >> 28); tmp0 = (tmp0 & 0x0fffffff) * 10; }

...
глядя на ассемблерное порождение - сильно больше на 32 бит x86 - вряд ли получится выжатьТут одинаковые операции делаются, поэтому если писать на ассемблере, то можно попытаться ускориться за счёт использования MMX-инструкций, которые работают с 32-битными числами, упакованными в 64-битные регистры:
paddd -- делает параллельно два сложения
psubd -- делает параллельно два вычитания
pslld -- делает параллельно два битовых сдвига влево
psrld -- делает параллельно два битовых сдвига вправо
pand -- делает параллельно два битовых and (на самом деле, просто 64-битный and)
А вот умножения нормального нет, поэтому умножение на f1_10001 придётся делать обычными инструкциями, а умножение на 10 заменить на «(n << 3) + (n << 1)». Кстати, Visual C++ умножение на 10 делает так:
Изопропил
Код: sql
1.
2.
	lea	ecx, DWORD PTR [ecx+ecx*4]
	add	ecx, ecx


Изопропил
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
; 263  : 	char  *p = buf;

	lea	eax, DWORD PTR _buf$[ebp]
$LL14@ui64toa10:

; 264  : 	while (p < buf+19 && *p == '0')p++;

	cmp	BYTE PTR [eax], 48			; 00000030H
	jne	SHORT $LN15@ui64toa10
	inc	eax
	lea	ecx, DWORD PTR _buf$[ebp+19]
	cmp	eax, ecx
	jb	SHORT $LL14@ui64toa10
$LN15@ui64toa10:

Зачем Visual C++ делает «ecx ← buf + 19» на каждой итерации цикла? Это достаточно сделать один раз до цикла. А если писать на ассемблере самому, то тут вообще, насколько я понимаю, весь цикл можно записать одной инструкцией: repe scasb.

Изопропилбыстрее, чем библиотечный _ui64toaКруто.
...
Рейтинг: 0 / 0
IntToPChar на ASM для DELPHI
    #39380424
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Пётр СедовVisual C++ сгенерировал такой код, как предлагал Aleksandr Sharahov: деление, умножение, вычитание. Хотя вполне мог сгенерировать код типа:
edx:eax ← _vq
div 100000
v3 ← eax (частное)
v2 ← edx (остаток)

uint64/uint32 - частное может не уместиться в uint32,
потому нельзя одной командой, переполнение может случиться - потому - деление "столбиком"
(см исходники ulldiv.asm, ulldrvm.asm)

Пётр СедовЗачем Visual C++ делает «ecx ← buf + 19» на каждой итерации цикла?
inc и lea выполнятся одновременно, потери производительности не будет, хотя действительно странно.
...
Рейтинг: 0 / 0
IntToPChar на ASM для DELPHI
    #39380429
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SSE2 версия
Код: plaintext
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.
static inline __m128i _mm_mullo_epi32emu(const __m128i &a, const __m128i &b)
{
	__m128i tmp1 = _mm_mul_epu32(a, b); /* mul 2,0*/
	__m128i tmp2 = _mm_mul_epu32(_mm_srli_si128(a, 4), _mm_srli_si128(b, 4)); /* mul 3,1 */
	return _mm_unpacklo_epi32(_mm_shuffle_epi32(tmp1, _MM_SHUFFLE(0, 0, 2, 0)), _mm_shuffle_epi32(tmp2, _MM_SHUFFLE(0, 0, 2, 0))); /* shuffle results to [63..0] and pack */
}

void _ui64toa10m(const uint64_t  val, char *obuf )
{
	int32_t const f1_10001 = (1 << 28) / 10000 + 1;

	uint64_t _vr, _vq;
	_vq = val / 10000000000;
	_vr = val % 10000000000;
	uint32_t v0 = _vr % 100000;
	uint32_t v1 = _vr / 100000;
	uint32_t v2 = _vq % 100000;
	uint32_t v3 = _vq / 100000;

	char buf[21];
	__m128i v = _mm_set_epi32(v3, v2, v1, v0);
	__m128i tmp = _mm_sub_epi32(_mm_mullo_epi32emu(v, _mm_set1_epi32(f1_10001)), _mm_srai_epi32(v, 2));

	for (size_t i = 0; i < 5; i++)
	{
		__m128i tmps = _mm_add_epi32(_mm_and_si128(_mm_srai_epi32(tmp, 28), _mm_set1_epi32(0xf)), _mm_set1_epi32('0'));
		buf[i + 0] = tmps.m128i_u32[3];
		buf[i + 5] = tmps.m128i_u32[2];
		buf[i + 10] = tmps.m128i_u32[1];
		buf[i + 15] = tmps.m128i_u32[0];
		tmp = _mm_mullo_epi32emu(_mm_and_si128(tmp, _mm_set1_epi32(0x0fffffff)), _mm_set1_epi32(10));
	}
	buf[20] = 0;
	char  *p = buf;
	while (p < buf + 19 && *p == '0')p++;
	memcpy(obuf, p, buf + 21 - p);
}



не ускоряет ( по крайней мере на тех CPU, что использовал)

а что до "крутости" - _ui64toa работает с произвольным основанием системы счисления и скорость зависит от количества цифр, возня может иметь смысл, если часто преобразовывать большие числа приходится.

в конечном итоге - преобразование двоичного в десятичное вряд ли является узким местом.
...
Рейтинг: 0 / 0
IntToPChar на ASM для DELPHI
    #39380430
Siemargl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Если нужно обрабатывать многоцифр, то нужно их обрабатывать параллельно.

И добро пожаловать в волшебный мир SIMD.

Остальное пырхание не стоит внимания.
...
Рейтинг: 0 / 0
IntToPChar на ASM для DELPHI
    #39380435
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SiemarglИ добро пожаловать в волшебный мир SIMD.
он не настолько волшебен, как иногда кажется.

ускорь _ui64toa с помощью SSE4, а там и будем выводы делать
...
Рейтинг: 0 / 0
IntToPChar на ASM для DELPHI
    #39380486
Midgard90
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Таак... с переполнением разобрался, потом нашёл ещё несколько багов: прошлая функция не дописывала нули, например:
9000000001000000001 на выходе 911)). В общем вышло как-то так:
Код: 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.
function Int64ToText(Arg: PAnsiChar; Value: Int64):integer; assembler;
var
  Ch1,Ch2,Ch3,Ch1_old,Ch2_old : array [0..10] of Char;
  PCh1,Pch2,PCh3,PCh1_old,PCh2_old :PAnsiChar;
  Val,n : int64;
  count, part : integer;
begin
  Ch1 := ('');
  Ch2 := ('');
  Ch3 := ('');
  Ch1_old := ('');
  Ch2_old := ('');
  val := value;
  PCh1 := @Ch1;
  PCh2 := @Ch2;
  PCh3 := @Ch3;
  PCh1_old := @Ch1_old;
  PCh2_old := @Ch2_old;
  Result := 0;
  if val < 0 then begin
    StrCopy(Arg,'-');
  end;
  //первая часть
  if (val <> 0) then begin
    part := val mod 1000000000;
    n := val div 1000000000;
    Count := IntToText(PCh1,abs(part));
    if (abs(part) < 1000000000)and(n<>0) then begin
      while Count < 9 do begin
        StrCopy(StrEnd(Pch1_old), '0');
        Inc(Count);
      end;
    end;
    StrCopy(StrEnd(Pch1_old), PCh1);

    Result := Result + Count;
  end;
  //Вторая часть
  if n <> 0 then begin
    part := n mod 1000000000;
    n := n div 1000000000;
    Count := IntToText(PCh2,abs(part));
    if (abs(part) < 1000000000)and(n<>0) then begin
      while Count < 9 do begin
        StrCopy(StrEnd(Pch2_old), '0');
        Inc(Count);
      end;
    end;
    StrCopy(StrEnd(Pch2_old), PCh2);
    Result := Result + Count;
  end;
  //третья часть
  if n <> 0 then begin
  part := n mod 10;
  Count := IntToText(PCh3,abs(part));
  Result := Result + Count;
  end;
  StrCopy(StrEnd(Arg), PCh3);
  StrCopy(StrEnd(Arg), PCh2_old);
  StrCopy(StrEnd(Arg), PCh1_old);

end;


Не думаю теперь что она быстрее IntToStr или предложенной ранее чисто дельфийской)) Завтра на скорость будем тестить с профитом по ядрам. Как её укоротить или оптимизировать уже что-то не соображаю. И масса локальных напрягает. Не функция а костыль, но работает)) Если есть мысли, с удовольствием выслушаю, как её сделать красивши)
...
Рейтинг: 0 / 0
IntToPChar на ASM для DELPHI
    #39380488
Midgard90
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Да, забыл, IntToText() осталась прежней, чисто асемблер, как и кидал ранее.
...
Рейтинг: 0 / 0
IntToPChar на ASM для DELPHI
    #39380516
Siemargl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ИзопропилSiemarglИ добро пожаловать в волшебный мир SIMD.
он не настолько волшебен, как иногда кажется.

ускорь _ui64toa с помощью SSE4, а там и будем выводы делатьТы не понял идею. Нужно не одно число переводить, а пачку.
Т.е. _ui64toa(const uint64_t val[4],.....)
...
Рейтинг: 0 / 0
IntToPChar на ASM для DELPHI
    #39380523
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Siemargl,

у интела в SIMD уже появилось деление 64 битных целых ?
...
Рейтинг: 0 / 0
IntToPChar на ASM для DELPHI
    #39380588
Siemargl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ИзопропилSiemargl,

у интела в SIMD уже появилось деление 64 битных целых ?Эмм, не нашел. Там простого деления я совсем не наблюдаю, только алгоритмами.

Но оно не требуется. Нам нужно деление с остатком 64бит на 32бит.
Оно реализуется 32-битными операциями, например так div_s64_rem()
http://lxr.free-electrons.com/source/lib/div64.c
...
Рейтинг: 0 / 0
25 сообщений из 54, страница 2 из 3
Форумы / Программирование [игнор отключен] [закрыт для гостей] / IntToPChar на ASM для DELPHI
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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