Многословное добавление в C
У меня есть программа на C, которая использует GCC __uint128_t
, и это здорово, но теперь мои потребности превысили ее.
Какие у меня варианты для быстрой арифметики с 196 или 256 битами?
Единственное, что мне нужно, это сложение (и мне не нужен бит переноса, то есть я буду работать с модом 2 192 или 2 256).
Скорость важна, поэтому я не хочу переходить на общую точность, если это вообще возможно. (На самом деле мой код в некоторых местах использует многоточность, но это находится в критическом цикле и будет выполняться десятки миллиардов раз. Пока что многоточность должна выполняться только десятки тысяч раз.)
Возможно, это достаточно просто для непосредственного кодирования, или мне нужно найти подходящую библиотеку.
Какой твой совет, о великий Кару?
Пояснение: GMP слишком медленный для моих нужд. Хотя я на самом деле использую в своем коде многоточность, она не во внутреннем цикле и выполняется менее 10 раз 5. Горячая петля работает более 10 раз 12. Когда я изменил свой код (увеличив параметр размера) так, чтобы часть с множественной точностью выполнялась чаще, чем с одинарной точностью, у меня было 100-кратное замедление (я думаю, что в основном из-за проблем с управлением памятью, а не из-за лишних мопов)). Я хотел бы снизить это до 4-х кратного замедления или лучше.
Ответы
Ответ 1
256-битная версия
__uint128_t a[2], b[2], c[2]; // c = a + b
c[0] = a[0] + b[0];
c[1] = a[1] + b[1] + (c[0] < a[0]);
Если вы используете его много раз в цикле, вы должны подумать о том, чтобы сделать его параллельным с помощью SIMD и многопоточности
Изменить: 192-битная версия. Таким образом, вы можете исключить 128-битное сравнение, как указано в @harold:
struct __uint192_t {
__uint128_t H;
__uint64_t L;
} a, b, c; // c = a + b
c.L = a.L + b.L;
c.H = a.H + b.H + (c.L < a.L);
Ответ 2
Вы можете проверить, достаточно ли достаточно "добавить (low < oldlow)
, чтобы имитировать перенос" -technique из этого ответа. Это немного осложняется тем, что low
здесь __uint128_t
, что может повредить генерацию кода. Вы можете попробовать это с 4 uint64_t
, я не знаю, будет ли это лучше или хуже.
Если это не так хорошо, перейдите к встроенной сборке и напрямую используйте флаг переноса - он не будет лучше, чем тот, но у вас будут обычные недостатки использования встроенной сборки.