Можно ли создать тип переменной в си с любым размером

Можно ли создать тип переменной в си с любым размером, и чтоб можно было работать с битовыми операциями!. Вот я хочу создать аналог int который будет 128 битовый, или 256 битовый итд И чтоб я мог складывать и вычитать и делить итд


Ответы (1 шт):

Автор решения: Mark Shevchenko

Принципиально в C это сделать можно, но выглядеть будет не так удобно, как, например, в объектно-ориентированном языке с перегрузкой операторов, таком, как C++.

Сначала, о том, как это делается в принципе. Огромные числа можно представить как последовательности (массивы) байтов.

Для простоты представим, что числа у нас беззнаковые и хранятся в массиве из 20-ти байт.

unsigned char a[20] = { 0x00, 0x00, …, 0xC0, 0xD0 };
unsigned char b[20] = { 0x00, 0x01, …, 0xF0, 0xFF };
unsigned char c[20];

В каждом байте может храниться 256 разных значений, поэтому наш массив представляет как бы 20-тизначное число в системе счисления 256.

Оно равно 25619*c[0]+25618*c[1]+...+2561*c[18]+2560*c[19]

Такой порядок соответствует тому, как мы записываем числа на бумаге: сначала старшие разряды, а в конце младшие, сначала миллионы, в конце единицы.

Чтобы сложить два больших числа мы действуем также, как и при сложении в столбик, начиная с младших разрядов.

Если бы мы складывали 17 и 25, то сначала бы сложили 7 и 5 и получили бы 12. Мы записали в младший разряд результата 2 (остаток от деления 12 на 10, потому что у нас десятичная система). Поскольку 12 больше 10, нам придётся прибавить 1 к сумме 1 и 2, то есть «перенести единицу».

Сложение чисел с 256-тизначной системе выглядит точно также. Начинать надо с младшего 19-го байта и подниматься к старшему 0-му байту:

unsigned char curry = 0;
for (int i = 19; i >= 0; i--) {
    int sum = a[i] + b[i] + curry;
    c[i] = sum % 256;
    curry = sum > 256 ? 1 : 0;
}

Здесь curry это значение переноса. Оно равно 0, если переноса нет, то есть сумма на предыдущем шаге меньше 256. Оно равно 1, если перенос есть. В c[i] мы сохраняем остаток от деления суммы двух цифр на 256.

Всё точно также, как и со сложением десятичных чисел, только вместо 10 у нас 256.

Естественно, алгоритм можно обобщить на массивы любой длины. В этом случае вам придётся хранить не только его байты-цифры, но и длину массива.

Для алгоритма умножения можно адаптировать умножение в столбик, либо использовать более быстрый алгоритм, такой как алгоритм Карацубы.

В C работу с большими числами нельзя сделать простой, потому что вам придётся написать функции сложения, которые вы будете вызывать приблизительно так:

BIGINT* a = bigint_from_int(100);
BIGINT* b = bigint from_str("9035801984122098342750239485334875");
BIGINT* c = bigint_add(a, b);

В C++ вы можете спрятать детали реализации внутрь класса и определить для него операторы сложения, умножения и так далее:

bigint a(100);
bigint b("9035801984122098342750239485334875");
bigint c = a + b;

В сети есть множество библиотек с открытым кодом, где это уже сделано, например kasparsklavins/bigint на GitHub.

→ Ссылка