前幾天和同事聊天,他說他上初中的兒子做出了一道很難的數(shù)學(xué)題,想考考我們這些大學(xué)生看能不能做得出來?
題目很簡單:
數(shù)學(xué)題目
大家先嘗試做一下?我沒想出怎么算的,只是用排除法確定了a和b的范圍,然后再逐個嘗試。
1.對4361進(jìn)行開方計(jì)算,得到結(jié)果最大為66,則a,b的值均小于等于66。
2.對4361/2進(jìn)行開方計(jì)算,則得到結(jié)果為46,則a,b兩者,一個是1-46,一個是46-66之間的數(shù)。
3.由平方和4361末尾為1,再根據(jù)整數(shù)平方和的幾種可能,計(jì)算出僅有0+1和5+6這兩種可能,而且平方之后的個位數(shù)為0/1/5/6,這樣就進(jìn)一步縮小了范圍,通過多次計(jì)算嘗試可以得出結(jié)果。
不過我懶得算了,就簡單寫了個C語言程序,計(jì)算出了結(jié)果:
#include
#include
#include
intmain(void)
{
intnum;
inta,b,n;
intresult;
intsqr;
printf("pleaseenteranumber:");//4361
scanf("%d",&num);
printf("inputnum:%d
",num);
sqr=sqrt(num);
for(a=1;a<=?sqr;?a++)????????//可以設(shè)置1-46
{
for(b=1;b<=?sqr;?b++)????//可以設(shè)置46-66
{
result=pow(a,2)+pow(b,2);
if(result==num)
{
printf("a=%2d,b=%2d,a+b=%d
",a,b,a+b);
n++;
}
}
}
if(n==0)
printf("Thereisnoanswer!
");
return0;
}
其實(shí)可以設(shè)置一個數(shù)的循環(huán)范圍是:1-46,一個數(shù)的循環(huán)范圍是46-66,這樣會減少循環(huán)次數(shù)。
運(yùn)行結(jié)果:
運(yùn)行結(jié)果而且這種方式還適用于解的個數(shù)不唯一的情況,比如7605:
運(yùn)行結(jié)果作為一個野生FPGA開發(fā)者,我在想能不能用FPGA的編程思想來實(shí)現(xiàn)呢?也就是如何用Verilog來實(shí)現(xiàn)兩個循環(huán)的嵌套呢?抄起鍵盤就是干!
verilog源文件fpga_math.v:
modulefpga_math(
//inputs
inputclk,
inputrst_n,
//outputs
outputreg[13:0]a,b,
outputreg[14:0]result,
outputok
);
parameterSUM=4361;
parameterSQR=67;//sqrt(SUM);
reg[13:0]tmp_a;
reg[13:0]tmp_b;
regflag;
assignok=(tmp_a*tmp_a+tmp_b*tmp_b==SUM);
always@(posedgeclk)
begin
if(!rst_n)
tmp_b<=0;
elseif(tmp_b==SQR)
tmp_b<=?0;
elseif(tmp_a!=SQR)
tmp_b<=?tmp_b?+?1;
end
always@(posedgeclk)
begin
if(!rst_n)
flag<=0;
elseif(tmp_b==SQR)
flag<=?1;
else
flag<=?0;
end
always@(posedgeclk)
begin
if(!rst_n)
tmp_a<=0;
elseif((tmp_a!=SQR)&flag)
tmp_a<=?tmp_a?+?1;
end
always@(posedgeclk)
begin
if(!rst_n)
begin
a<=0;
b<=?0;
result<=?0;
end
elseif(ok)
begin
a<=tmp_a;
b<=?tmp_b;
????????result?=?tmp_a?+?tmp_b;
????end
end
endmodule
為了驗(yàn)證這個模塊的正確性,我們需要對這個模塊進(jìn)行仿真,即給一個激勵輸入信號,看輸出是否正確。
新建testbench文件fpga_math_tb.v:
`timescale1ns/100ps
modulefpga_math_tb;
parameterSUM=4361;
parameterSQR=67;//sqrt(4361)
parameterSYSCLK_PERIOD=10;//100MHZ
wire[13:0]a,b;
wire[14:0]result;
regSYSCLK;
regNSYSRESET;
initial
begin
SYSCLK=1'b0;
NSYSRESET=1'b0;
#(SYSCLK_PERIOD*10)
NSYSRESET=1'b1;
#(SYSCLK_PERIOD*(SQR*SQR+500))
$stop;
end
/*generateclock*/
always@(SYSCLK)
#(SYSCLK_PERIOD/2.0)SYSCLK<=?!SYSCLK;???????
/*instancemodule*/
fpga_math#(
.SUM(SUM),
.SQR(SQR)
)fpga_math_0(
//inputs
.clk(SYSCLK),
.rst_n(NSYSRESET),
//outputs
.a(a),
.b(b),
.result(result),
.ok(ok)
);
endmodule
ModelSim仿真波形:
仿真波形仿真工具除了使用各大FPGA廠商IDE帶的ModelSim等,也可以使用小巧開源的全平臺仿真工具:iverilog+gtkwave,使用方法可以參考:
全平臺輕量開源verilog仿真工具iverilog+GTKWave使用教程
如果使用iverilog進(jìn)行仿真,需要在TB文件中添加以下幾行語句:
/*iverilog*/
initial
begin
$dumpfile("wave.vcd");//生成的vcd文件名稱
$dumpvars(0,fpga_math_tb);//tb模塊名稱
end
/*iverilog*
首先,對Verilog源文件進(jìn)行編譯,檢查是否有語法錯誤,這會在當(dāng)前目錄生成wave目標(biāo)文件:
iverilog-owave*.v
然后通過vvp
指令,產(chǎn)生仿真的wave.vcd
波形文件:
vvp-nwave-lxt2
使用gtkwave
打開波形文件:
gtkwavewave.vcd
當(dāng)然,以上命令也可以寫成批處理文件:
echo"開始編譯"
iverilog-owave*.v
echo"編譯完成"
echo"生成波形文件"
vvp-nwave-lxt2
echo"打開波形文件"
gtkwavewave.vcd
以文本方式存儲為build.bat
文件即可,雙擊即可自動完成編譯、生成波形文件、打開波形文件操作。
仿真波形:
仿真波形可以看出,和使用ModelSim仿真是一樣的結(jié)果。
總結(jié)
從仿真波形圖中,可以得到計(jì)算的結(jié)果,a+b的值為91,如果要在真實(shí)的FPGA芯片硬件上實(shí)現(xiàn),還需要添加其他功能模塊,把結(jié)果通過串口輸出,或者在數(shù)碼管等顯示屏上進(jìn)行顯示,這里只是簡單介紹使用FPGA計(jì)算方法的實(shí)現(xiàn)。
作為純數(shù)字電路的FPGA,實(shí)現(xiàn)平方根是比較復(fù)雜的,這里采用直接人為輸入平方根結(jié)果的方式,而不是像C語言那樣調(diào)用sqrt函數(shù)自動計(jì)算平方根。
FPGA中不僅有觸發(fā)器和查找表,而且還有乘法器、除法器等硬核IP,所以在涉及到乘除法、平方根運(yùn)算時,不要直接使用*/等運(yùn)算符,而是要使用FPGA自帶的IP核,這樣就不會占用大量的邏輯資源,像Xilinx的基于Cordic算法的Cordic IP核,不僅能實(shí)現(xiàn)平方根計(jì)算,而且還有sin/cos/tan/arctan等三角函數(shù)。
END 審核編輯 :李倩-
FPGA
+關(guān)注
關(guān)注
1630文章
21796瀏覽量
606009 -
C語言
+關(guān)注
關(guān)注
180文章
7614瀏覽量
137714 -
編程
+關(guān)注
關(guān)注
88文章
3637瀏覽量
93983
原文標(biāo)題:如何用FPGA解一道初中數(shù)學(xué)題?
文章出處:【微信號:gh_c472c2199c88,微信公眾號:嵌入式微處理器】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論