在下面的代碼中,我使用與問題中相同的想法實現加法和減法。唯一實際的區別是在我的實現中,這兩個函數還會帶入一個進位/借入位併產生一個進位/借位位。
進位位用於通過加法實現減法,該位有助於獲得進位和退出位的正確值。基本上,我用狀態寄存器中的進位標誌來實現典型的類CPU加法和減法。
進位/借位位然後用於通過減法來實現比較。我在沒有>=
算子的情況下執行比較,我也認爲算術算術,因爲它不太具有比特性。由於使用了restoring division algorithm,所以在除法功能中需要比較功能。
我也避免使用!
運營商和使用^1
來代替。
除法函數將除數作爲2 unsigned ints
,它是最重要和最不重要的部分。最後,它將最重要的部分替換爲剩餘部分,將最不重要的部分替換爲商。因此,它可以進行除法和模運算,並以類似CPU的方式執行它們(例如,像x86 DIV
指令)。該函數成功時返回1,溢出/除法時返回0.
主函數做了一個簡單的測試。它將劃分功能的結果與直接劃分的結果進行比較,並以不匹配的錯誤消息結束。
我在測試部分使用unsigned long long
可以測試除數= UINT_MAX
而不會陷入無限循環。測試分紅和除數的整個範圍值可能需要很長時間,這就是爲什麼我分別將它們限制在0xFFFF和0xFF而不是UINT_MAX
。
代碼:
#include <stdio.h>
#include <limits.h>
unsigned add(unsigned a, unsigned b, unsigned carryIn, unsigned* carryOut)
{
unsigned sum = a^b^carryIn;
unsigned carryOuts = a & b | (a | b) & carryIn;
*carryOut = 0;
if (sum & (carryOuts << 1))
sum = add(sum, carryOuts << 1, 0, carryOut);
else
sum |= carryOuts << 1;
*carryOut |= (carryOuts & (UINT_MAX/2 + 1)) >> (sizeof(unsigned) * CHAR_BIT - 1); // +-*/ are OK in constants
return sum;
}
unsigned sub(unsigned a, unsigned b, unsigned borrowIn, unsigned* borrowOut)
{
unsigned diff = add(a, ~b, borrowIn^1, borrowOut);
*borrowOut ^= 1;
return diff;
}
unsigned less(unsigned a, unsigned b)
{
unsigned borrowOut;
sub(a, b, 0, &borrowOut);
return borrowOut;
}
int udiv(unsigned* dividendh, unsigned* dividendl, unsigned divisor)
{
int i;
unsigned tmp;
if (less(*dividendh, divisor)^1/* *dividendh >= divisor */)
return 0; // overflow
for (i = 0; i < sizeof(unsigned) * CHAR_BIT; i++)
{
if (less(*dividendh, UINT_MAX/2 + 1)^1/* *dividendh >= 0x80...00 */)
{
*dividendh = (*dividendh << 1) | (*dividendl >> (sizeof(unsigned) * CHAR_BIT - 1));
*dividendl <<= 1;
*dividendh = sub(*dividendh, divisor, 0, &tmp);/* *dividendh -= divisor; */
*dividendl |= 1;
}
else
{
*dividendh = (*dividendh << 1) | (*dividendl >> (sizeof(unsigned) * CHAR_BIT - 1));
*dividendl <<= 1;
if (less(*dividendh, divisor)^1/* *dividendh >= divisor */)
{
*dividendh = sub(*dividendh, divisor, 0, &tmp);/* *dividendh -= divisor; */
*dividendl |= 1;
}
}
}
return 1;
}
int udiv2(unsigned* dividendh, unsigned* dividendl, unsigned divisor)
{
unsigned long long dividend =
((unsigned long long)*dividendh << (sizeof(unsigned) * CHAR_BIT)) | *dividendl;
if (*dividendh >= divisor)
return 0; // overflow
*dividendl = (unsigned)(dividend/divisor);
*dividendh = (unsigned)(dividend % divisor);
return 1;
}
int main(void)
{
unsigned long long dividend, divisor;
for (dividend = 0; dividend <= /*UINT_MAX*/0xFFFF; dividend++)
for (divisor = 0; divisor <= /*UINT_MAX*/0xFF; divisor++)
{
unsigned divh = 0, divl = (unsigned)dividend, divr = (unsigned)divisor;
unsigned divh2 = 0, divl2 = (unsigned)dividend;
printf("0x%08X/0x%08X=", divl, divr);
if (udiv(&divh, &divl, divr))
printf("0x%08X.0x%08X", divl, divh);
else
printf("ovf");
printf(" ");
if (udiv2(&divh2, &divl2, divr))
printf("0x%08X.0x%08X", divl2, divh2);
else
printf("ovf");
if ((divl != divl2) || (divh != divh2))
{
printf(" err");
return -1;
}
printf("\n");
}
return 0;
}
看起來你必須揭開'這個簡單的公式]結合乘法和減法來計算兩者的商和提醒,(https://en.wikipedia.org/wiki/剩餘部分) – C2H5OH
Badd() - Mike Jones –
根據[家庭作業指導](http://meta.stackexchange.com/questions/147100/the-homework-tag-is-now-officially-deprecated),這個問題也是設法成爲一個實際的編程問題,應該被視爲不是一個真正的問題。 –