Умножение двух 128-битных интов

Я пытаюсь умножить два 128-битных целых числа в C.

вот мой алгоритм:

разделить две 128-битные последовательности на S1 и S2.

затем разделить на С1 С11 (передняя/верхняя) и S12 (задняя/нижняя половина) и сплит S2 В типа S21 (передняя/верхняя) и S22 (задняя/нижняя половина).

умножьте S12 на S22... = S1222.

умножьте S11 на S21... = S1121, а затем бит сдвигает его, умножая его на 2^128

Объединить S1222 и S1121 будет передней и задней половинами нового массива. Назовем его "Array1". Длина нового массива в два раза больше длины S1.

тогда мы должны умножить S12 на S21 и S11 на S22. Я умножил эти два, чтобы получить s1221 и S1122 соответственно (и бит-сдвинул их соответственно). Теперь я должен добавить их в Array1. Это та часть, где я прошу о помощи. Я не уверен, как добавить их один за другим в Array1. Имейте в виду, что может быть перенос 1, Когда вы идете по кусочкам от 3/4 от Array1 до 1/4 от Array1, так как это промежуток, где необходимо добавить S1221 и S1122.

мой вопрос: Как добавить dstM1 и dstM2 в массив d, который уже заполнен?

3 ответов


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

uint16_t foo[4];  // 0000 aaaa FFFF cccc
uint16_t bar[4];  // dddd eeee FFFF 0000

хороший момент заключается в том, что "FFFF+FFFF+1" просто (1)FFFF. Таким образом, перенос всегда может быть добавлен в каждое слово, не производя дополнительного переноса (как если бы сумма могла быть 20000).

создание временной суммы:sum = foo[3] + bar[3] + carry; с переносом изначально 0, либо эта сумма производит новый перенос, либо нет.

  • Carry производится из (A+B), если (A+B) < A
  • при суммировании (A+B+c) перенос производится, если ((A + c) < A) || (((A + c) + B) < B)

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

            AAAA BBBB CCCC
       DDDD EEEE FFFF ....
  GGGG HHHH IIII .... ....
--------------------------
  col4 col3 col2 col1 col0

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

uint32_t sum_low = carry_in_from_previous_column;
uint32_t sum_high = 0;

for (i = 0; i < N; i++) {
     sum_low += matrix[i][column] & 0xffff;
     sum_high += matrix[i][column] >> 16;
}
sum_high += sum_low >> 16;    // add the multibit half carry

result = (sum_low & 0xffff) | (sum_high << 16);
carry_out = sum_high >> 16;

Если вы находитесь на gcc или clang, вы можете использовать __int128 и unsigned __int128 напрямую.


вы застряли в бесконечном цикле, потому что i += 1/32 Это то же самое, что i += 0.

также: Примечание:memcpy(&d[3l/2-i], dstM1, 1/8); и memcpy(&d[1-i], dstM1, 0);