Cara melakukan pendekatan nilai kecil untuk sqrt (x) pada FPGA

8

Saya mencoba menerapkan titik tetap rutin yang melibatkan menghitung nilai xuntuk kecil yang mendekati . Arsitektur target adalah FPGA. Satu masalah adalah bahwa fungsi ini tidak cocok dengan penggunaan ekspansi Taylor. Kita dapat melihat bahwa untuk nilai x yang kecil, kemiringan berubah hingga tak terhingga ketika mendekati , oleh karena itu mengevaluasi fungsi menggunakan rangkaian daya melibatkan mengalikan koefisien besar dengan kecil . Karenanya metode ini secara numerik tidak stabil.x0xx0x

Menggunakan pendekatan iteratif, Newton-Raphson menghasilkan persamaan iteratif berikut: , di mana kita berada mencoba memperkirakan . Tetapi sekali lagi, karena kecil, juga harus kecil untuk solusi untuk bertemu. Karena persamaan melibatkan membagi angka kecil dengan angka kecil lainnya, kemungkinan aritmatika titik tetap akan gagal.xn+1=xn2-α2xnααxn

Dengan itu, saya ingin tahu bagaimana menerapkan pendekatan nilai kecil untuk menggunakan aritmatika titik tetap, baik menggunakan koefisien yang telah dikomputasi atau metode iteratif.x

Ang Zhi Ping
sumber
2
Jika Anda menargetkan FPGA, pertanyaan pertama dan terpenting adalah ketepatan yang Anda inginkan. Anda mengatakan Anda ingin menggunakan titik perbaikan: ketepatan untuk input, ketepatan untuk hasilnya? Di titik tetap (seperti dalam bilangan bulat) tidak ada "mendekati nol". Hanya ada nomor terkecil yang Anda minati.
Philippe

Jawaban:

5

Sebuah rutinitas yang telah saya gunakan sebelumnya (saya tidak tahu apakah itu "tepat" atau tidak) adalah pendekatan membagi dan menaklukkan.

Anda mulai dengan nilai sewenang-wenang atas dan bawah (katakan masing-masing 5 dan 0 - akar kuadrat tertinggi dan terendah yang ingin Anda temukan) dan temukan titik tengah di antara mereka. Kuadratkan nilai itu.

Jika nilai kuadrat lebih besar dari target Anda, tetapkan nilai atas menjadi nilai kuadrat Anda. Jika lebih rendah, atur nilai yang lebih rendah.

Ulangi sampai nilai kuadrat cocok dengan nilai pencarian Anda, atau Anda telah menjalankan iterasi yang cukup seakurat yang Anda inginkan.

Berikut ini adalah versi kecil yang telah saya ketuk bersama di 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";

Ini tentu saja menggunakan floating point, tetapi dapat dengan mudah ditambahkan ke titik tetap. Anda dapat memvariasikan keakuratan dengan mengubah batas iterasi. Setiap iterasi menjadi sedikit lebih akurat daripada yang sebelumnya.

misal: - cari akar kuadrat dari 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

Jika sudah menemukan nilai 3 tentu saja akan berhenti lebih awal.

Berikan iterasi yang cukup dan itu harus membuatnya sangat akurat:

./sqrt.pl 0.00284
Square root found at 0.0532916503778969
59 iterations
Majenko
sumber
2
Pada dasarnya pencarian biner.
rfusca
Apakah Anda tahu metode untuk memilih nilai awal?
Ang Zhi Ping
Ini adalah akar kuadrat dari jumlah terbesar yang Anda harapkan untuk ditangani.
Majenko
4

Berikut adalah beberapa ide dan rutinitas dari guru transenden / Guru Scott Dattalo di sini .
Itu tentu saja lelucon kecuali bagian guru (Guru?). Scott luar biasa.

Diskusi yang relevan. 2005 & PIC dan beberapa bernilai C tetapi mungkin bernilai.

Scott lagi - 2003

Dua Tuan !!!
Dattallo & Golovchenko.
Berbagai metode

Russell McMahon
sumber
3

Anda tidak menentukan apa yang Anda maksud dengan "nilai kecil", atau "perkiraan". Jadi apa yang akan saya usulkan mungkin tidak berhasil, tapi begini saja.

Hal yang paling mudah adalah dengan melihat-lihat. Pada dasarnya ROM di mana bus alamat adalah nomor yang Anda inginkan dengan root-square, dan hasilnya adalah data. Dengan BRAM tunggal, Anda bisa melakukan 9 bit, 8 bit LUT. Tentu saja, lebih banyak BRAM akan memberi Anda meja yang lebih besar.

(BRAM = Istilah Xilinx untuk RAM Blok, yang juga dapat digunakan sebagai ROM. FPGA lain memiliki hal serupa.)

Jika Anda ingin lebih presisi daripada yang diberikan BRAM, Anda bisa melakukan interpolasi linier sederhana dari dua entri LUT. Sebagai contoh, katakanlah Anda menginginkan input 12-bit, tetapi Anda hanya memiliki BRAM untuk 10 bit. Anda mengambil 10 bit teratas dari input Anda dan mencarinya di LUT. Tambahkan 1 ke 10 bit itu dan cari nilainya juga. Anda kemudian melakukan interpolasi linier sederhana antara dua hasil, menggunakan 2 bit terbawah untuk memberi tahu Anda proporsi satu nilai di atas yang lain. Tentu saja ini hanya akan memberi Anda perkiraan, tetapi saya pikir jika Anda menghitung, Anda akan menemukan bahwa itu mungkin cukup baik.

Metode ini adalah yang paling tidak akurat dengan angka bernilai rendah, tetapi saat input masuk ke nilai yang lebih tinggi, akurasi meningkat.

Optimalisasi metode di atas adalah dengan menggunakan BRAM sebagai ROM dual-port. Dengan cara ini Anda dapat membaca dua nilai tanpa menambah jumlah yang digunakan BRAM. Ini juga akan memungkinkan Anda untuk menghitung SQRT untuk setiap siklus clock, dengan beberapa penundaan perpipaan.

Kebetulan, metode ini juga berfungsi untuk SINE / COSINE juga!


sumber
Nilai kecil berarti x mendekati 0, itu sebabnya saya menarik dalam pendekatan nilai kecil dari \ sqrt {x}.
Ang Zhi Ping
1
@angzhiping "Mendekati nol" tidak membantu. Kita perlu mengetahui jangkauan dan akurasi. Apa yang Anda berikan adalah setengah dari jangkauan dan tidak ada keakuratannya. Hasil akhirnya adalah mengetahui jumlah bit input dan output. Juga penting adalah kecepatan yang dibutuhkan: dalam hal kecepatan jam dan jam per sqrt.
3

Coba pendekatan berikut

  • Jika angkanya negatif, tangani sesuai.
  • Jika angkanya 0, kembalikan 0.
  • Jika tidak:
  • normalisasikan ke angka dalam rentang [1/4, 1]: hitung berapa kali k Anda harus mengalikan angka Anda dengan 4 ( x <<= 2dalam C) hingga berada dalam kisaran di atas.
  • gunakan pendekatan arbitrer (perkiraan polinomial, metode Newton untuk sqrt a [n] = (a [n-1] + k / a [n-1]) / 2, dll.) untuk menghitung akar kuadrat dalam rentang ini
  • denormalize: bergeser ke kanan oleh k bits
Jason S
sumber
0

Mencoba x=(y+d)2y2+2dy jadi biarkan d=(x-y2)/2y=(x/y-y)1 dan selanjutnya y=y+d. Jika MSb adalah n dari kanan, biarkan duluy=1(n/2). Berkonvergensi dalam <4 iterasi.

Byron
sumber
0

Coba: tebakan yang lebih baik untuk variabel 1

Nomor Anda dapat dianggap: A * 2 ^ n
Perkiraan pertama adalah: A * 2 ^ (n / 2)

Katakanlah Anda menggunakan angka 32-bit, dengan 24 bit digunakan untuk menyimpan pecahan. Untuk angka> 1:
1. Hitung jumlah bit yang digunakan dalam bagian integer (N)
2. Membagi dua angka ini (N '= N / 2, mis. Bergeser ke kanan 1 bit)
3. Geser ke kanan angka asli dengan N' : ini adalah tebakan pertama Anda.

Dalam format ini, jumlah terkecil yang dapat Anda miliki adalah 2 ^ -24. Root kuadrat akan ba sekitar 2 ^ -12. Jadi, untuk angka <1:
1. Hitung jumlah bit "nol" di dalam fraksi, hingga Anda mencapai bit yang ditentukan (N)
2. Membagi dua angka ini (N '= N / 2, mis. Kanan bergeser 1 bit)
3. KIRI menggeser nomor asli dengan jumlah yang direvisi: ini adalah tebakan pertama Anda.

Contoh:
0,0000 0000 0000 0000 1 [16 angka nol terkemuka] kira-kira sama dengan: 0,0000 0000 1

Akhirnya, jika Anda masih memiliki masalah dengan A kecil: dapatkah Anda menghitung 1 / A?
Jika demikian, maka balikkan nomor Anda, lalu coba gunakan algoritma Inverse Square Root:
x' = 0.5x * (3 - Ax^2)

Alan Campbell
sumber