Неограниченная реализация целочисленного списка без знака. Вычитание не работает

Итак, я реализовал целый целочисленный класс Unlimited Unsigned, используя связанный список для задачи Эйлера проекта, над которой я работаю. Я проверил, что все логические операции с битами верны (хотя я могу опубликовать, если вы хотите их видеть). Я уже реализовал все операторы и операции. Однако вычитание (и все, что его использует, то есть деление и модуль) не работает. Когда я запускаю следующий тест, это то, что я получаю:

  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

Решение

После добавления двух дополнений вы добавляете, который использует нулевое расширение, когда ширины не равны. Когда вы расширяете вычитаемое (теперь добавляемое) шириной, равной уменьшаемому, вы должны использовать расширение знака, а не нулевое расширение. Это связано с тем, что значение дополнения двух должно рассматриваться в этом контексте как отрицательное число (несмотря на то, что все остальное не подписано в другом месте). В качестве альтернативы (и, возможно, в большей степени в соответствии с общим дизайном), вычитаемое и уменьшаемое должны быть одинаковой ширины, прежде чем начинать с дополнения.

Вы делаете что-то вроде этого:

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
3

Другие решения

Однажды некоторые инженеры из Control Data Corporation (CDC) изобрели сумматор с одним циклом (до этого сумматор брал один цикл на бит, распространяющий перенос), и CDC запатентовал изобретение. Затем инженеры наняли Крэя, и они хотели быстрого сумматора. Таким образом, умные инженеры изобрели быстрый взгляд на заемщика, и Крэй запатентовал это.

Мораль истории — сложение и вычитание — это одно и то же, и ваш код вычитания должен выглядеть почти так же, как ваш код сложения.

0

По вопросам рекламы [email protected]