проблема: у процессора нет команды целочисленного деления (FPU тоже нет)
как реализовать деление на 24, чтобы оно работало быстро (так чтобы, можно было
пользоваться им внутри длинных циклов).
умножение на 24 реализуется просто: a * 24 = a*(8 + 16), т.е. два сдвига:
b = a << 3; // a*8
res = b + (b << 1); // res = a*8 + a*16
хотелось бы что нибудь подобное для операции деления на эту константу.
Здравствуйте, Тимошенко Антон Валентинович, Вы писали:
ТАВ>проблема: у процессора нет команды целочисленного деления (FPU тоже нет) ТАВ>как реализовать деление на 24, чтобы оно работало быстро (так чтобы, можно было ТАВ>пользоваться им внутри длинных циклов). ТАВ>умножение на 24 реализуется просто: a * 24 = a*(8 + 16), т.е. два сдвига:
ТАВ>b = a << 3; // a*8 ТАВ>res = b + (b << 1); // res = a*8 + a*16
ТАВ>хотелось бы что нибудь подобное для операции деления на эту константу.
а в итоге деления что ты хочешь получить?
у меня есть подозрение что всё таки деление целочисленное...то есть если два числа целое и результирующее тооже целое тот деление будет токо до запятой проводиться....(во всяком случае я всегда на это надеюсь)
Здравствуйте, IceLoveR, Вы писали:
ILR>Здравствуйте, Тимошенко Антон Валентинович, Вы писали:
ТАВ>>проблема: у процессора нет команды целочисленного деления (FPU тоже нет) ТАВ>>как реализовать деление на 24, чтобы оно работало быстро (так чтобы, можно было ТАВ>>пользоваться им внутри длинных циклов). ТАВ>>умножение на 24 реализуется просто: a * 24 = a*(8 + 16), т.е. два сдвига:
ТАВ>>b = a << 3; // a*8 ТАВ>>res = b + (b << 1); // res = a*8 + a*16
ТАВ>>хотелось бы что нибудь подобное для операции деления на эту константу. ILR>а в итоге деления что ты хочешь получить?
ILR>25/24 что будет?
я хочу целочисленное деление с остатком.
25/24 = 1, остаток 1
смысл — вычисление индекса в массиве (матрице), который представляет
равномерное разбиение пространства на блоки размером 24. Остаток от деления = координата точки внутри блока.
Так что нужны оба эти числа. Раньше я работал с блоком размером 16, так тут все решалось простым сдвигом (целая часть)
и маскированием младших 4 битов (остаток). Теперь нужен блок размером 24...
Здравствуйте, Тимошенко Антон Валентинович, Вы писали:
ТАВ>проблема: у процессора нет команды целочисленного деления (FPU тоже нет)
Те пишешь под какуюто странную железку?
Незнаю поможет или нет но вот что VC++8 нагенерил из этого кода
__declspec(noinline)
unsigned int get()
{
return GetTickCount() % 123;
}
__declspec(noinline)
void print(unsigned int i, unsigned int j, unsigned int k)
{
std::cout << i << " " << j << " " << k;
}
int main()
{
unsigned int i = get();
unsigned int j = i / 24;
unsigned int k = i % 24;
print(i, j, k);
return 0;
}
;тут в esi исходное число
mov eax, -1431655765 ; aaaaaaabH
mul esi
mov ecx, edx
shr ecx, 4
;тут в ecx получается частное
lea eax, DWORD PTR [ecx+ecx*2]
add eax, eax
add eax, eax
add eax, eax
;тут в eax получается частное*24
;единственное чего я не понял это почему в место одного
;shl eax, 3
;использованы 3
;add eax, eax
;??? Ктонибудь это может объяснить? Можут тут какоето хитрое спаривание комманд?
;или это по томучто VC++8.0 beta 1 и просто не всех тараканов из оптимизатора выловили?
mov edx, eax
mov eax, esi
sub eax, edx;тут в eax получается остаток
... << RSDN@Home 1.1.4 beta 3 rev. 185>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
WolfHound wrote: > > ;единственное чего я не понял это почему в место одного > ;shl eax, 3 > ;использованы 3 > ;add eax, eax > ;??? Ктонибудь это может объяснить? Можут тут какоето хитрое спаривание комманд? > ;или это по томучто VC++8.0 beta 1 и просто не всех тараканов из оптимизатора выловили?
Хмм.. вопрос интересный. Есть подозрение что "shl eax, 3" скорее всего
равно "eax * 8" в то время как "3 add eax, eax" == "shl eax, 1.5" (точно
не помню, проверьте пожалуйста).
Ну и add для П4 это дешево, он их может делать несколько штук за такт.
Кроме того есть подозрение что команда кодирует аргументы "в себе" и
процесору будет быстрее ее парсить, размер опкода тоже должен быть
поменьше других команд подхлдящих для этой цели. Вообщем лутше пока ниче
нет для умножения на 3.
Здравствуйте, Тимошенко Антон Валентинович, Вы писали:
ТАВ>проблема: у процессора нет команды целочисленного деления (FPU тоже нет) ТАВ>как реализовать деление на 24, чтобы оно работало быстро (так чтобы, можно было
В общем, вот что получилось. Использована идея с умножением на 0x5555. Умножение реализовано через сдвиги. Правда (любимый) компилятор от МС заменил все наши старания на imul (гад!). А IC оставил как есть, и дернул МС почти на 1 сек.
#include <iostream>
#include <cstdlib>
#include <ctime>
#define NOMINMAX
#include <windows.h>
int Add[48], Mod[48];
void Fill()
{
int i;
for( i = 0; i<24; ++i )
{
Add[i] = 0;
Mod[i] = i;
}
for( i = 0; i<24; ++i )
{
Add[i+24] = 1;
Mod[i+24] = i;
}
}
inline void Magic( int n, int &a, int &b )
{
a = n;
a = (a<<2)+a;
a = (a<<4)+a;
a = (a<<8)+a;
a >>= 19;
b = a<<3;
b += (b<<1);
b = n-b;
a += Add[b];
b = Mod[b];
}
int main()
{
Fill();
srand( time( NULL ) );
int n, a, b, res = 0, time = ::GetTickCount();
for( n = 100000000; n>=0; --n )
{
Magic( rand()*2+rand(), a, b );
res += (a+b);
}
std::cout << res << std::endl;
std::cout << (::GetTickCount()-time)/1000.0 << std::endl;
return 0;
}