Следующее правильно округляет частное до ближайшего целого числа как для положительного, так и для отрицательного операндов БЕЗ плавающей запятой или условных ветвей (см. Вывод сборки ниже). Предполагается, что N-бит 2 дополняет целые числа.
#define ASR(x) ((x) < 0 ? -1 : 0) // Compiles into a (N-1)-bit arithmetic shift right
#define ROUNDING(x,y) ( (y)/2 - (ASR((x)^(y)) & (y)))
int RoundedQuotient(int x, int y)
{
return (x + ROUNDING(x,y)) / y ;
}
Значение ROUNDING будет иметь тот же знак, что и дивиденд (x), и половину величины делителя (y). Таким образом, добавление ROUNDING к дивиденду увеличивает его величину до того, как целочисленное деление усекает результирующий коэффициент. Вот вывод компилятора gcc с оптимизацией -O3 для 32-битного процессора ARM Cortex-M4:
RoundedQuotient: // Input parameters: r0 = x, r1 = y
eor r2, r1, r0 // r2 = x^y
and r2, r1, r2, asr #31 // r2 = ASR(x^y) & y
add r3, r1, r1, lsr #31 // r3 = (y < 0) ? y + 1 : y
rsb r3, r2, r3, asr #1 // r3 = y/2 - (ASR(x^y) & y)
add r0, r0, r3 // r0 = x + (y/2 - (ASR(x^y) & y)
sdiv r0, r0, r1 // r0 = (x + ROUNDING(x,y)) / y
bx lr // Returns r0 = rounded quotient