Здравствуйте, Marty, Вы писали:
M>Меня собственно, интересует такая версия:
M>static inline void mul128(uint64_t a, uint64_t b, uint64_t& hi, uint64_t &lo) {
M> uint128_t t = a;
M> lo = t *= b;
M> hi = t >> 64;
M>}
Хорошо, так что тут конкретно интересует?
Под архитектуру x86-64 это пример компилируется gcc, clang, icc. После компиляции — та же единственная инструкция умножения, только имена регистров другие.
Или ты намекаешь, что раз в текущем стандарте языка не упомянут тип uint256_t, то такой подход не масштабируется на гипотетические 128-битные процессоры? Ну так так всегда будет — сначала вводится платформо-зависимое расширение (в данном случае типы вроде __uint256_t или __uint128_t), а потом уже это попадает в стандарт (да и то, только если достаточно широко начинает использоваться).
Всё-таки языки C/C++ тем и отличаются, что в стандарте не описывается единственно верное поведение, в вместо этого существует, например, implementation defined behaviour. Это, конечно, не добавляет переносимости программам, но уж такой язык. В С++ ведь не только длины целых чисел меняются, так даже two's complement представление знаковых не гарантируется. Да даже размер байта не всегда 8 бит (и так действительно бывает). С этой точки зрения у тебя в программу уже содержится явно непереносимые операции вроде
mask <<= 8;. Хочешь определённости и переносимости — пиши на какой-нибудь Java, а не на C++. А на С/C++ тебе самому придётся задумываться о том, является ли, например,
long int 32-битным или 64-битным числом, и что твоя программа будет делать если таки не является.