Для тестов использовался LPC1758, разогнанный до 100МГц. Отвлекающих от вычислений факторов нет, кроме таймера, отсчитывающего миллисекунды.
CODE
uint32_t sqrt1 (uint32_t L)
{
int32_t temp, div;
uint32_t rslt = L;
if (L <= 0) return 0;
else if (L & 0xFFFF0000L)
if (L & 0xFF000000L)
div = 0x3FFF;
else
div = 0x3FF;
else
if (L & 0x0FF00L) div = 0x3F;
else div = (L > 4) ? 0x7 : L;
while (1)
{
temp = L/div + div;
div = temp >> 1;
div += temp & 1;
if (rslt > div) rslt = (uint32_t)div;
else
{
if (L/rslt == rslt-1 && L%rslt==0) rslt--;
return rslt;
}
}
}
uint32_t sqrt2 (uint32_t src)
{
uint32_t wrk;
uint32_t dst;
int i;
dst = 0x8000;
wrk = 0x8000;
for(i=0; i<16; i++)
{
if(dst*dst>src) dst &= ~wrk;
wrk >>= 1;
dst |= wrk;
}
return dst;
}
uint32_t sqrt3 (uint32_t src)
{
uint32_t mask, sqr = 0, temp;
int j=16;
temp = 0xC0000000;
do {
if( src & temp ) break;
temp>>=2;
} while( --j);
if( j==0 ) return 0;
mask = temp & (temp>>1);
do {
temp = sqr | mask;
sqr >>= 1;
if( temp <= src ) {
sqr |= mask;
src -= temp;
}
mask >>= 2;
} while( --j );
return sqr;
}
uint32_t sqrt4 (uint32_t Val)
{
unsigned int bitSqr = 0x40000000;
unsigned int root = 0;
while (bitSqr != 0)
{
if (Val >= (bitSqr + root))
{
Val = Val - (bitSqr + root);
root = (root >> 1) | bitSqr;
}
else
root = (root >> 1);
bitSqr = (bitSqr >> 2);
}
return(root);
}
int TestSqrt(uint32_t(*func)(uint32_t))
{
tick_count_t starttime = get_tick_count();
for (uint32_t i = 0; i < 10000000; i++) {
uint32_t s = func(i);
//Check the value
uint32_t sq = s * s;
if (!((sq == i) ||
(sq > i) && (s-1)*(s-1) < i ||
(sq < i) && (s+1)*(s+1) > i))
{
while (1);
}
}
return get_tick_count() - starttime;
}
{
int32_t temp, div;
uint32_t rslt = L;
if (L <= 0) return 0;
else if (L & 0xFFFF0000L)
if (L & 0xFF000000L)
div = 0x3FFF;
else
div = 0x3FF;
else
if (L & 0x0FF00L) div = 0x3F;
else div = (L > 4) ? 0x7 : L;
while (1)
{
temp = L/div + div;
div = temp >> 1;
div += temp & 1;
if (rslt > div) rslt = (uint32_t)div;
else
{
if (L/rslt == rslt-1 && L%rslt==0) rslt--;
return rslt;
}
}
}
uint32_t sqrt2 (uint32_t src)
{
uint32_t wrk;
uint32_t dst;
int i;
dst = 0x8000;
wrk = 0x8000;
for(i=0; i<16; i++)
{
if(dst*dst>src) dst &= ~wrk;
wrk >>= 1;
dst |= wrk;
}
return dst;
}
uint32_t sqrt3 (uint32_t src)
{
uint32_t mask, sqr = 0, temp;
int j=16;
temp = 0xC0000000;
do {
if( src & temp ) break;
temp>>=2;
} while( --j);
if( j==0 ) return 0;
mask = temp & (temp>>1);
do {
temp = sqr | mask;
sqr >>= 1;
if( temp <= src ) {
sqr |= mask;
src -= temp;
}
mask >>= 2;
} while( --j );
return sqr;
}
uint32_t sqrt4 (uint32_t Val)
{
unsigned int bitSqr = 0x40000000;
unsigned int root = 0;
while (bitSqr != 0)
{
if (Val >= (bitSqr + root))
{
Val = Val - (bitSqr + root);
root = (root >> 1) | bitSqr;
}
else
root = (root >> 1);
bitSqr = (bitSqr >> 2);
}
return(root);
}
int TestSqrt(uint32_t(*func)(uint32_t))
{
tick_count_t starttime = get_tick_count();
for (uint32_t i = 0; i < 10000000; i++) {
uint32_t s = func(i);
//Check the value
uint32_t sq = s * s;
if (!((sq == i) ||
(sq > i) && (s-1)*(s-1) < i ||
(sq < i) && (s+1)*(s+1) > i))
{
while (1);
}
}
return get_tick_count() - starttime;
}
Проверка с бесконечным циклом ни на одном алгоритме не сработала - все вычислялось четко.
Результаты замеров в миллисекундах приведены ниже. В скобках приведено время вычисления без проверки правильности, только вычисление корня в цикле.
sqrt1() - 0x349d (0x296d)
sqrt2() - 0x4286 (0x3986)
sqrt3() - 0x4807 (0x3cca)
sqrt4() - 0x4933 (0x44df)
Явный лидер - sqrt1(). Получается, что среднее время вычисления кв. корня около 1 микросекунды. Алгоритм взят отсюда
Меня результат вполне устраивает, но если у кого-то есть другие интересные алгоритмы, давайте и их проверим. Интересно же найти лучший.