Я использую 128-битный целочисленный счетчик в самых внутренних циклах моего кода на С++. (Неприемлемый фон: фактическое приложение оценивает конечные разностные уравнения на регулярной сетке, которая включает в себя повторное увеличение больших целых чисел, и даже 64 бита недостаточно точны, потому что небольшое округление накапливается достаточно, чтобы повлиять на ответы.)
Я представлял целое число как два 64-битных unsigned longs. Теперь мне нужно увеличить эти значения с помощью 128-битной константы. Это не сложно, но вы должны вручную поймать перенос с низкого слова на высокое слово.
У меня есть рабочий код примерно так:
inline void increment128(unsigned long &hiWord, unsigned long &loWord)
{
const unsigned long hiAdd=0x0000062DE49B5241;
const unsigned long loAdd=0x85DC198BCDD714BA;
loWord += loAdd;
if (loWord < loAdd) ++hiWord; // test_and_add_carry
hiWord += hiAdd;
}
Это жесткий и простой код. Он работает.
К сожалению, это примерно 20% от моего времени выполнения. Линия убийцы - это тест loWord. Если я удалю его, я, очевидно, получу неправильные ответы, но накладные расходы во время выполнения сократятся с 20% до 4%! Так что перенос теста особенно дорог!
Мой вопрос: Предоставляет ли С++ флаги переноса оборудования, даже как расширение для GCC? Похоже, что дополнения могут быть сделаны без линии тестирования и добавления-переноса выше, если фактические скомпилированные инструкции использовали добавление с использованием последней инструкции переноса для добавления hiWord. Есть ли способ переписать строку test-and-add-carry, чтобы заставить компилятор использовать внутренний код операции?