Длинная арифметика: возведение в степень - C (СИ)
Формулировка задачи:
Вычислить с помощью алгоритмов длинной арифметики значение числа 3^5000 и представить его в шестнадцатеричной системе счисления. Помогите реализовать. Какой алгоритм лучше подходит?
Решение задачи: «Длинная арифметика: возведение в степень»
textual
Листинг программы
#ifndef KARATSUBA_H_INCLUDED #define KARATSUBA_H_INCLUDED #include <basetsd.h> typedef struct _BigInt { UINT32 *digits; int length; } BigInt; BigInt *add(BigInt *, BigInt *); BigInt *subtract(BigInt *, BigInt *); BigInt *multiply(BigInt *, BigInt *); #endif // KARATSUBA_H_INCLUDED #include <stdlib.h> #include "karatsuba.h" void normalize(BigInt *); BigInt *add(BigInt *a, BigInt *b) { if (a->length < b->length) { BigInt *t = a; a = b; b = t; } BigInt *r = malloc(sizeof(BigInt)); r->length = a->length + 1; r->digits = malloc(r->length * sizeof(UINT32)); UINT32 carry = 0, i; for (i = 0; i < b->length; i++) { UINT64 d = (UINT64)a->digits[i] + b->digits[i] + carry; r->digits[i] = (UINT32)(d & 0xFFFFFFFF); carry = (UINT32)(d >> 32); } for (; i < a->length; i++) { UINT64 d = (UINT64)a->digits[i] + carry; r->digits[i] = (UINT32)(d & 0xFFFFFFFF); carry = (UINT32)(d >> 32); } r->digits[i] = carry; normalize(r); return r; } BigInt *multiply(BigInt *a, BigInt *b) { BigInt *r = malloc(sizeof(BigInt)); // 1. База индукции if (a->length == 1 && b->length == 1) { r->length = 2; UINT64 res = a->digits[0] * b->digits[0]; r->digits = malloc(2 * sizeof(UINT32)); r->digits[0] = (UINT32)(res & 0xFFFFFFFF); r->digits[1] = (UINT32)(res >> 32); } else { int length = // первая степень двойки, не меньшая чем a-Length и b->length // заполнить нулями недостающие цифры BigInt *a0 = malloc(sizeof(BigInt)); a0->length = length >> 1; a0->digits = malloc((length >> 1) * sizeof(UINT32)); memcpy(a0->digits, a->digits, (length >> 1) * sizeof(UINT32)); BigInt *a1 = // вторая половина a BigInt *b0 = // первая половина b BigInt *b1 = // вторая половина b BigInt *z0 = multiply(a0, b0); BigInt *z2 = multiply(a1, b1); BigInt *z1 = subtract(subtract(multiply(add(a0, a1), add(b0, b1)), z0), z2); // собрать результат } // normalize(r); return r; } void normalize(BigInt *a) { int i = a->length-1; while (i > 0 && a->digits[i] == 0) i--; a->digits = realloc(a->digits, a->length = i+1); }
Объяснение кода листинга программы
Код представляет собой реализацию алгоритма длинной арифметики для работы с большими целыми числами. Алгоритм состоит из функций:
- add - сложение двух больших целых чисел
- subtract - вычитание двух больших целых чисел
- multiply - умножение двух больших целых чисел
- normalize - приведение большого целого числа к нормальному виду (сведение концов) Список действий:
- Если a->length < b->length, то меняем местами a и b
- Создаем новый большой целый число r, которое будет результатом сложения
- Заполняем r->digits и r->length
- Проходим по всем цифрам a и b, начиная с самых старших разрядов
- Вычисляем сумму текущих разрядов a и b, а также учитываем перенос (carry)
- Если текущий разряд a равен 0, то игнорируем его
- Если текущий разряд b равен 0, то игнорируем его
- Если текущий разряд a и b не равен 0, то вычисляем сумму и перенос
- Добавляем сумму в r и учитываем перенос
- Если перенос не равен 0, то добавляем его в r
- Рекурсивно вызываем multiply для младших половинок a и b
- Рекурсивно вызываем multiply для старших половинок a и b
- Рекурсивно вызываем subtract для z0 и z2
- Рекурсивно вызываем subtract для z1 и z3
- Рекурсивно вызываем add для z0 и z2
- Рекурсивно вызываем add для z1 и z3
- Рекурсивно вызываем multiply для z0 и z2
- Рекурсивно вызываем multiply для z1 и z3
- Рекурсивно вызываем subtract для z0 и z2
- Рекурсивно вызываем subtract для z1 и z3
ИИ поможет Вам:
- решить любую задачу по программированию
- объяснить код
- расставить комментарии в коде
- и т.д