реклама на сайте
подробности

 
 
> Очень нужна помощь в оптимизации алгоритма извлечения квадратного корня
Rostislav
сообщение Dec 4 2012, 22:16
Сообщение #1


Частый гость
**

Группа: Участник
Сообщений: 127
Регистрация: 6-07-08
Из: Москва
Пользователь №: 38 765



Ребята, всем привет! Помогите, пожалуйста оптимизировать алгоритм извлечения корня. А то что-то до фига получается циклов вычисления. Заранее огромное спасибо всем откликнувшимся!

Алгоритм простой, основан на методе последовательного приближения. Собственно вот он (без шелухи):

bprev:=bprev div 2;
if (b+bprev)*(b+bprev) > a then
b:=b-bprev
else
if (b+bprev)*(b+bprev) < a then
b:=b+bprev
else
выход;
повтор цикла....

Полный текст:

a:word;
b:word;
bprev:word;
cnt:word;

a:=strtoint(edit1.Text); // подкоренное выражение
b:=a; // в b хранится результат
bprev:=a;
cnt:=0;
while 1=1 do begin
cnt:=cnt+1; // Счетчик циклов
bprev:=bprev div 2;
if bprev=0 then begin
bprev:=1;
if ((b+1)*(b+1) > a) and ((b+0)*(b+0) < a) then break;
end;
if (b+bprev)*(b+bprev) > a then
b:=b-bprev
else
if (b+bprev)*(b+bprev) < a then
b:=b+bprev
else
break;
end;
b:=b+bprev;
Form1.Caption:='результат: '+inttostr(b)+' циклов: '+inttostr(cnt);

Результаты замера следующие:
sqr (1) - 2 цикла;
sqr (10) - 5 циклов;
sqr (100) - 5 циклов;
sqr (1000) - 13 циклов;
sqr (10000) - 38 циклов;
sqr (32000) - 73 цикла;
...

Алгоритм предложенный alexeyv:

i:=1; // результат в i
b:=1;
a:=10000; // подкоренное выражение
while 1=1 do begin
if (b > a) or (b = a) then break;
b:=b+2;
a:=a-b;
i:=i+1;
end;
caption:=inttostr(i);

sqr (10000) - 100 циклов.

Сообщение отредактировал Rostislav - Dec 5 2012, 07:35
Go to the top of the page
 
+Quote Post
3 страниц V   1 2 3 >  
Start new topic
Ответов (1 - 36)
alexeyv
сообщение Dec 5 2012, 03:37
Сообщение #2


Местный
***

Группа: Участник
Сообщений: 298
Регистрация: 26-01-09
Из: Пермь
Пользователь №: 43 940



Если нужна только целая часть квадратного корня, то можно воспользоваться другим алгоритмом:

Для квадратов чисел верны следующие равенства:
1 = 1^2
1+3 = 2^2
1+3+5 = 3^2
и так далее.

То есть, узнать целую часть квадратного корня числа можно, вычитая из него все нечётные числа по порядку, пока остаток не станет меньше следующего вычитаемого числа или равен нулю, и посчитав количество выполненных действий. Например, так:
Выполнено 3 действия, квадратный корень числа 9 равен 3.

Недостатком такого способа является то, что если извлекаемый корень не является целым числом, то можно узнать только его целую часть, но не точнее. В то же время такой способ вполне доступен детям, решающим простейшие математические задачи, требующие извлечения квадратного корня.

Циклов конечно будет больше, зато время их выполнения гораздо меньше
Go to the top of the page
 
+Quote Post
Rostislav
сообщение Dec 5 2012, 06:09
Сообщение #3


Частый гость
**

Группа: Участник
Сообщений: 127
Регистрация: 6-07-08
Из: Москва
Пользователь №: 38 765



Цитата(alexeyv @ Dec 5 2012, 06:37) *
1 = 1^2
1+3 = 2^2
1+3+5 = 3^2
и так далее.


Забавный алгоритм))

Т.е. если я Вас правильно понял, то программа должна выглядеть так:

a=подкоренное выражение
b=1
i=1

цикл
если b > a или b = a то
....выход (результат в i)
иначе
....b=b+(b+2)
....i=i+1
повтор цикла

Так?

Сообщение отредактировал Rostislav - Dec 5 2012, 06:30
Go to the top of the page
 
+Quote Post
Tanya
сообщение Dec 5 2012, 06:28
Сообщение #4


Гуру
******

Группа: Модераторы
Сообщений: 8 752
Регистрация: 6-01-06
Пользователь №: 12 883



Цитата(Rostislav @ Dec 5 2012, 10:09) *
Забавный алгоритм))

Что Вас так забавляет?
Немного школьной арифметики...
Сумма арифметической прогрессии дает - сумма N нечетных чисел в точности равна N в квадрате.
Следующий разряд (после точки) можно вычислить как (половина остатка)/N.
Go to the top of the page
 
+Quote Post
Rostislav
сообщение Dec 5 2012, 06:55
Сообщение #5


Частый гость
**

Группа: Участник
Сообщений: 127
Регистрация: 6-07-08
Из: Москва
Пользователь №: 38 765



Что забавляет? Все)) Магия чисел в особенности))

Проверил работу алгоритма:

sqr (10000) = 13
Но sqr (9) = 3 !!!!!

Где-то ошибка(

i:=1;
b:=1;
a:=10000;
while 1=1 do begin
if (b > a) or (b = a) then break;
b:=b+(b+2);
i:=i+1;
end;
caption:=inttostr(i);

Сообщение отредактировал Rostislav - Dec 5 2012, 06:59
Go to the top of the page
 
+Quote Post
MrYuran
сообщение Dec 5 2012, 06:59
Сообщение #6


Беспросветный оптимист
******

Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646



Цитата(Rostislav @ Dec 5 2012, 10:55) *
Где-то ошибка(


Код
........b=b+(b+2)

просто b=b+2
a=a-b

(эх и ужос этот ваш паскаль.. да ещё без тега code)


--------------------
Программирование делится на системное и бессистемное. ©Моё :)
— а для кого-то БГ — это Bill Gilbert =)
Go to the top of the page
 
+Quote Post
Rostislav
сообщение Dec 5 2012, 07:11
Сообщение #7


Частый гость
**

Группа: Участник
Сообщений: 127
Регистрация: 6-07-08
Из: Москва
Пользователь №: 38 765



Кстати, детская арифметика заканчивается начиная с sqr (36). Результат 5!

Цитата(MrYuran @ Dec 5 2012, 09:59) *
Код
........b=b+(b+2)

просто b=b+2
a=a-b


Ага, спасибо, все заработало! В итоге sqr (10000) вычисляется за 100 шагов. Оптимизации не получилось. Можно попробовать изменить его под переменную базу. Сейчас мы прибавляем 2, а можно начинать, например, с 16 последовательно уменьшая это число в двое. Если конечно это сработает. Буду думать...

Цитата(MrYuran @ Dec 5 2012, 09:59) *
(эх и ужос этот ваш паскаль.. да ещё без тега code)


Ну да, вот так и мучаюсь всю жизнь!))

Сообщение отредактировал Rostislav - Dec 5 2012, 09:25
Go to the top of the page
 
+Quote Post
skyv
сообщение Dec 5 2012, 10:59
Сообщение #8


Частый гость
**

Группа: Участник
Сообщений: 181
Регистрация: 26-07-10
Пользователь №: 58 606




Я использовал просто таблицу, которую предварительно вычислял.
Где ее лучше расположить это зависит от ресурсов CPU.
Go to the top of the page
 
+Quote Post
Rostislav
сообщение Dec 5 2012, 11:04
Сообщение #9


Частый гость
**

Группа: Участник
Сообщений: 127
Регистрация: 6-07-08
Из: Москва
Пользователь №: 38 765



Цитата(skyv @ Dec 5 2012, 13:59) *
Я использовал просто таблицу


А Вы можете привести пример? Мне нужно как-то оценить эффективность такого подхода. Сейчас я не могу сделать никаких выводов. Я знаю, что существуют табличные вычисления, но все нужно проверять в живую)
Go to the top of the page
 
+Quote Post
Lmx2315
сообщение Dec 5 2012, 11:14
Сообщение #10


отэц
*****

Группа: Свой
Сообщений: 1 729
Регистрация: 18-09-05
Из: Москва
Пользователь №: 8 684



QUOTE (Rostislav @ Dec 5 2012, 15:04) *
А Вы можете привести пример? Мне нужно как-то оценить эффективность такого подхода. Сейчас я не могу сделать никаких выводов. Я знаю, что существуют табличные вычисления, но все нужно проверять в живую)


..могу предположить что таблица - массив , где адрес - подкоренное выражение, значение массива - корень .
Значения подкоренных выражений находящися между между адресами массива высчитываются интерполяцией, линейной для простоты .






--------------------
b4edbc0f854dda469460aa1aa a5ba2bd36cbe9d4bc8f92179f 8f3fec5d9da7f0
SHA-256
Go to the top of the page
 
+Quote Post
MrYuran
сообщение Dec 5 2012, 11:28
Сообщение #11


Беспросветный оптимист
******

Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646



Прикрепленный файл  bibliofond_556017.rtf ( 117.89 килобайт ) Кол-во скачиваний: 1040


Можно скомбинировать.
Таблицу для грубого определения и дальше уточнять.


--------------------
Программирование делится на системное и бессистемное. ©Моё :)
— а для кого-то БГ — это Bill Gilbert =)
Go to the top of the page
 
+Quote Post
Rostislav
сообщение Dec 5 2012, 11:39
Сообщение #12


Частый гость
**

Группа: Участник
Сообщений: 127
Регистрация: 6-07-08
Из: Москва
Пользователь №: 38 765



Цитата(MrYuran @ Dec 5 2012, 14:28) *
Можно скомбинировать.
Таблицу для грубого определения и дальше уточнять.


Спасибо! Изучаю Вавилонский способ. Оказывается древние не только воевать умели) Я пока с комбинированием не хочу связываться. Нужно выжать максимум из того, что сейчас наработано. Мне кажется, что потенциал есть у обоих алгоритмов. А о комбинировании различных методов мысля уже проскальзывала, но хочется сделать монолитно-красиво)
Go to the top of the page
 
+Quote Post
sysel
сообщение Dec 5 2012, 13:56
Сообщение #13


Знающий
****

Группа: Свой
Сообщений: 601
Регистрация: 3-07-07
Пользователь №: 28 852



Не знаю, как называется метод, но пашет:
Код
// Вычисление квадратного корня из 32х битного числа
int16 isqrt32 (int32 from){
  register int32 mask=0x40000000;
  register int32 sqr=0;
  do {
    register int32 temp = sqr | mask;
    sqr >>= 1;
    if (temp <= from){
      sqr |= mask;
      from -= temp;
    };
  } while (mask >>= 2);
  if (sqr < from) sqr++;
  return ((int16)sqr);
}
Go to the top of the page
 
+Quote Post
skyv
сообщение Dec 6 2012, 10:52
Сообщение #14


Частый гость
**

Группа: Участник
Сообщений: 181
Регистрация: 26-07-10
Пользователь №: 58 606



Цитата(Lmx2315 @ Dec 5 2012, 15:14) *
..могу предположить что таблица - массив , где адрес - подкоренное выражение, значение массива - корень .


Так и есть.
В этом случае операция вычисления (в принципе чего угодно) сводится к
чтению ячейки массива.
Go to the top of the page
 
+Quote Post
анатолий
сообщение Dec 8 2012, 21:23
Сообщение #15


Местный
***

Группа: Свой
Сообщений: 221
Регистрация: 10-12-05
Из: Украина
Пользователь №: 12 052



Вот функция корня по алгоритму CORDIC
Код
function SQROOT(x1:integer) return integer is
        variable m,n,i, a, x,y,b: INTEGER;      
        constant bn:integer:=28;
            begin                
        y:=x1;     x:=x1;
        m:=1;    n:=bn/2;
        L1: for i in 1 to n loop
            a:=4*x;     
            exit L1 when a>=2**(bn);    
            y:=2*y;    x:=a;
        end loop;    
        L2:for i in 1 to n-1 loop
            b:=x+x/2**m;
            a:=b+b/2**m;
            if a<2**(bn) then
                x:=a;
                y:=y+y/2**m;
            end if;    
            m:=m+1;
        end loop;        
        return y/(2**n);
    end;
Go to the top of the page
 
+Quote Post
Rostislav
сообщение Dec 11 2012, 06:07
Сообщение #16


Частый гость
**

Группа: Участник
Сообщений: 127
Регистрация: 6-07-08
Из: Москва
Пользователь №: 38 765



Цитата(анатолий @ Dec 9 2012, 00:23) *
Вот функция корня по алгоритму CORDIC
Код
....
    b:=x+x/2**m;
....


Анатолий, спасибо огромное! Изучаю алогоритмик. Только вот я не понял, что означает в программе '**'? Степень числа?
Go to the top of the page
 
+Quote Post
Guest_TSerg_*
сообщение Dec 11 2012, 11:41
Сообщение #17





Guests






Код
function intSqrt_(Val : Longword) : Longword;
var bitSqr : Longword;
begin
bitSqr := $40000000;
Result := 0;

While bitSqr <> 0 do
  begin
   if (Val >= bitSqr + Result) then begin
       Dec(Val, bitSqr + Result);
       Result := (Result shr 1) or bitSqr;
     end
   else
       Result := Result shr 1;
   bitSqr := bitSqr shr 2;
  end;
end;


Если сравнивать с уже упомянутой медленной функцией:
Код
function Q(x: Longword): Longword;
var k: Longword;
begin
  Result := 0;
  k := 1;
  while (k <= x) do begin
    Dec(x,k);
    Inc(k,2);
    Inc(Result);
  end;
end;


то разница на писюках более чем в 20 раз лучше.
Go to the top of the page
 
+Quote Post
akorud
сообщение Dec 11 2012, 18:41
Сообщение #18


Местный
***

Группа: Свой
Сообщений: 203
Регистрация: 12-11-10
Из: Poland
Пользователь №: 60 842



Есть возможность использовать floating-point? Может известный алгоритм быстрого инверсного корня из Quake III http://en.wikipedia.org/wiki/Fast_inverse_square_root и факт что sqrt(x) = x/sqrt(x) -> sqrt(x) = x * rsqrt(x)
Go to the top of the page
 
+Quote Post
анатолий
сообщение Dec 11 2012, 19:16
Сообщение #19


Местный
***

Группа: Свой
Сообщений: 221
Регистрация: 10-12-05
Из: Украина
Пользователь №: 12 052



Цитата(Rostislav @ Dec 11 2012, 08:07) *
что означает в программе '**'? Степень числа?

Это степень числа, язык VHDL. Cинтезируется в логическую схему.
Go to the top of the page
 
+Quote Post
VitekSVM
сообщение Dec 20 2012, 13:41
Сообщение #20





Группа: Новичок
Сообщений: 2
Регистрация: 29-12-09
Пользователь №: 54 559



http://algolist.manual.ru/maths/count_fast/index.php
Go to the top of the page
 
+Quote Post
ASN
сообщение Dec 20 2012, 14:38
Сообщение #21


Местный
***

Группа: Свой
Сообщений: 459
Регистрация: 15-07-04
Из: g.Penza
Пользователь №: 326



Rostislav
С какой практической точностью нужно вычислять выражение ?
На какой целевой платформе выполняется прикладная программа?
Если вычислительная система поддерживает вычисления с плавающей точкой , то лучше воспользоваться арифметическим сопроцессором (типа сопроцессора для i386) или специальными командами самого процессора (как в TMS320C55).
Если требуется целочисленная арифметика, то проще и быстрее заранее вычисленной таблицы в памяти что-то предложить сложно.
Go to the top of the page
 
+Quote Post
Rostislav
сообщение Dec 20 2012, 20:46
Сообщение #22


Частый гость
**

Группа: Участник
Сообщений: 127
Регистрация: 6-07-08
Из: Москва
Пользователь №: 38 765



Цитата(ASN @ Dec 20 2012, 17:38) *
С какой практической точностью нужно вычислять выражение ?


Уважаемый ASN! Мне придумалась еще одна идея. Более простого алгоритма я придумать не смог (кстати, не понятно, почему этот вариант мне раньше не пришел в голову). Но все же отвечу на Ваши вопросы))

Меня интересует целочисленный результат.

Цитата(ASN @ Dec 20 2012, 17:38) *
На какой целевой платформе выполняется прикладная программа?
Если вычислительная система поддерживает вычисления с плавающей точкой , то лучше воспользоваться арифметическим сопроцессором (типа сопроцессора для i386) или специальными командами самого процессора (как в TMS320C55).


Меня интересовал вариант, который мог бы выполнятся на микроконтроллерах с простой архитектурой (типа PIC12).

Цитата(ASN @ Dec 20 2012, 17:38) *
Если требуется целочисленная арифметика, то проще и быстрее заранее вычисленной таблицы в памяти что-то предложить сложно.


Таблицы сразу не понравились. Для них нужна память.

----

Итак, мое заднее)))) предложение:

Код
  a : Word;  // подкоренное выражение
  b : Word;  // результат
  n : Byte;

  a := 121;
  b := 0;

  // начало
  for n := 15 downto 0 do   // Счет от 15 до 0   // 15 - разрядность подкоренного выражения (вернее N не 15, а N=15+1)
   begin
     if ((b + 1 shl n) * (b + 1 shl n) < a) or         // shl - побитовый сдвиг влево на n бит
        ((b + 1 shl n) * (b + 1 shl n) = a) then
      begin
        b := b + 1 shl n;
      end;
   end;
  // конец

  Form1.Caption := IntToStr (b);    // b = 11

  Циклов для 16-ти разрядного числа 16!!!
         для 32-х  разрядного числа 32!!!!!!


По-моему, получилось красиво))) Операции умножения можно заменить на бинарное сложение столбиком с предварительным смещением бит влево. Если более оптимального алгоритма наука)) еще не придумала, то тему можно закрывать. Теперь возьмусь за вычисление тригонометрических функций)))) Всем спасибо!!!!!

Сообщение отредактировал Rostislav - Dec 20 2012, 21:57
Go to the top of the page
 
+Quote Post
beaRTS
сообщение Dec 21 2012, 02:07
Сообщение #23


Местный
***

Группа: Участник
Сообщений: 211
Регистрация: 27-12-11
Из: Челябинск
Пользователь №: 69 111



Цитата(Rostislav @ Dec 21 2012, 00:46) *
[code] a : Word; // подкоренное выражение
b : Word; // результат
n : Byte;

a := 121;
b := 0;

// начало
for n := 15 downto 0 do // Счет от 15 до 0 // 15 - разрядность подкоренного выражения (вернее N не 15, а N=15+1)
begin
if ((b + 1 shl n) * (b + 1 shl n) < a) or // shl - побитовый сдвиг влево на n бит
((b + 1 shl n) * (b + 1 shl n) = a) then
begin
b := b + 1 shl n;
end;
end;
// конец

Form1.Caption := IntToStr (cool.gif; // b = 11
[code]

По-моему, получилось красиво)))


Может, я чего-то не понимаю... но в цикле for явно не красота красуется. Вы 5 раз вычисляете одно и тоже выражение b + 1 shl n !! Дык, зачем это делать?. один раз вычислите, присвойте результат какой-нибудь временной переменной и таскайте ее за собой везде. что-то типа:

for n := 15 downto 0 do // Счет от 15 до 0 // 15 - разрядность подкоренного выражения (вернее N не 15, а N=15+1)
begin
temp := b + 1 shl n;
if (temp * temp < a) or // А ТАК НЕЛЬЗЯ???? (temp * temp <= a )
(temp * temp = a) then
begin
b := temp
end;
end;
// конец

Сообщение отредактировал beaRTS - Dec 21 2012, 02:10


--------------------
"Об уме человека вернее судить по его вопросам, нежели по его ответам" (с)
Go to the top of the page
 
+Quote Post
Rostislav
сообщение Dec 21 2012, 05:56
Сообщение #24


Частый гость
**

Группа: Участник
Сообщений: 127
Регистрация: 6-07-08
Из: Москва
Пользователь №: 38 765



Цитата(beaRTS @ Dec 21 2012, 05:07) *
temp := b + 1 shl n;
if (temp * temp < a) or //А ТАК НЕЛЬЗЯ????


Да нее, Вы все правильно понимаете)))))))) Просто я не стал делать очевидное, то, что лежит на поверхности. Ну конечно же, мне известны некоторые трюки программирования. Умножение на 2 (и деление), например, легко можно заменить на побитовый сдвиг и т.п. А Ваш вариант оптимизации сделает, скорее всего, компилятор. Меня (и не только меня, наверное) больше всего интересовала суть. Суть я и изложил. Поэтому, спасибо Вам за участие и с наступающим Новым Годом!!!!!!!)))))))))

Сообщение отредактировал Rostislav - Dec 21 2012, 05:58
Go to the top of the page
 
+Quote Post
beaRTS
сообщение Dec 21 2012, 06:16
Сообщение #25


Местный
***

Группа: Участник
Сообщений: 211
Регистрация: 27-12-11
Из: Челябинск
Пользователь №: 69 111



Цитата(Rostislav @ Dec 21 2012, 08:56) *
Да нее, Вы все правильно понимаете)))))))) Просто я не стал делать очевидное, то, что лежит на поверхности. Ну конечно же, мне известны некоторые трюки программирования. Умножение на 2 (и деление), например, легко можно заменить на побитовый сдвиг и т.п. А Ваш вариант оптимизации сделает, скорее всего, компилятор. Меня (и не только меня, наверное) больше всего интересовала суть. Суть я и изложил. Поэтому, спасибо Вам за участие и с наступающим Новым Годом!!!!!!!)))))))))

а, ну тогда добро, добро. я тут тоже начал над своим вариантом извлечения корня биться. Ну как своим - комбинирую два метода. посмотрим что получится


--------------------
"Об уме человека вернее судить по его вопросам, нежели по его ответам" (с)
Go to the top of the page
 
+Quote Post
Rostislav
сообщение Dec 21 2012, 06:19
Сообщение #26


Частый гость
**

Группа: Участник
Сообщений: 127
Регистрация: 6-07-08
Из: Москва
Пользователь №: 38 765



Цитата(beaRTS @ Dec 21 2012, 09:16) *
а, ну тогда добро, добро. я тут тоже начал над своим вариантом извлечения корня биться. Ну как своим - комбинирую два метода. посмотрим что получится


Здорово!!!))) Выкладывайте Ваши идеи!!!!!! Очень интересно!!!)))

Сообщение отредактировал Rostislav - Dec 21 2012, 06:19
Go to the top of the page
 
+Quote Post
blackfin
сообщение Dec 21 2012, 06:19
Сообщение #27


Гуру
******

Группа: Свой
Сообщений: 3 106
Регистрация: 18-04-05
Пользователь №: 4 261



Сто раз уже обсуждали: ReAl.
Go to the top of the page
 
+Quote Post
Rostislav
сообщение Dec 21 2012, 06:24
Сообщение #28


Частый гость
**

Группа: Участник
Сообщений: 127
Регистрация: 6-07-08
Из: Москва
Пользователь №: 38 765



Цитата(blackfin @ Dec 21 2012, 09:19) *
Сто раз уже обсуждали: ReAl.


Да, похоже, я не открыл Америку))))))))
Go to the top of the page
 
+Quote Post
beaRTS
сообщение Dec 21 2012, 06:27
Сообщение #29


Местный
***

Группа: Участник
Сообщений: 211
Регистрация: 27-12-11
Из: Челябинск
Пользователь №: 69 111



Цитата(blackfin @ Dec 21 2012, 09:19) *
Сто раз уже обсуждали:

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


--------------------
"Об уме человека вернее судить по его вопросам, нежели по его ответам" (с)
Go to the top of the page
 
+Quote Post
Rostislav
сообщение Dec 21 2012, 06:31
Сообщение #30


Частый гость
**

Группа: Участник
Сообщений: 127
Регистрация: 6-07-08
Из: Москва
Пользователь №: 38 765



Цитата(beaRTS @ Dec 21 2012, 09:27) *
...я эту ссылку первый раз вижу...


Присоединяюсь! К тому же, может быть "подует свежий ветер"!)))
Go to the top of the page
 
+Quote Post
Guest_TSerg_*
сообщение Dec 21 2012, 07:12
Сообщение #31





Guests






Топик-стартер слушает только себя в попытке изобрести велосипед.sm.gif

Вам уже приводились идеи и работающие варианты.
Науке известны разные способы ивлечения целочисленного корня на разные вкусы.

Еще раз приведу (для 16р сетки), число иттераций всегда 9 и никаких умножений.

function QuickSqrt_(Val : word) : word;
var bitSqr : word;
begin
bitSqr := $10000;
Result := 0;

While bitSqr <> 0 do begin
if (Val >= bitSqr + Result) then begin
Dec(Val, bitSqr + Result);
Result := (Result shr 1) or bitSqr;
end
else Result := Result shr 1;
bitSqr := bitSqr shr 2;
end;
end;
Go to the top of the page
 
+Quote Post
Rostislav
сообщение Dec 21 2012, 11:10
Сообщение #32


Частый гость
**

Группа: Участник
Сообщений: 127
Регистрация: 6-07-08
Из: Москва
Пользователь №: 38 765



Цитата(TSerg @ Dec 21 2012, 10:12) *
Топик-стартер слушает только себя в попытке изобрести велосипед.sm.gif

Вам уже приводились идеи и работающие варианты.
Науке известны разные способы извлечения целочисленного корня на разные вкусы.


Уважаемый TSerg, ну тё Вы ругаетесь? Себя я, конечно же, слушаю))) Велосипед? Да, изобретаю! Не мешайте мне побыть гениальнымbiggrin.gif biggrin.gif biggrin.gif biggrin.gif biggrin.gif

Ваш вариант действительно очень эффективен. Да, выполняется за всего за 9 циклов! Я бы добавил его в начало темы, но не могу. Первое сообщение не доступно уже для изменения.

Более того, в последнем Вашем коде есть ошибка: bitSqr : word. Это говорит о том, что Вы лично его не проверяли в деле.

Судя по тому, что маске присваивается значение 0x010000, маска bitSqr должна быть 32-х разрядной (как и было в первом Вашем варианте). Далее в коде все операции с ней происходят как с 32-х разрядным числом (компилятор не будет динамически менять разрядность), это требует дополнительной памяти данных и инструкций. Это первое.

Второе. Объем кода в Вашем варианте мне показался больше, чем в моем (к тому же, учитывая операции с 32-х разрядным числом в микроконтроллере с 8-ми разрядной архитектурой (даже с аппаратным умножителем 8х8), например). Но это на вскидку. Если все совсем делать серьезно, то, по идее, оба алгоритма нужно перевести на ассемблер микроконтроллера PIC16, например, и сравнить.

Но, Ваш код прост. Мой имеет один (?) недостаток - операция умножения. В микроконтроллере с аппаратным умножителем это не будет проблемой, в остальных да.

Вариантов, действительно, было множество. Но ищется оптимальный (имеющий малый объем кода, простоту вычислений, быстрый). Не все они отвечают этим требованиям. И вкус, часто определяется архитектурой вычислительного ядра. Ищу золотую середину)))

ЗЫ. Кстати, очень интересно какие все же идеи есть у beaRTS)))

Сообщение отредактировал Rostislav - Dec 21 2012, 11:16
Go to the top of the page
 
+Quote Post
Rostislav
сообщение Dec 22 2012, 08:25
Сообщение #33


Частый гость
**

Группа: Участник
Сообщений: 127
Регистрация: 6-07-08
Из: Москва
Пользователь №: 38 765



TSerg, Ваш вариант описывается тут: http://en.wikipedia.org/wiki/Methods_of_co...ng_square_roots

Ребят, кто-нибудь понимает предложенные там еще два метода:

Код
          1  2. 3  4
        ___________
       /
     \/  01 52.27 56

         01                   1*1 <= 1 < 2*2                 x = 1
         01                     y = x*x = 1*1 = 1
         00 52                22*2 <= 52 < 23*3              x = 2
         00 44                  y = (20+x)*x = 22*2 = 44
            08 27             243*3 <= 827 < 244*4           x = 3
            07 29               y = (240+x)*x = 243*3 = 729
               98 56          2464*4 <= 9856 < 2465*5        x = 4
               98 56            y = (2460+x)*x = 2464*4 = 9856
               00 00          Algorithm terminates: Answer is 12.34

          1. 4  1  4  2
          _____________
       /
     \/  02.00 00 00 00

         02                  1*1 <= 2 < 2*2                 x = 1
         01                    y = x*x = 1*1 = 1
         01 00               24*4 <= 100 < 25*5             x = 4
         00 96                 y = (20+x)*x = 24*4 = 96
            04 00            281*1 <= 400 < 282*2           x = 1
            02 81              y = (280+x)*x = 281*1 = 281
            01 19 00         2824*4 <= 11900 < 2825*5       x = 4
            01 12 96           y = (2820+x)*x = 2824*4 = 11296
               06 04 00      28282*2 <= 60400 < 28283*3     x = 2
                             The desired precision is achieved:
                             The square root of 2 is about 1.4142
?

Сообщение отредактировал Rostislav - Dec 22 2012, 08:27
Go to the top of the page
 
+Quote Post
beaRTS
сообщение Dec 22 2012, 08:50
Сообщение #34


Местный
***

Группа: Участник
Сообщений: 211
Регистрация: 27-12-11
Из: Челябинск
Пользователь №: 69 111



Цитата(Rostislav @ Dec 21 2012, 14:10) *
ЗЫ. Кстати, очень интересно какие все же идеи есть у beaRTS)))

да какие там идеи... =) тож начитался много чего (по диагонали)
мне корень нужен для нахождения модуля вектора, т.е.: имею синфазную и квадратурную составляющую сигнала (I и Q), т.е. как бы координаты вектора, ну и надо модуль найти, чтобы два канала I и Q соединить в один. Так вот. У меня на проце TMS320F28335 есть FPU (в общем, floating-point понимает и перемножитель даже есть аппаратный), работаю с числами float (вещественными одинарной точности).

Ну и показался метод Ньютона (он же вроде вырождается в метод Вавилонский) более подходящий из всех, т.к. ему пофигу что считать: либо целые либо вещественны числа. Стал думать как делать для него первое приближение g0 (в книге Уоррен Генри. "Алгоритмические трюки для программистов такие обозначения" ). Ну а тут прям в масть ознакомился с неким алгоритмом "максимум альфа плюс минимум бета", который линейно аппроксимирует выражение sqrt( I^2 + Q^2) с приемлемой точностью и быстротой (точность зависит от коэффициентов альфа и бета). ну и решил первое приближение g0 делать при помощи него.

итого, программка работает. только мне еще вкурить надо как должным образом проверить ее производительность во времени (что-то типа профилирования), сколько итераций расчета по методу ньютона производит с таким начальным/первым приближением. и сравнить по времени выполнения со стандартными функциями С++. Ну и величину ошибки тоже вычислить.

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

В общем статистику еще не проводил и не оформлял. но стопудово сделаю какую-нить статейку.


--------------------
"Об уме человека вернее судить по его вопросам, нежели по его ответам" (с)
Go to the top of the page
 
+Quote Post
beaRTS
сообщение Dec 22 2012, 09:01
Сообщение #35


Местный
***

Группа: Участник
Сообщений: 211
Регистрация: 27-12-11
Из: Челябинск
Пользователь №: 69 111



Цитата(Rostislav @ Dec 21 2012, 14:10) *
ЗЫ. Кстати, очень интересно какие все же идеи есть у beaRTS)))

да какие там идеи... =) тож начитался много чего (по диагонали)
мне корень нужен для нахождения модуля вектора, т.е.: имею синфазную и квадратурную составляющую сигнала (I и Q), т.е. как бы координаты вектора, ну и надо модуль найти, чтобы два канала I и Q соединить в один. Так вот. У меня на проце TMS320F28335 есть FPU (в общем, floating-point понимает и перемножитель даже есть аппаратный), работаю с числами float (вещественными одинарной точности).

Ну и показался метод Ньютона (он же вроде вырождается в метод Вавилонский) более подходящий из всех, т.к. ему пофигу что считать: либо целые либо вещественны числа. Стал думать как делать для него первое приближение g0 (в книге Уоррен Генри. "Алгоритмические трюки для программистов такие обозначения" ). Ну а тут прям в масть ознакомился с неким алгоритмом "максимум альфа плюс минимум бета", который линейно аппроксимирует выражение sqrt( I^2 + Q^2) с приемлемой точностью и быстротой (точность зависит от коэффициентов альфа и бета). ну и решил первое приближение g0 делать при помощи него.

итого, программка работает. только мне еще вкурить надо как должным образом проверить ее производительность во времени (что-то типа профилирования), сколько итераций расчета по методу ньютона производит с таким начальным/первым приближением. и сравнить по времени выполнения со стандартными функциями С++. Ну и величину ошибки тоже вычислить.

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

В общем статистику еще не проводил и не оформлял. но стопудово сделаю какую-нить статейку.

ну вот сырые данные в картинке во вложении.
Под итерациями я здесь подразумеваю сколько раз алгоритму требуется пройтись по циклу while() :
Код
    while( firstEstimation - nextEstimation != 0 ) {    
        firstEstimation = nextEstimation;

        nextEstimation = ( firstEstimation + quotient )/2;

        //for next iteration check in while()
        quotient = radicand/firstEstimation;

        //for debug
        ++iterationCnt;
    } //while



а в main() прогоняю такие числа:
Код
    for( int k = 0, g = 50; k < 50; ++k, --g) {
        temp = k*k + g*g;
        i = ( float )k;
        q = ( float )g;
        std::cout << "<cmath> sqrt(): " << sqrt(temp) << "     my sqrt(): " << sqrtIQ(i, q) << "   perform in " << iterationCnt << " iterations"<< std::endl;
    } // for

Эскизы прикрепленных изображений
Прикрепленное изображение
 


--------------------
"Об уме человека вернее судить по его вопросам, нежели по его ответам" (с)
Go to the top of the page
 
+Quote Post
beaRTS
сообщение Dec 22 2012, 16:06
Сообщение #36


Местный
***

Группа: Участник
Сообщений: 211
Регистрация: 27-12-11
Из: Челябинск
Пользователь №: 69 111



по поводу своей идеи начал новую тему. вот здесь кому интересно - зайдите , посоветуйте


--------------------
"Об уме человека вернее судить по его вопросам, нежели по его ответам" (с)
Go to the top of the page
 
+Quote Post
Guest_TSerg_*
сообщение Dec 22 2012, 17:47
Сообщение #37





Guests






Цитата(Rostislav @ Dec 21 2012, 15:10) *
Ваш вариант действительно очень эффективен. Да, выполняется за всего за 9 циклов! Я бы добавил его в начало темы, но не могу. Первое сообщение не доступно уже для изменения.

Более того, в последнем Вашем коде есть ошибка: bitSqr : word. Это говорит о том, что Вы лично его не проверяли в деле.


Это не мой вариант, но давно известный.

bitSqr := $FFFF;

Да, чисто механически оттранслировал на 16рsm.gif
Delphi исправляет мою погрешность, но в микроконтроллере надо быть внимательнее, конечно же.

Go to the top of the page
 
+Quote Post

3 страниц V   1 2 3 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 19th June 2025 - 08:50
Рейтинг@Mail.ru


Страница сгенерированна за 0.01749 секунд с 7
ELECTRONIX ©2004-2016