LongNumber
LongNumber::operator* (const LongNumber& number)
{
LongNumber result;
// Ссылки на большее и меньшее по модулю исходные числа.
// Обычно при умножении в столбик, сверху записывают
// большее число. Поступим также.
const LongNumber *big, *small;
// Сравниваем модули чисел и присваиваем ссылки на них
// соответствующим указателям.
if (compareModules(*this, number) < 0) {
big = this;
small = &number;
}
else {
small = this;
big = &number;
}
// Присваиваем результирующему числу знак.
result.sign_ = this->sign_ * number.sign_;
// Результирующее число не может иметь большую
// разрядность чем удвоеная разрядность большего из исходных
// чисел. Впоследствии лишние старшие разряды результата
// будут обрезаны.
result.setLength(big->length_ * 2);
// Временные переменные.
int over, res, final, finOver, i, j;
over = res = 0;
// Во внешнем цикле перебираем поочередно разряды меньшего из чисел,
// как мы делали это в школе.
for (i = 0; i < small->length_; i++)
{
// Во внутреннем цикле перемножаем поочередно разряды большего
// числа на текущий разряд меньшего.
for (j = 0; j < big->length_; j++)
{
// Вычисляем произведение текущих разрядов и прибавляем к нему
// значение [i+j] разряда результирующего числа.
res = small->array_[i] * big->array_[j] + result.array_[i + j];
// Если результат предыдущей операции (res) оказался больше
// основания, значит в [i+j] разряде результирующего числа следует
// оставить остаток от деления res на основание (res % BASE),
// а остальное перенести в следующий по старшинству разряд.
if (res >= BASE)
{
result.setDigit(i + j, res % BASE);
// То, что будет перенесено в следующий разряд.
over = res / BASE;
// Вычисляем сумму следующего по старшинству разряда результата и over.
final = result.array_[i + j + 1] + over;
// Если эта сумма (final) также получилась больше основания,
// то начинаем переносить лишнее в следующие по старшинству разряды,
// до тех пор, пока final не станет меньше основания.
if (final >= BASE)
{
finOver = final / BASE;
int k = 1;
while (finOver > 0) {
result.setDigit(i + j + k, final % BASE);
k++;
final = result.getDigit(i + j + k) + finOver;
result.setDigit(i + j + k, final % BASE);
finOver = final / BASE;
}
}
// Иначе, записываем final в следующий по старшинству разряд
// и обнуляем over.
else
{
result.setDigit(i + j + 1, final);
over = 0;
}
}
// Иначе записываем res в [i+j] разряд.
else
{
result.setDigit(i + j, res);
}
}
}
// Отрежем ведущие нули, если они есть.
int zeros = 0;
for (int dig = 0, i = result.length_ - 1; dig == 0; i--) {
dig = result.array_[i];
if (dig == 0) zeros++;
}
LongNumber r;
r.setLength(result.length_ - zeros);
for (int i = 0; i < result.length_ - zeros; i++)
r.setDigit(i, result.array_[i]);
// Установим знак результирующего числа
r.sign_ = this->sign_ * number.sign_;
return r;
}
Деление: реализация операции деления "в столбик" примечальна тем, что требует на каждом шаге нахождения такого максимального x, который удовлетворял бы неравенству: x * a ≤ b, где a - делитель, а b - число, состоящее из старших разрядов делимого, и большее либо равное делителя. Причем x ∊ [1..9999]. В нашем случае нахождение такого числа реализовано методом бинарного поиска. Также, в случае деления на ноль, выводится соответствующее сообщение и возвращается нулевое длинное число.