前言
大家都知道51單片機是有乘法、除法指令的,不管是用C語言還是彙編語言,都是可以直接計算乘法、除法的,我以爲+,-,*,/ 這些算術運算是單片機的標配,而我公司使用的應廣單片機居然沒有乘法、除法指令,應廣單片機使用的是mini-C語言,和C語言有點像,可以在C代碼中穿插彙編指令。但mini-C不支持for循環,也不支持函數傳參,所以一下代碼都沒有傳參,也沒有for循環。
乘法
思路0
我們都知道左移1位(<<1)相當於乘2,左移2位(<<2)相當於乘4,但想乘3、乘5、乘6、乘7怎麼辦?
在已知要乘多少時,我們可以考慮這種方法
int a=13;
b=a<<1;//b=a*2
b=(a<<1)+a;//b=a*3
b=a<<2;//b=a*4
b=(a<<2)+a;//b=a*5
b=(a<<2)+a+a;//b=a*6
b=(a<<3)-a;//b=a*7
b=a<<3;//b=a*8
//.....
思路1
前面的方法顯然不是我想找的,也不是你想找的,我需要一個實現乘法的功能:a×b,a是變量,b也是變量。
再想想,例如做9×4時,我們是如何計算除法的?相信大家首先想到的是乘法口訣“四九三十六” 那是中國人太聰明瞭有乘法口訣,若是老外計算,可能就是“nine plus nine equals eighteen, eighteen plus nine equals twenty seven …”,乘法的本質就是把n個數相加,所以寫程序的時候做循環相加即可以實現乘法計算。
byte ma;//第一個因式,這裏byte等價於unsigned char
byte mb;//第二個因式
word mc;//計算結果,這裏word等價於unsigned int
void mult(void)
{
mc=0;
while(mb)
{
mc+=ma;
mb--;
}
}
很好理解,mb是幾,mc就循環加幾次ma,但這個方法在比較耗時,例如2×100時,2+2+2+2+…+2,這裏有100次加法運算。
思路2
小學乘法的豎式計算也同樣適用於二進制
因爲二進制只有0或1,ma×1=ma,ma×0=0;程序中只需要:
①判斷被乘數mb的最低位,若爲1則mc累加ma,爲0則不累加(或累加0)
②讓ma左移1位,mb右移1位
③再次回到①,直到mb變爲0,運算結束
word ma;//第一個因式,計算結果也存放在ma
byte mb;//第二個因式
void mult(void)
{
word t=0;
while(mb)
{
if(mb.0)//if(mb&0x01)
{
t+=ma;
}
ma<<=1;
mb>>=1;
}
ma=t;
}
對於上面是程序,大大減少了計算時間,最壞情況ma*11111111B需要循環8次,一共8次累加、8次左移、8次右移。
這個程序也可以做一點優化,先比較ma、mb的大小,用大的數乘以小的數。
這樣可以讓0000 0001B×1111 1111B這樣的乘法更快計算完成。
if(mb>ma)
{
t=mb; mb=ma; ma=t;
}
t=0;
除法
思路0
通過右移指令實現÷2、÷4、÷8等,但對於除以其他數卻不行了。
思路1
和乘法一樣,除法也可以理解爲減法。
例如:16個蘋果分給5個孩子
- 每個孩子拿1個,還剩16-5=11個
- 每個孩子再拿1個,還剩11-5=6個
- 每個孩子再拿1個,還剩6-5=1個
這時不夠每個孩子拿1個了,所以餘數是1,每個人都有3個,所以商是3。
byte ma;//被除數、商
byte mb;//除數、餘數
void div(void)
{
byte n=0;
while(ma>mb)
{
ma-=mb;
n++;
}
mb=ma;
ma=n;
}
這個方法對於被除數大、除數小的情況會耗時比較久。
大家可以考慮一下除數爲0會發生什麼,該怎麼解決。
思路2
同樣使用除法豎式來幫助理解
被除數高位需要對齊除數低位,再比較被除數與除數的大小決定要不要商1,但程序似乎不好寫。再來看另一張圖片
先將除數左移字長-1bit,就可以低位對齊並且可以相減了。
對照圖片中的思路應該很好理解下面的程序。
byte ma;//被除數、商
word mb;//除數、餘數
void div(void)
{
word t=0;
byte i=8;
mb<<=7;
while(i--)
{
t<<=1;
if(ma>=mb)
{
ma-=mb;
temp|=0x01;
}
mb>>=1;
}
mb=ma;//餘數
ma=t;//商
}