Умножение очень длинных целых чисел

Есть ли алгоритм для точного умножения двух целых чисел произвольной длины? Язык, с которым я работаю, ограничен длиной 64-битного целого числа без знака (максимальный размер целого числа 18446744073709551615). На самом деле, я хотел бы иметь возможность сделать это, разбивая каждое число, обрабатывая их каким-либо образом, используя беззнаковые 64-битные целые числа, а затем получая возможность снова объединить их в строку (что решило бы проблему умножения результата. место хранения).

Есть идеи?

Отметьте это> алгоритм умножения больших чисел

ARJUN 20.09.2014 10:32
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
7
1
14 762
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

Да, вы делаете это, используя тип данных, который фактически представляет собой строку цифр (точно так же, как обычная «строка» - это строка символов). Как вы это делаете, сильно зависит от языка. Например, Java использует BigDecimal. На каком языке ты говоришь?

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

Valdemarick 11.10.2008 03:58

Это часто дают в качестве домашнего задания. Алгоритм, который вы изучили в начальной школе, будет работать. Используйте библиотеку (некоторые из них упоминаются в других сообщениях), если вам это нужно для реального приложения.

Ответ принят как подходящий

В большинстве языков есть функции или библиотеки, которые делают это, обычно называемые библиотекой Bignum (GMP - хороший вариант).

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

Пример:

  45
 x67
 ---
 315
+270
----
 585

Или в двоичном формате:

   101
  x101
  ----
   101
  000
+101
------
 11001

Редактировать: Сделав это в двоичном формате, я понял, что было бы намного проще (и, конечно, быстрее) кодировать, используя побитовые операции вместо строк, содержащих числа с основанием 10. Я отредактировал свой пример двоичного умножения, чтобы показать шаблон: для каждого 1 бита в нижнем числе добавьте к переменной верхнее число, сдвинутое влево положение 1-битного раз. В конце эта переменная будет содержать продукт.

Чтобы сохранить продукт, вам нужно иметь два 64-битных числа и представить, что одно из них является первыми 64 битами, а другое - вторыми 64 битами продукта. Вам нужно будет написать код, который переносит добавление от 63 бита второго числа к биту 0 первого числа.

Поздравляю, вы только что заново изобрели «крестьянское умножение». ;) en.wikipedia.org/wiki/…

Nick Johnson 11.10.2008 13:55

Есть гораздо более быстрые алгоритмы умножения, чем «крестьянское умножение».

DanielOfTaebl 20.09.2011 13:18

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

Дано A B C D * E F G H (каждый фрагмент 32-битный, всего 128 бит)
Вам нужен выходной массив шириной 9 слов. Установите [0..8] на 0

Для начала вы выполните: H * D + out [8] => 64-битный результат.
Сохраните младшие 32 бита в out [8] и возьмите старшие 32 бита как переносимые
Далее: (H * C) + out [7] + carry
Опять же, сохраните младшие 32 бита в out [7], используйте старшие 32 бита в качестве переноса
. после выполнения H * A + out [4] + Carry вам нужно продолжать цикл до тех пор, пока у вас не закончится перенос.

Затем повторите с G, F, E.
. Для G вы должны начать с out [7] вместо out [8] и так далее.

Наконец, перейдите и преобразуйте большое целое число в цифры (для этого потребуется процедура «разделить большое число на одно слово»)

Если вы не можете использовать существующую библиотеку bignum, такую ​​как GMP, проверьте Статья в Википедии о двоичном умножении на компьютерах. Для этого существует ряд хороших эффективных алгоритмов.

Вот мой фрагмент кода на C. Старый добрый метод умножения

char *multiply(char s1[], char s2[]) {
    int l1 = strlen(s1);
    int l2 = strlen(s2);
    int i, j, k = 0, c = 0;
    char *r = (char *) malloc (l1+l2+1); // add one byte for the zero terminating string
    int temp;

    strrev(s1);
    strrev(s2);
    for (i = 0;i <l1+l2; i++) {
        r[i] = 0 + '0';
    }

    for (i = 0; i <l1; i ++) {
        c = 0; k = i;
        for (j = 0; j < l2; j++) {
            temp = get_int(s1[i]) * get_int(s2[j]);
            temp = temp + c + get_int(r[k]);
            c = temp /10;
            r[k] = temp%10 + '0';

            k++;
        }
        if (c!=0) {
            r[k] = c + '0';
            k++;
        }
    }

    r[k] = '\0';
    strrev(r);
    return r;
}

    //Here is a JavaScript version of an Karatsuba Algorithm running with less time than the usual multiplication method
    
    function range(start, stop, step) {
        if (typeof stop == 'undefined') {
            // one param defined
            stop = start;
            start = 0;
        }
        if (typeof step == 'undefined') {
            step = 1;
        }
        if ((step > 0 && start >= stop) || (step < 0 && start <= stop)) {
            return [];
        }
        var result = [];
        for (var i = start; step > 0 ? i < stop : i > stop; i += step) {
            result.push(i);
        }
        return result;
    };
    function zeroPad(numberString, zeros, left = true) {
        //Return the string with zeros added to the left or right.
        for (var i in range(zeros)) {
            if (left)
                numberString = '0' + numberString
            else
                numberString = numberString + '0'
        }
    
        return numberString
    }
    function largeMultiplication(x, y) {
        x = x.toString();
        y = y.toString();
    
        if (x.length == 1 && y.length == 1)
            return parseInt(x) * parseInt(y)
    
        if (x.length < y.length)
            x = zeroPad(x, y.length - x.length);
    
        else
            y = zeroPad(y, x.length - y.length);
    
        n = x.length
        j = Math.floor(n/2);
    
        //for odd digit integers
        if ( n % 2 != 0)
            j += 1    
        var BZeroPadding = n - j
        var AZeroPadding = BZeroPadding * 2
    
        a = parseInt(x.substring(0,j));
        b = parseInt(x.substring(j));
        c = parseInt(y.substring(0,j));
        d = parseInt(y.substring(j));
    
        //recursively calculate
        ac = largeMultiplication(a, c)
        bd = largeMultiplication(b, d)
        k = largeMultiplication(a + b, c + d)
        A = parseInt(zeroPad(ac.toString(), AZeroPadding, false))
        B = parseInt(zeroPad((k - ac - bd).toString(), BZeroPadding, false))
        return A + B + bd
    }
    //testing the function here
    example = largeMultiplication(12, 34)
    console.info(example)

в вашем коде много синтаксических ошибок, которые приводят к сбою компиляции. Я исправил некоторые из них, но код по-прежнему не работает

phuclv 18.10.2018 12:14

ты уверен, что это работает? почему вы удаляете тег js, чтобы люди могли проверить?

phuclv 20.10.2018 08:15

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

Pianistprogrammer 21.10.2018 07:41

Другие вопросы по теме