четверг, 10 октября 2013 г.

Вычисление длины гипотенузы

Подхожу постепенно к комплексным числам, но завуалированно. Пока примерчик из геометрии.
Exported from Notepad++
#include <iostream> #include <math.h> #include <limits.h> using namespace std; unsigned short sqrt(unsigned short x) { unsigned short ans = 0; unsigned short tmp = 0; unsigned short local_mask = 0b11; unsigned short mask = 0; for(int i = 15; i>=0; i--) { mask |= local_mask << (2*i); tmp = x & mask; ans ^= 1 << i; if(tmp < ans*ans) ans ^= 1 << i; } return ans; } int main () { unsigned short x1 = 3; unsigned short x2 = 4; unsigned short x = x1*x1+x2*x2; unsigned short y =sqrt(x); cout << x << endl; cout << y; return 0; }


























Вывод x = 25, y = 5
Не буду накладывать ограничения на диапазон переменных х1, х2, х, ибо это просто пример. У нас есть два катета, длина гипотенузы вычисляется по известной формуле. Складывать числа на Verilog мы умеем, умножать тоже, квадратный корень разобрали в прошлый раз. Ситуация немного осложнилась выбором разрядности переменных short - 16 бит. На самом деле если сложить две переменных unsigned short можно словить переполнение, возведя в квадрат переменную тем более. Поэтому, следуя этим правилам, если ushort возвести в квадрат, то на выходе будет размерность 32 бита (16+16). Сложим два числа по 32 бита получим 33 битное слово. Нечетная размерность не подходит для вычисления квадратного корня, поэтому расширим представление числа до 34 бит вставкой нуля на позицию msb. Используя примочки языка Verilog , такие как generate..endgenerate можно получить достаточно компактное описания операции взятия квадратного корня:
Exported from Notepad++
module test( input wire clk, input wire [ 15 : 0 ] x1, input wire [ 15 : 0 ] x2, output wire [ 16 : 0 ] y ); wire [ 31 : 0 ] x1_2 = x1*x1; wire [ 31 : 0 ] x2_2 = x2*x2; wire [ 32 : 0 ] x = x1_2 + x2_2; wire [ 33 : 0 ] xx = {1'b0, x}; wire [ 16 : 0 ] yy; assign yy[16] = xx[33-:2] == 2'b00 ? 1'b0 : 1'b1; genvar k; generate for(k = 15; k >= 0; k = k - 1) begin: gen assign yy[k] = xx[33-:(2*(17-k))] < {yy[16:k+1],1'b1}*{yy[16:k+1],1'b1} ? 1'b0 : 1'b1; end endgenerate assign y = yy; endmodule























Можно погонять в testbench с критическими числами, типа 65535, чтобы убедиться, что возвращается верное значение. В случае x1 = x2 = 65535 вернется 92680. 

Комментариев нет:

Отправить комментарий