C ++ функции для целочисленного деления с четко определенной стратегией округления - PullRequest
8 голосов
/ 15 ноября 2011

Я хочу что-то в C ++, которое позволит мне эффективно целочисленное деление с указанным поведением округления, что-то вроде этого:

div_down(-4,3)        ==> -2
div_up(4,3)           ==> 2
div_to_zero(-4,3)     ==> -1
div_to_nearest(5,3)   ==> 2

Я бы хотел, чтобы он обнаруживал поведение целевой машины во время компиляции и генерировал соответствующееоптимальные реализации.Было бы неплохо что-то похожее на модуль, абстрагируясь от неопределенного поведения для отрицательных операндов во время компиляции.

Существует ли это?

Если нет, каков хороший способ сделать это?Я могу подумать о нескольких возможных подходах:

  • Попробуйте реализовать их как отдельные выражения, которые статически оптимизируют
  • Использование константных выражений для определения поведения цели и выбора из нескольких реализаций, например, с использованием шаблонов(но как именно?)

Ответы [ 3 ]

5 голосов
/ 17 ноября 2011

Это то, что у меня есть, с предварительным условием d> 0. Кажется, что все они работают, но можно ли их упростить?

int div_down(int n, int d) {
  if (n < 0) {
    return -((d - n - 1) / d);
  } else {
    return n / d;
  }
}

int div_up(int n, int d) {
  if (n < 0) {
    return -(-n / d);
  } else {
    return (n + d - 1) / d;
  }
}

int div_to_zero(int n, int d) {
  return n / d;
}

int div_to_nearest(int n, int d) {
  if (n < 0) {
    return (n - d/2 + 1) / d;
  } else {
    return (n + d/2) / d;
  }
}
4 голосов
/ 19 ноября 2015

Старый пост, но здесь он идет.Примите и оцените, если хотите.

int div_to_zero(int n, int d) { return n / d; }
//as per C++11 standard note 80

int div_up(int n, int d) {
    return n / d + (((n < 0) ^ (d > 0)) && (n % d));
} //i.e. +1 iff (not exact int && positive result)

int div_down(int n, int d) {
    return n / d - (((n > 0) ^ (d > 0)) && (n % d));
} //i.e. +1 iff (not exact int && negative result)

int div_to_nearest(int n, int d) {
    return (2*n - d + 2*(true&&(n<0^d>0))*d) / (2*d); 
} //i.e. +-0.5 as per pre-rounding result sign, then div_to-zero 
//it however rounds numbers like +/- 3.5 towards 0 and not even.

Примечание: большинство современных компиляторов будут использовать одну операцию деления для n / d и n% d, используемых совместно.Таким образом, с точки зрения производительности, это лучшее сокращение памяти.

1 голос
/ 15 ноября 2011

Последний черновик C ++ 11, n3242 , который почти идентичен фактическому стандарту C ++ 11, говорит об этом в 5.6 пункт 4 (стр. 118):

Для целых операндов оператор / дает алгебраический фактор с любой дробной частью отбрасывается; (см. примечание 80)

Примечание 80 состояний (обратите внимание, что примечания являются ненормативными):

80) Это часто называют усечением до нуля.

Для полноты, пункт 4 переходит в состояние:

если частное a / b представимо в типе результата, (a / b) * b + a% b равно a.

, который, как можно показать, требует, чтобы знак a%b совпадал со знаком a (если не ноль).

Примечание. Действующий стандарт C ++ 11 юридически недоступен онлайн. Тем не менее, проекты являются. К счастью, различия между последним проектом (N3242) и фактическим стандартом невелики. См. этот ответ .

ПРИМЕЧАНИЕ : Я не уверен, какие компиляторы придерживаются стандарта C ++ 11.


То есть div_to_zero() - обычное / деление.

Боюсь, что для других функций вам придется проверить знаки a и b и отрегулировать их соответствующим образом. Иногда может потребоваться дополнительная проверка, равняется ли a%b нулю. Таким образом, мы рассматриваем 12 тестовых случаев для каждой функции (3 для знака или нули a, 2 раза для знака b, 2 раза, равняется ли a%b нулю или нет).

Это слишком много для меня, чтобы понять прямо сейчас, поэтому, может быть, кто-то еще прыгнет и даст правильный ответ.

Я знаю, что Я не ответил на ваш вопрос , но приведенная выше информация казалась ценной и была слишком большой, чтобы уместиться в комментарии.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...