Cách thực hiện xấp xỉ giá trị nhỏ cho sqrt (x) trên FPGA


8

Tôi đang cố gắng thực hiện một thói quen điểm cố định liên quan đến việc tính toán giá trị của cho nhỏ tiếp cận . Kiến trúc đích là một đồ họa. Một vấn đề là chức năng này không dễ dàng cho vay khi sử dụng bản mở rộng của Taylor. Người ta có thể thấy rằng đối với các giá trị nhỏ của x, độ dốc của sẽ đến vô cùng khi tiến đến , do đó việc đánh giá hàm bằng chuỗi lũy thừa bao gồm nhân các hệ số lớn với nhỏ . Do đó phương pháp này không ổn định về số lượng.xx0xx0x

Sử dụng phương pháp lặp, Newton-Raphson mang lại phương trình lặp sau: , trong đó chúng ta cố gắng gần đúng . Nhưng một lần nữa, vì nhỏ, cũng phải nhỏ để giải pháp hội tụ. Vì phương trình liên quan đến việc chia một số nhỏ cho một số nhỏ khác, nên nhiều khả năng là số học điểm cố định sẽ thất bại.xn+1=xn2α2xnααxn

Cùng với đó, tôi muốn biết cách triển khai xấp xỉ giá trị nhỏ cho bằng cách sử dụng số học điểm cố định, bằng cách sử dụng các hệ số được tính toán trước hoặc phương pháp lặp.x


2
Nếu bạn đang nhắm mục tiêu một FPGA, câu hỏi đầu tiên và quan trọng nhất là độ chính xác mà bạn muốn. Bạn nói rằng bạn muốn sử dụng điểm sửa lỗi: độ chính xác nào cho đầu vào, độ chính xác nào cho kết quả? Trong điểm cố định (như trong số nguyên) không có "gần bằng 0". Chỉ có một con số nhỏ nhất mà bạn quan tâm.
Philippe

Câu trả lời:


5

Một thói quen mà tôi đã sử dụng trước đây (tôi không biết đó có phải là "đúng" hay không) là một cách tiếp cận phân chia và chinh phục.

Bạn bắt đầu với một giá trị trên và dưới tùy ý (lần lượt là 5 và 0 - căn bậc hai cao nhất và thấp nhất bạn muốn tìm) và tìm điểm giữa giữa chúng. Bình phương giá trị đó.

Nếu giá trị bình phương lớn hơn mục tiêu của bạn, hãy đặt giá trị trên thành giá trị bình phương của bạn. Nếu nó thấp hơn, đặt giá trị thấp hơn.

Lặp lại cho đến khi giá trị bình phương khớp với giá trị tra cứu của bạn hoặc bạn đã thực hiện đủ số lần lặp để chính xác như bạn muốn.

Đây là một phiên bản nhỏ tôi đã gõ cùng nhau trong perl:

#!/usr/bin/perl

my $val = shift;

my $max = 5;
my $min = 0;

my $iterations = 0;
my $maxiter = 40;

while(($max > $min) and ($iterations<$maxiter))
{
    $iterations++;
    my $diff = $min + ($max - $min) / 2;
    my $square = $diff * $diff;

    if($square == $val)
    {

        print "Square root found at $diff\n";
        print "$iterations iterations\n";
        exit(0);
    } else {
        if($square > $val)
        {
            $max = $diff;
        } else {
            $min = $diff;
        }
    }
}

my $diff = $min + ($max - $min) / 2;
print "Approximate square root after $iterations iterations: $diff\n";

Điều này tất nhiên là sử dụng điểm nổi, nhưng có thể dễ dàng được thêm vào điểm cố định. Bạn có thể thay đổi độ chính xác bằng cách thay đổi giới hạn lặp. Mỗi lần lặp lại sẽ chính xác hơn một chút so với lần lặp trước.

ví dụ: - tìm căn bậc hai của 9:

Approximate square root after 40 iterations: 2.99999999999955
   - or - 
Approximate square root after 10 iterations: 3.00048828125
   - or - 
Approximate square root after 5 iterations: 3.046875

Nếu nó đã tìm thấy giá trị 3 thì tất nhiên nó sẽ dừng lại sớm.

Cung cấp cho nó đủ số lần lặp và nó sẽ làm cho nó rất chính xác:

./sqrt.pl 0.00284
Square root found at 0.0532916503778969
59 iterations

2
Về cơ bản là một tìm kiếm nhị phân.
rfusca

Bạn có biết một phương pháp để chọn giá trị bắt đầu không?
Ang Zi Ping

Đó là căn bậc hai của số lớn nhất mà bạn muốn xử lý.
Majenko


3

Bạn đã không xác định những gì bạn có nghĩa là "giá trị nhỏ" hoặc "xấp xỉ". Vì vậy, những gì tôi sắp đề xuất có thể không hoạt động, nhưng ở đây đi.

Cách dễ nhất là làm một cái nhìn lên bàn. Về cơ bản, ROM trong đó bus địa chỉ là số mà bạn muốn căn bậc hai, và kết quả đầu ra dữ liệu là kết quả. Với một BRAM duy nhất, bạn có thể thực hiện LUT 9 bit, 8 bit ngoài. Tất nhiên, nhiều BRAM sẽ cung cấp cho bạn một bảng lớn hơn.

(BRAM = Thuật ngữ Xilinx cho Block RAM, cũng có thể được sử dụng làm ROM. Các loại đồ họa khác có những thứ tương tự.)

Nếu bạn muốn độ chính xác cao hơn BRAM sẽ cung cấp cho bạn, bạn có thể thực hiện phép nội suy tuyến tính đơn giản của hai mục LUT. Ví dụ: giả sử bạn muốn có đầu vào 12 bit, nhưng bạn chỉ có BRAM cho 10 bit. Bạn lấy 10 bit đầu vào của bạn và tìm kiếm trong LUT. Thêm 1 vào 10 bit đó và cũng tìm giá trị đó. Sau đó, bạn thực hiện phép nội suy tuyến tính đơn giản giữa hai kết quả, sử dụng 2 bit dưới cùng để cho bạn biết tỷ lệ của một giá trị so với giá trị kia. Tất nhiên điều này sẽ chỉ cung cấp cho bạn một xấp xỉ, nhưng tôi nghĩ rằng nếu bạn làm toán bạn sẽ thấy rằng nó có thể đủ tốt.

Phương pháp này ít chính xác nhất với các số có giá trị thấp, nhưng khi đầu vào chuyển sang giá trị cao hơn, độ chính xác sẽ tăng lên.

Tối ưu hóa phương pháp trên sẽ là sử dụng BRAM làm ROM cổng kép. Theo cách này, bạn có thể đọc hai giá trị mà không tăng số lượng BRAM được sử dụng. Điều này cũng sẽ cho phép bạn tính toán một SQRT cho mỗi chu kỳ đồng hồ, với một số độ trễ đường ống.

Ngẫu nhiên, phương pháp này cũng hoạt động cho SINE / COSINE!


Giá trị nhỏ có nghĩa là x tiếp cận 0, đó là lý do tại sao tôi thú vị trong xấp xỉ giá trị nhỏ của \ sqrt {x}.
Ang Zhi Ping

1
@angzhiping "Tiếp cận số không" không giúp được gì. Chúng ta cần biết phạm vi và độ chính xác. Những gì bạn đã đưa ra là một nửa của phạm vi và không có độ chính xác. Kết quả cuối cùng là để biết số lượng bit đầu vào và đầu ra. Cũng quan trọng là tốc độ cần thiết: về tốc độ đồng hồ và đồng hồ trên mỗi sqrt.

3

Hãy thử cách tiếp cận sau

  • Nếu số âm, xử lý tương ứng.
  • Nếu số là 0, trả về 0.
  • Nếu không thì:
  • chuẩn hóa thành một số trong phạm vi [1/4, 1]: đếm số lần k bạn phải nhân số của mình với 4 (tính x <<= 2bằng C) cho đến khi nó nằm trong phạm vi trên.
  • sử dụng một cách tiếp cận tùy ý (xấp xỉ đa thức, phương pháp của Newton cho sqrt a [n] = (a [n-1] + k / a [n-1]) / 2, v.v.) để tính căn bậc hai trong phạm vi này
  • không chuẩn hóa: dịch chuyển sang phải bởi k bit

0

x= =(y+d)2y2+2dyd= =(x-y2)/2y= =(x/y-y)»1y= =y+d.y= =1«(n/2). Hội tụ trong <4 lần lặp.


0

Thử: cải thiện đoán cho biến thứ 1

Số của bạn có thể được xem xét: A * 2 ^ n
Xấp xỉ 1 là: A * 2 ^ (n / 2)

Giả sử bạn đang sử dụng số 32 bit, với 24 bit được sử dụng để giữ phân số. Đối với các số> 1:
1. Đếm số bit được sử dụng trong phần nguyên (N)
2. Giảm một nửa số này (N '= N / 2, tức là phải dịch chuyển 1 bit)
3. Phải dịch chuyển số gốc bằng N' : đây là phỏng đoán đầu tiên của bạn.

Trong định dạng này, số nhỏ nhất bạn có thể có là 2 ^ -24. Căn bậc hai sẽ ba khoảng 2 ^ -12. Vì vậy, đối với các số <1:
1. Đếm số bit "không" trong phân số, cho đến khi bạn đạt được một bit đã đặt (N)
2. Giảm một nửa số này (N '= N / 2, tức là phải dịch chuyển 1 bit)
3. TRÁI số thay đổi số gốc theo số đếm đã sửa đổi: đây là lần đoán đầu tiên của bạn.

Ví dụ:
0,0000 0000 0000 0000 1 [16 số 0 đứng đầu] gần đúng với: 0,0000 0000 1

Cuối cùng, nếu bạn vẫn gặp rắc rối với A nhỏ: bạn có thể tính 1 / A không?
Nếu vậy, hãy đảo ngược số của bạn, sau đó thử sử dụng thuật toán Inverse Square Root:
x' = 0.5x * (3 - Ax^2)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.