powered by simpleCommunicator - 2.0.59     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Программирование [игнор отключен] [закрыт для гостей] / Ассемблер - регистры MMX - команды условного перехода.
25 сообщений из 225, страница 3 из 9
Ассемблер - регистры MMX - команды условного перехода.
    #39657499
Leonid Kudryavtsev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Кинь тогда хоть какие-то примерные входные данные и что должно получится.

На мой взгляд, код вполне можно упростить.
...
Рейтинг: 0 / 0
Ассемблер - регистры MMX - команды условного перехода.
    #39657502
Leonid Kudryavtsev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сорри, сразу не заметил

Контрольный пример: f(4294967337, 8589934591) = 1. Это числа длиной 33 бита.
...
Рейтинг: 0 / 0
Ассемблер - регистры MMX - команды условного перехода.
    #39657503
Aleksandr Sharahov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
AR®,

напрашивается декремент b вместо инкремента c
...
Рейтинг: 0 / 0
Ассемблер - регистры MMX - команды условного перехода.
    #39657510
AR®
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Aleksandr SharahovAR®, напрашивается декремент b вместо инкремента c

Пробовал. А точнее, был декремент c при начальном c = b:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
__int32 f(unsigned __int64 a, unsigned __int64 b)
{
	__int64 c = b;
	__int64 d = 1;

	do
	{
		__int64 e = -(d & 1);
		d >>= 1;
		d ^= e & a;
		c--;
	}
	while (d != 1 && c != 0);
                                                        
	return (d == 1 && c == 0) ? 1 : 0;	// если выполнились одновременно оба условия, достаточных для выхода из цикла, возвращаем 1, иначе 0
}



Результат был хуже на ~5%.
...
Рейтинг: 0 / 0
Ассемблер - регистры MMX - команды условного перехода.
    #39657512
AR®
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Leonid KudryavtsevНа мой взгляд, код вполне можно упростить.
Буду благодарен.
Но у меня теперь большие сомнения в этом.
...
Рейтинг: 0 / 0
Ассемблер - регистры MMX - команды условного перехода.
    #39657513
Aleksandr Sharahov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
маска e = -(d & 1) может иметь всего два значения (-1 или 0) в зависимости от младшего бита d

соответственно e & a может иметь 2 значения (a или 0) в зависимости от младшего бита d

поэтому для вычисления этого выражения проще всего использовать условную пересылку после проверки бита d
...
Рейтинг: 0 / 0
Ассемблер - регистры MMX - команды условного перехода.
    #39657516
Aleksandr Sharahov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
AR®Aleksandr SharahovAR®, напрашивается декремент b вместо инкремента c

Пробовал. А точнее, был декремент c при начальном c = b:

Результат был хуже на ~5%.

нафига тут вообще нужна доп. переменная с?
...
Рейтинг: 0 / 0
Ассемблер - регистры MMX - команды условного перехода.
    #39657533
Leonid Kudryavtsev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Aleksandr Sharahovмаска e = -(d & 1) может иметь всего два значения (-1 или 0) в зависимости от младшего бита d

соответственно e & a может иметь 2 значения (a или 0) в зависимости от младшего бита d

поэтому для вычисления этого выражения проще всего использовать условную пересылку после проверки бита d
I think so

+ вместо __int64 для цикла, можно использовать два вложенных цикла по __int32. Максимум избавиться от арифметики над __int64
...
Рейтинг: 0 / 0
Ассемблер - регистры MMX - команды условного перехода.
    #39657543
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Я так понимаю это обращение к памяти, если использовать регистр проца, то быстрее должно стать
AR®
Код: plaintext
1.
2.
3.
	and	esi, DWORD PTR _a$[ebp]

	and	edi, DWORD PTR _a$[ebp+4]


У меня вот во что откомпилировалось
MSVC 2015 Release x64
Код: 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.
int main() {
000000013F892420  sub         rsp,28h  
	int x = f(4294967337, 8589934591);
000000013F892424  mov         r9d,1  
	int x = f(4294967337, 8589934591);
000000013F89242A  xor         r8d,r8d  
000000013F89242D  mov         edx,r9d  
000000013F892430  mov         r11,100000029h  
000000013F89243A  mov         r10,1FFFFFFFFh  
000000013F892444  nop         dword ptr [rax]  
000000013F892448  nop         dword ptr [rax+rax]  
000000013F892450  mov         rcx,rdx  
000000013F892453  mov         rax,rdx  
000000013F892456  and         ecx,r9d  
000000013F892459  shr         rax,1  
000000013F89245C  dec         rcx  
000000013F89245F  inc         r8  
000000013F892462  and         rcx,r11  
000000013F892465  mov         rdx,rcx  
000000013F892468  xor         rdx,rax  
000000013F89246B  cmp         rdx,r9  
000000013F89246E  je          main+57h (013F892477h)  
000000013F892470  cmp         r8,r10  
000000013F892473  jne         main+30h (013F892450h)  
000000013F892475  jmp         main+5Ch (013F89247Ch)  
000000013F892477  cmp         r8,r10  
000000013F89247A  je          main+5Fh (013F89247Fh)  
000000013F89247C  xor         r9d,r9d  

	printf("%d\n", x);
...


Время 9.3 сек. на i7-6700K

Если не секрет - в чем суть этого цикла? что он делает? Может алгоритм можно сменить?
...
Рейтинг: 0 / 0
Ассемблер - регистры MMX - команды условного перехода.
    #39657563
AR®
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Aleksandr Sharahovнафига тут вообще нужна доп. переменная с?

Для её инкремента от 0 до b, т.к. вариант с декрементом оказался медленнее, хотя и не очень сильно.
...
Рейтинг: 0 / 0
Ассемблер - регистры MMX - команды условного перехода.
    #39657564
Leonid Kudryavtsev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
AR®Leonid KudryavtsevНа мой взгляд, код вполне можно упростить.
Буду благодарен.
Но у меня теперь большие сомнения в этом.
Дай еще каких нибудь циферек для проверки.
А то я в циклах запустался )))

твой код 23-24 с., мой вариант 18 сек

ассемблер не смотрел. На C давно не программировал (лет 12), т.ч. извеняюсь за говно-код и плохое оформление)))


Код: 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.
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.
#include <QCoreApplication>

#include <windows.h>

__int32 f(unsigned __int64 a, unsigned __int64 b)
{
    __int64 c = 0;
    __int64 d = 1;

    do
    {
        __int64 e = -(d & 1);
        d >>= 1;
        d ^= e & a;
        c++;
    }
    while (d != 1 && c != b);

    printf( "d=%llu  c=%llu  a=%llu    b=%llu\n", d, c, a, b );

    return (d == 1 && c == b) ? 1 : 0;	// если выполнились одновременно оба условия, достаточных для выхода из цикла, возвращаем 1, иначе 0
}

__int32 f2(unsigned __int64 a, unsigned __int64 b)
{
    unsigned __int64 flags[2] = {0,a};
    __int64 c = 0;
    __int64 d = 1;
    unsigned __int64 *e_ptr;

    unsigned int count1;
    unsigned int count2;
    // Избавляемся от in64 счетчика цикла, заменяем просто на
    // два вложенных цикла
    unsigned int i1;
    unsigned int i2;

    count1 = b >> 32;
    count2 = b & 0xFFFFFFFF;
    // Цикл по старшему значению
    for ( i1=count1; i1 > 0;  ) {
        // Здесь мы должны повторить 0x10000000, но это уже не умешается в 32 разряда )))
        for ( i2=0xFFFFFFFF; i2 > 0;  ) {
            // __int64 e = -(d & 1);
            e_ptr = flags + ( d & 1 );
            d >>= 1;
            d ^= *e_ptr;
            i2--;
            // прерываем цикл если d == 1
            if ( d==1 ) {
                goto m_exit;
            }
        }
        // Нужен еще одна лишняя интерация. что бы кол-во интераций было 0x10000000
        // __int64 e = -(d & 1);
        e_ptr = flags + ( d & 1 );
        d >>= 1;
        d ^= *e_ptr;
        i1--;
        // прерываем цикл если d == 1
        if ( d==1 ) {
            goto m_exit;
        }
    }
    for ( i2=count2; i2 > 0; ) {
        // __int64 e = -(d & 1);
        e_ptr = flags + ( d & 1 );
        // заменяем
        d >>= 1;
        d ^= *e_ptr;
        i2--;
        // прерываем цикл если d == 1
        if ( d==1 ) {
            goto m_exit;
        }
    }
m_exit:

    printf( "i1=%i   i2=%i\n", i1, i2 );
    printf( "d=%llu  c=%llu  a=%llu    b=%llu\n", d, c, a, b );
    return (d == 1 && (i1==0 && i2==0) ) ? 1 : 0;	// если выполнились одновременно оба условия, достаточных для выхода из цикла, возвращаем 1, иначе 0
}



int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    __int32 res;
    DWORD start, end;

    start = GetTickCount();
    res = f(4294967337, 8589934591);
    end = GetTickCount();
    printf( "f=%i time=%i\n", res, (end-start) );

    start = GetTickCount();
    res = f2(4294967337, 8589934591);
    end = GetTickCount();
    printf( "f2=%i time=%i\n", res, (end-start) );

    return a.exec();
}



Код: sql
1.
2.
3.
4.
5.
d=1  c=8589934591  a=4294967337    b=8589934591
f=1 time=23078
i1=0   i2=0
d=1  c=0  a=4294967337    b=8589934591
f2=1 time=18688


...
Рейтинг: 0 / 0
Ассемблер - регистры MMX - команды условного перехода.
    #39657566
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Aleksandr Sharahovмаска e = -(d & 1) может иметь всего два значения (-1 или 0) в зависимости от младшего бита d

соответственно e & a может иметь 2 значения (a или 0) в зависимости от младшего бита d

поэтому для вычисления этого выражения проще всего использовать условную пересылку после проверки бита d
Затестил. Втрое медленнее как ни странно
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
	do
	{
		int e = (d & 1);
		d >>= 1;
		if(e) d ^= a;
		c++;
	} while (d != 1 && c != b);
...
Рейтинг: 0 / 0
Ассемблер - регистры MMX - команды условного перехода.
    #39657571
AR®
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Leonid Kudryavtsev+ вместо __int64 для цикла, можно использовать два вложенных цикла по __int32. Максимум избавиться от арифметики над __int64

Мы избавлены от неё 32-битным компилятором. Напомню, что всё делается на 32-битном компе. И два 32-битных счётчика нам организовал сам компилятор. В случае инкремента так:
Код: plaintext
1.
2.
	add	edx, 1
	adc	esi, 0



А в случае декремента так:
Код: plaintext
1.
2.
	add	edx, -1
	adc	esi, -1



Последнее оказалось немного медленнее (почему?).
...
Рейтинг: 0 / 0
Ассемблер - регистры MMX - команды условного перехода.
    #39657577
Leonid Kudryavtsev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Тут между командами взаимозависимость по регистру флагов. Т.е. теоретически "плохо". Но теоретически, практически там возможны исчезающие доли процентов
...
Рейтинг: 0 / 0
Ассемблер - регистры MMX - команды условного перехода.
    #39657586
AR®
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Leonid KudryavtsevДай еще каких нибудь циферек для проверки.
А то я в циклах запустался )))

f(6777995264, 8589934591) = 1
f(5033164800, 8589934591) = 1

Второе число не трогайте (это маска 33 бита == 1), а первое можете уменьшить-увеличить на 1, функция должна вернуть 0.
...
Рейтинг: 0 / 0
Ассемблер - регистры MMX - команды условного перехода.
    #39657599
AR®
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TЗатестил. Втрое медленнее как ни странно
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
	do
	{
		int e = (d & 1);
		d >>= 1;
		if(e) d ^= a;
		c++;
	} while (d != 1 && c != b);



Это не странно.
Первоначальный алгоритм содержал if / else, а затем от них избавились путём подбора масок (000..00 и 111..11), позволяющих всегда делать одинаковые действия.
...
Рейтинг: 0 / 0
Ассемблер - регистры MMX - команды условного перехода.
    #39657601
Aleksandr Sharahov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TAleksandr Sharahovмаска e = -(d & 1) может иметь всего два значения (-1 или 0) в зависимости от младшего бита d

соответственно e & a может иметь 2 значения (a или 0) в зависимости от младшего бита d

поэтому для вычисления этого выражения проще всего использовать условную пересылку после проверки бита d
Затестил. Втрое медленнее как ни странно
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
	do
	{
		int e = (d & 1);
		d >>= 1;
		if(e) d ^= a;
		c++;
	} while (d != 1 && c != b);



Ну так компилер не такой же умный, чтоб понять, что о от него требуется
надо что-то вроде этого
e=0;
if (d and 1) e=a;
d^=e;
или сразу всю функцию на асме с условной пересылкой написать
...
Рейтинг: 0 / 0
Ассемблер - регистры MMX - команды условного перехода.
    #39657605
AR®
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TУ меня вот во что откомпилировалось

Так это всё под x64.
...
Рейтинг: 0 / 0
Ассемблер - регистры MMX - команды условного перехода.
    #39657608
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
В продолжение 21476642 добавлю x32 вариант, тут тоже нет обращений к памяти внутри цикла
Так компилируется в x32
Код: 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.
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.
__int32 f(unsigned __int64 a, unsigned __int64 b)
{
00A92260  push        ebp  
00A92261  mov         ebp,esp  
00A92263  sub         esp,0Ch  
00A92266  push        ebx  
00A92267  push        esi  
00A92268  xorps       xmm0,xmm0  
	__int64 c = 0;
	__int64 d = 1;
00A9226B  mov         esi,1  
00A92270  movlpd      qword ptr [ebp-8],xmm0  
00A92275  xor         eax,eax  
00A92277  mov         ebx,dword ptr [c]  
00A9227A  push        edi  
00A9227B  mov         edi,dword ptr [ebp-4]  
00A9227E  xchg        ax,ax  

	do
	{
		__int64 e = -(d & 1);
00A92280  mov         edx,esi  
00A92282  xor         ecx,ecx  
00A92284  and         edx,1  
		d >>= 1;
		d ^= e & a;
00A92287  neg         edx  
		d >>= 1;
		d ^= e & a;
00A92289  adc         ecx,ecx  
00A9228B  and         edx,29h  
00A9228E  shrd        esi,eax,1  
00A92292  neg         ecx  
00A92294  and         ecx,1  
00A92297  sar         eax,1  
00A92299  xor         esi,edx  
00A9229B  xor         eax,ecx  
		c++;
00A9229D  add         ebx,1  
00A922A0  adc         edi,0  
	} while (d != 1 && c != b);
00A922A3  cmp         esi,1  
00A922A6  jne         f+4Ch (0A922ACh)  
00A922A8  test        eax,eax  
00A922AA  je          f+5Fh (0A922BFh)  
00A922AC  cmp         ebx,0FFFFFFFFh  
00A922AF  jne         f+20h (0A92280h)  
00A922B1  cmp         edi,1  
00A922B4  jne         f+20h (0A92280h)  

	return (d == 1 && c == b) ? 1 : 0;	// если выполнились одновременно оба условия, достаточных для выхода из цикла, возвращаем 1, иначе 0
00A922B6  xor         eax,eax  
}
00A922B8  pop         edi  
00A922B9  pop         esi  
00A922BA  pop         ebx  
00A922BB  mov         esp,ebp  
00A922BD  pop         ebp  
00A922BE  ret  

	return (d == 1 && c == b) ? 1 : 0;	// если выполнились одновременно оба условия, достаточных для выхода из цикла, возвращаем 1, иначе 0
00A922BF  cmp         ebx,0FFFFFFFFh  
00A922C2  jne         f+56h (0A922B6h)  
00A922C4  cmp         edi,1  
00A922C7  jne         f+56h (0A922B6h)  
00A922C9  mov         eax,edi  
}
00A922CB  pop         edi  
00A922CC  pop         esi  
00A922CD  pop         ebx  
00A922CE  mov         esp,ebp  
00A922D0  pop         ebp  
00A922D1  ret  


13.7 сек
...
Рейтинг: 0 / 0
Ассемблер - регистры MMX - команды условного перехода.
    #39657615
AR®
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Aleksandr SharahovНу так компилер не такой же умный, чтоб понять, что от него требуется
Мне теперь кажется, что он даже умнее, чем просто чтоб понять, что от него требуется. :)

Aleksandr Sharahovсразу всю функцию на асме с условной пересылкой написать
Писал (как вставку в C) 3 версии, все работают дольше, чем "компиляторская". :)
...
Рейтинг: 0 / 0
Ассемблер - регистры MMX - команды условного перехода.
    #39657625
Aleksandr Sharahov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
AR®Aleksandr SharahovНу так компилер не такой же умный, чтоб понять, что от него требуется
Мне теперь кажется, что он даже умнее, чем просто чтоб понять, что от него требуется. :)

Aleksandr Sharahovсразу всю функцию на асме с условной пересылкой написать
Писал (как вставку в C) 3 версии, все работают дольше, чем "компиляторская". :)

с использованием CMOV получилось медленнее? не верю )
...
Рейтинг: 0 / 0
Ассемблер - регистры MMX - команды условного перехода.
    #39657630
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Aleksandr SharahovНу так компилер не такой же умный, чтоб понять, что о от него требуется
надо что-то вроде этого
e=0;
if (d and 1) e=a;
d^=e;
или сразу всю функцию на асме с условной пересылкой написать
тоже тормоз
Код: plaintext
1.
2.
3.
4.
		__int64 e = 0;
		if(d & 1) e = a;
		d >>= 1;
		d ^= e;
...
Рейтинг: 0 / 0
Ассемблер - регистры MMX - команды условного перехода.
    #39657634
AR®
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TВ продолжение 21476642 добавлю x32 вариант, тут тоже нет обращений к памяти внутри цикла
Так компилируется в x32
Очень интересно. Особенно, в чём глубокий смысл "and edx, 29h "?
...
Рейтинг: 0 / 0
Ассемблер - регистры MMX - команды условного перехода.
    #39657638
Aleksandr Sharahov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TAleksandr SharahovНу так компилер не такой же умный, чтоб понять, что о от него требуется
надо что-то вроде этого
e=0;
if (d and 1) e=a;
d^=e;
или сразу всю функцию на асме с условной пересылкой написать
тоже тормоз
Код: plaintext
1.
2.
3.
4.
		__int64 e = 0;
		if(d & 1) e = a;
		d >>= 1;
		d ^= e;



Интересно, а
if(d & 1) e = a;
компилируется с переходом или с CMOV'ом?
...
Рейтинг: 0 / 0
Ассемблер - регистры MMX - команды условного перехода.
    #39657644
AR®
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima Tтоже тормоз
Код: plaintext
1.
2.
3.
4.
		__int64 e = 0;
		if(d & 1) e = a;
		d >>= 1;
		d ^= e;



Не мучайтесь. :)
Разные варианты этого алгоритма с ветвлениями были испытаны, и все были в 2-3 раза медленнее. Причём это верно и для чисел до 32 бит (когда всё без __int64).
...
Рейтинг: 0 / 0
25 сообщений из 225, страница 3 из 9
Форумы / Программирование [игнор отключен] [закрыт для гостей] / Ассемблер - регистры MMX - команды условного перехода.
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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