Молодогвардейцев 454015 Россия, Челябинская область, город Челябинск 89085842764
MindHalls logo

Реализация больших чисел на C/C++ со сложением и вычитанием

Доброго времени суток и светлого неба над головой, дорогие друзья! Ни для кого из вас не секрет, что ограничение максимального и минимального значения целого числа, хоть и разнится на разных архитектурах, но существует. Например, для целого числа типа int диапазон его значений равен от –2147483647 – 1 до 2147483647. Казалось бы, 2 миллиарда в каждую сторону это целая гора, но как только вы займетесь настоящей криптографией, либо машинным обучением, теорией вероятностей или еще более крутой математикой, вы поймете, что это чертовски мало. Именно в таком случае на помощь приходят, так называемые, большие числа.

Идея большого числа в том, чтобы вылезти за рамки ограничений стандартных типов данных, оперировать бесконечно большими числами, размер которых будет ограничен только вычислительной мощностью «машины». Как этого достичь? Самый логичный способ заключается в том, чтобы записывать число в строку и конвертировать специальным образом в согласованный массив чисел стандартного типа.

Например, как можно хранить число 123456789123456789, в int оно не поместится. тогда мы поместим его в массив int`ов, mas[0] = 123456, mas[1] = 789123, mas[2] = 456789, напишем специальные алгоритмы, которые будут корректно складывать, вычитать, умножать и делить такие числа.

Как раз о таких алгоритмах инициализации, сложения и вычитания больших чисел я сейчас расскажу, поехали!

Другие статьи по теме

Как реализовать большие числа на C/C++

Сейчас я расскажу о том, как будет работать написанный нами специальный класс BigNumber с реализованной инициализацией числа из строки, сложением, вычитанием и выводом в поток. А после приведу полный листинг исходного кода с этим классом, снабженный комментариями. Вы можете читать описания, поглядывая на код. Я специально не стал дублировать функции, чтобы не нагромождать и без того длинный текст статьи.

Инициализация большого числа

Конструктор класса BigNumber(string str), принимающий на вход строку, работает следующим образом. Начиная с конца строки отсекаются подстроки длины BASE, конвертируются в числа и закидываются в вектор chunks. В зависимости от наличия минуса в строке инициализируется еще одно приватное поле класса — sign. BASE это статическое константное поле, одинаковое для всех объектов класса, чтобы не было конфликтов в нормализации.

Сложение больших чисел

Для сложения мы перегрузим оператор +, он в свою очередь будет вызывать метод _plus(), который сложит два больших числа «почанково». Кроме того, перед самим сложением необходимо сделать одинаковыми размеры векторов chunks обоих чисел. А после сложения  нормализовать результат функцией _normalizationChunks(). Нормализовать — значит сделать так, чтобы во всех чанках лежали BASE-разрядные числа (если BASE = 2, то только двузначные числа).

Вычитание больших чисел

Вычитание работает аналогично сложению, перегружается оператор —, используется метод _minus().

Вывод большого числа в поток

Вывод происходит благодаря перегрузке оператора <<, но перед самим выводом, число нужно нормализовать функцией _normalizationSigns(). Она почистит все нулевые чанки, отрицательные числа в чанках, корректно установит знак числа.

Исходный код реализации больших чисел на C/C++

Теперь непосредственно сама реализация с комментариями.

Заключение

Данная реализация не является оптимизированной по используемой памяти, особенно при маленьких значениях BASE, но является вполне рабочим вариантом. Кроме сложения и вычитания, большой интерес вызывает умножение (деление так вообще). Но с умножением разберемся как нибудь в следующий раз. А на сегодня у меня все, спасибо за внимание!