Вы были на правильном пути, разбив умножение на части, кроме случаев, когда у вас было h = (UINT_MAX + 1) / 2, это должно быть h = sqrt (UINT_MAX + 1). Если у вас есть 32-разрядные целые числа, например, h = 0x10000. Умножение на такую константу - это то же самое, что и смещение влево на количество битов, поэтому ваше уравнение становится:
a0 = a & 0xffff;
a1 = a >> 16;
b0 = b & 0xffff;
b1 = b >> 16;
a*b = a0*b0 + ((a1*b0)<<16 + (a0*b1)<<16) + (a1*b1)<<32
Поскольку каждый компонент имеет размер 16 бит или менее, каждое умножение гарантированно вписывается в 32-разрядный результат без знака.
Сведения о сложении значений с множественной точностью см. В Как добавить и вычесть 128-битные целые числа в C или C ++, если мой компилятор не поддерживает их?