因此,我使用链接列表实现了一个完整的Unlimited Unsigned整数类,用于我正在处理的项目Euler问题。我已经验证所有逻辑位操作都是正确的(尽管如果你想看到它们我可以发布)。我已经实现了所有运营商和运营。但是,减法(以及使用它的所有内容,即除法和模数)都不起作用。当我运行以下测试时,这就是我得到的:
LimitlessUnsigned limitless = 0x88888888u;
limitless = limitless << 4;
LimitlessUnsigned tester = 0x88888884u;
tester = tester << 4;
//limitless = limitless >> 5;
LimitlessUnsigned another = limitless - tester;
我从调试器中获取以下值:
another LimitlessUnsigned
integerList std::__1::list<unsigned int, std::__1::allocator<unsigned int> >
[0] unsigned int 0b11111111111111111111111111111111
[1] unsigned int 0b00000000000000000000000001000000
limitless LimitlessUnsigned
integerList std::__1::list<unsigned int, std::__1::allocator<unsigned int> >
[0] unsigned int 0b00000000000000000000000000001000
[1] unsigned int 0b10001000100010001000100010000000
tester LimitlessUnsigned
integerList std::__1::list<unsigned int, std::__1::allocator<unsigned int> >
[0] unsigned int 0b00000000000000000000000000001000
[1] unsigned int 0b10001000100010001000100001000000
似乎我错过了减法和两个赞美的定义。代码工作,直到我需要添加额外的32位。我考虑到溢出,从前32到下32。但是,我在最高位丢弃溢出(我想我应该)。显然,我没有正确地做到这一点。以下是相关的源代码。
void LimitlessUnsigned::Sub(const LimitlessUnsigned& other)
{
if(*this <= other)
{
*this = 0u;
return;
}
LimitlessUnsigned temp = other;
while(temp.integerList.size() > integerList.size())
integerList.push_front(0u);
while(integerList.size() > temp.integerList.size())
temp.integerList.push_front(0u);
temp.TwosComp();
Add(temp, true);
}
void LimitlessUnsigned::Add(const LimitlessUnsigned& other, bool allowRegisterLoss)
{
LimitlessUnsigned carry = *this & other;
LimitlessUnsigned result = *this ^ other;
while(carry != 0u)
{
carry.ShiftLeft(1, allowRegisterLoss);
LimitlessUnsigned shiftedcarry = carry;
carry = result & shiftedcarry;
result = result ^ shiftedcarry;
}
*this = result;
}
void LimitlessUnsigned::Not()
{
for(std::list<unsigned>::iterator iter = integerList.begin(); iter != integerList.end(); ++iter)
{
*iter = ~*iter;
}
}
void LimitlessUnsigned::TwosComp()
{
Not();
Add(1u, true);
}
void LimitlessUnsigned::ShiftLeft(unsigned shifts, bool allowRegisterLoss)
{
unsigned carry = 0u;
bool front_carry = false;
while(shifts > 0u)
{
if((integerList.front() & CARRY_INT_HIGH) == CARRY_INT_HIGH)
front_carry = true;
for(std::list<unsigned>::reverse_iterator iter = integerList.rbegin(); iter != integerList.rend(); ++iter)
{
unsigned temp = *iter;
*iter = *iter << 1;
*iter = *iter | carry;
if((temp & CARRY_INT_HIGH) == CARRY_INT_HIGH)
carry = CARRY_INT;
else
carry = 0u;
}
carry = 0u;
if(front_carry && !allowRegisterLoss)
{
front_carry = false;
integerList.push_front(1u);
}
--shifts;
}
}
更新 我终于解决了这个问题。这是我的博客文章以及源代码:
http://memmove.blogspot.com/2013/04/unlimited-unsigned-integer-in-c.html
答案 0 :(得分:3)
在取两个补码之后,你正在添加,当宽度不相等时使用零扩展。当您将减数(现在为加数)扩展为与minuend一样宽时,您需要使用符号扩展,而不是零扩展。这是因为在这种情况下,需要将两个补码值视为负数(尽管其他地方都未签名)。或者(也许更多地与整体设计保持一致),在开始两个补充业务之前,减数和减数必须是相同的宽度。
你正在做这样的事情:
0110 - 10 = 0110 + (~(10) + 1)
= 0110 + (01 + 1)
= 0110 + 10
= 0110 + 0010
= 1000
应该是:
0110 - 10 = 0110 + (~(10) + 1)
= 0110 + (01 + 1)
= 0110 + 10
= 0110 + 1110 <= sign-extended subtrahend
= 0100
或者:
0110 - 10 = 0110 - 0010 <= widths equalized
= 0110 + (~(0010) + 1)
= 0110 + (1101 + 1)
= 0110 + 1110
= 0100
答案 1 :(得分:0)
曾几何时,Control Data Corporation(CDC)的一些工程师发明了单周期加法器(在此之前,加法器每位传播一个周期传播该进位),CDC为本发明申请了专利。然后工程师被Cray聘用,他们想要一个快速加法器。因此,聪明的工程师发明了借用减法器和Cray专利的快速外观。
故事的士气是加法和减法是一回事,你的减法代码应该与你的加法代码几乎相同。