Мне нужно разделить число 256 и округлить его до более близкого значения, например, если на входе 255 я хочу получить 1, а не 0. Теперь я использую
int x = 150;
int z = MulDiv(x, 1, 256);
Но я думаю, что это не оптимальный способ достижения моей цели, может кто-то посоветует лучший способ.
Использовать этот:
unsigned int x = 150;
unsigned int z = (x + 128) >> 8;
128 — среднее значение, так что после добавления округления, и 256=2^8
так что вы можете использовать операцию сдвига бит вместо деления.
НОТА: этот способ работает только для положительных ценностей.
Если вам нужно это для положительных и отрицательных значений, вам нужно это:
int x = -150;
int z = (x >= 0 ? (x + 128) : (x - 128)) / 256;
НОТА: сдвиг битов для подписанных значений имеет некоторые особенности и не всегда может быть доверенным, поэтому вы не можете использовать это: int z = (x < 0) ? (x - 128) / 256 : (x + 128) >> 8;
Это будет работать как для положительных, так и для отрицательных целых чисел (и нуля тоже):
int eps = x < 0 ? -128 : 128
int y = (x + eps) / 256;
Обязательный -pedantic
а также f[oo|ai]lsafe
версия:
if (x < INT_MIN + 128 || x > INT_MAX - 128) {
fputs("nasal demons!\n", stderr);
abort();
}
int eps = x < 0 ? -128 : 128;
int y = (x + eps) / 256;
Для правильного округления до ближайшего значения со знаком вы можете сделать это:
y = (x >= 0 ? (x + 128) : (x - 128)) / 256;
Для правильной обработки очень больших и малых значений вы можете использовать
int divideAndRound256(int x)
{
if(x > INT_MAX - 128)
return (x - 128) / 256 + 1;
else if(x < INT_MIN + 128)
return (x + 128) / 256 - 1;
else if(x < 0)
return (x - 128) / 256;
else
return (x + 128) / 256;
}
Или только для неподписанных значений
unsigned int divideAndRound256(unsigned int x)
{
if(x > UINT_MAX - 128)
return ((x - 128) >> 8) + 1;
else
return (x + 128) >> 8;
}