Преимущество округления inline-ASM путем помещения значения float в переменную int
Я унаследовал довольно интересный кусок кода:
inline int round(float a)
{
int i;
__asm {
fld a
fistp i
}
return i;
}
Моим первым побуждением было отказаться от него и заменить звонки на(int)std::round
(до C ++ 11, будет использоватьstd::lround
если бы это случилось сегодня), но через некоторое время я начал задаваться вопросом, может ли это все-таки иметь какое-то значение ...
Вариант использования этой функции - все значения в[-100, 100]
, так что дажеint8_t
будет достаточно широким, чтобы вместить результат.fistp
ля @ требуется как минимум 32-битная переменная памяти, поэтому меньшеint32_t
тратится впустую больше, чем больше.
Теперь совершенно очевидно, что приведение числа с плавающей точкой к int - не самый быстрый способ сделать что-либо, поскольку для этого режим округления должен быть переключен наtruncate
, согласно стандарту, и обратно потом. C ++ 11 предлагаетstd::lround
ункция @, которая устраняет эту конкретную проблему, но все же кажется более расточительной, учитывая, что значение передается float-> long-> int вместо того, чтобы напрямую прибыть туда, где и должно.
С другой стороны, с inline-ASM в функции компилятор не может оптимизироватьi
в регистр (и даже если бы мог,fistp
ожидает переменную памяти), поэтомуstd::lround
не выглядит намного хуже ...
Однако наиболее актуальный вопрос, который у меня возникает, заключается в том, насколько безопасно предположить (как это делает эта функция), что режим округления всегда будетround-to-nearest
, как это очевидно (без проверок). Какstd::lround
должен гарантировать определенное поведение, не зависящее от режима округления, это предположение, пока оно выполняется, всегда делает inline-ASM лучшим вариантом.
Кроме того, мне совершенно неясно, установлен ли режим округленияstd::fesetround
и используетсяstd::lround
альтернативаstd::lrint
и режим округления, используемый вfistp
ASM-инструкция гарантированно будет одинаковой или хотя бы синхронной.
Это мои соображения, то есть то, чего я не знаю, чтобы принять обоснованное решение о сохранении или замене функции.
Теперь на вопросы:
Следуя более осознанному взгляду на эти или подобные вопросы, о которых я не задумывался, представляется ли целесообразным использовать эту функцию?
Насколько велик риск, если есть?
Существуют ли рассуждения о том, почему это не будет быстрее, чемstd::lround
илиstd::lrint
?
Может ли это быть улучшено без снижения производительности?
Изменились ли какие-либо из этих рассуждений, если программа была скомпилирована для x86-64?