Веселий виклик. :)
Я припускаю, що вам потрібні цілі числа довільної довжини. Я пропоную такий підхід:
Розглянемо двійкову природу типу даних "int". Подумайте про те, щоб використовувати прості двійкові операції, щоб імітувати те, що роблять схеми вашого процесора, коли вони додають речі. Якщо ви зацікавлені більш детально, подумайте прочитати цю статтю Вікіпедії про напівсумарі та повні додавачі . Ви будете робити щось подібне до цього, але ви можете спуститися на такий низький рівень - але, будучи лінивим, я думав, що я просто відмовився і знайду ще більш просте рішення.
Але перш ніж вдаватися до будь-яких алгоритмічних подробиць щодо додавання, віднімання, множення, давайте знайдемо певну структуру даних. Звичайно, простий спосіб зберігати речі у std :: vector.
template< class BaseType >
class BigInt
{
typedef typename BaseType BT;
protected: std::vector< BaseType > value_;
};
Можливо, ви захочете розглянути, чи хочете ви зробити вектор фіксованого розміру і чи потрібно його попередньо розподілити. Причиною є те, що для різноманітних операцій вам доведеться пройти кожен елемент вектора - O (n). Можливо, вам захочеться дізнатись відразу, наскільки складною буде операція, і фіксована n робить саме це.
Але тепер до деяких алгоритмів роботи з числами. Ви можете зробити це на логічному рівні, але ми використаємо цю чарівну потужність процесора для обчислення результатів. Але те, що ми візьмемо з логічної ілюстрації Half- і FullAdders, - це спосіб, з яким він має справу. Як приклад, розглянемо, як ви реалізуєте оператор + = . Для кожного числа в BigInt <> :: value_, ви додасте їх і подивитеся, чи результат створює якусь форму перенесення. Ми не будемо робити це поступово, але покладаємось на природу нашого BaseType (будь то довгий чи int або короткий чи що завгодно): він переповнюється.
Звичайно, якщо ви додасте два числа, результат повинен бути більшим за більший із цих чисел, так? Якщо це не так, то результат переповнений.
template< class BaseType >
BigInt< BaseType >& BigInt< BaseType >::operator += (BigInt< BaseType > const& operand)
{
BT count, carry = 0;
for (count = 0; count < std::max(value_.size(), operand.value_.size(); count++)
{
BT op0 = count < value_.size() ? value_.at(count) : 0,
op1 = count < operand.value_.size() ? operand.value_.at(count) : 0;
BT digits_result = op0 + op1 + carry;
if (digits_result-carry < std::max(op0, op1)
{
BT carry_old = carry;
carry = digits_result;
digits_result = (op0 + op1 + carry) >> sizeof(BT)*8;
}
else carry = 0;
}
return *this;
}
Інші арифметичні дії йдуть аналогічно. Чорт, ви навіть можете використовувати stl-функтори std :: plus та std :: minus, std :: times та std :: розділяє, ..., але майте на увазі перенесення. :) Ви також можете реалізувати множення і ділення, використовуючи оператори плюс і мінус, але це дуже повільно, оскільки це перераховує результати, які ви вже обчислили в попередніх викликах, на плюс і мінус у кожній ітерації. Існує багато хороших алгоритмів для цього простого завдання, використовуйте wikipedia або Інтернет.
І звичайно, вам слід застосувати стандартні оператори, такі як operator<<
(просто змістіть кожне значення у value_ вліво на n бітів, починаючи з value_.size()-1
... о, і пам'ятайте перенесення :), operator<
- тут ви навіть можете трохи оптимізувати, перевіряючи приблизна кількість цифр з size()
першою. І так далі. Тоді зробіть свій клас корисним за допомогою befriendig std :: ostream operator<<
.
Сподіваюся, такий підхід корисний!