Длинная арифметика: возведение в степень - 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);
}

Объяснение кода листинга программы

Код представляет собой реализацию алгоритма длинной арифметики для работы с большими целыми числами. Алгоритм состоит из функций:

  1. add - сложение двух больших целых чисел
  2. subtract - вычитание двух больших целых чисел
  3. multiply - умножение двух больших целых чисел
  4. normalize - приведение большого целого числа к нормальному виду (сведение концов) Список действий:
  5. Если a->length < b->length, то меняем местами a и b
  6. Создаем новый большой целый число r, которое будет результатом сложения
  7. Заполняем r->digits и r->length
  8. Проходим по всем цифрам a и b, начиная с самых старших разрядов
  9. Вычисляем сумму текущих разрядов a и b, а также учитываем перенос (carry)
  10. Если текущий разряд a равен 0, то игнорируем его
  11. Если текущий разряд b равен 0, то игнорируем его
  12. Если текущий разряд a и b не равен 0, то вычисляем сумму и перенос
  13. Добавляем сумму в r и учитываем перенос
  14. Если перенос не равен 0, то добавляем его в r
  15. Рекурсивно вызываем multiply для младших половинок a и b
  16. Рекурсивно вызываем multiply для старших половинок a и b
  17. Рекурсивно вызываем subtract для z0 и z2
  18. Рекурсивно вызываем subtract для z1 и z3
  19. Рекурсивно вызываем add для z0 и z2
  20. Рекурсивно вызываем add для z1 и z3
  21. Рекурсивно вызываем multiply для z0 и z2
  22. Рекурсивно вызываем multiply для z1 и z3
  23. Рекурсивно вызываем subtract для z0 и z2
  24. Рекурсивно вызываем subtract для z1 и z3

ИИ поможет Вам:


  • решить любую задачу по программированию
  • объяснить код
  • расставить комментарии в коде
  • и т.д
Попробуйте бесплатно

Оцени полезность:

6   голосов , оценка 4.333 из 5
Похожие ответы