В C, C++ есть функция div (stdlib.h).
div_t div(int numer, int denom);
typedef struct _div_t
{
int quot;
int rem;
} div_t;
Но в C, C++ есть операторы / и %.
У меня вопрос: "Когда есть операторы / и %, полезна ли функция div?"
В C, C++ есть функция div (stdlib.h).
div_t div(int numer, int denom);
typedef struct _div_t
{
int quot;
int rem;
} div_t;
Но в C, C++ есть операторы / и %.
У меня вопрос: "Когда есть операторы / и %, полезна ли функция div?"
Функция div() возвращает структуру, содержащую частное и остаток от деления первого параметра (числителя) на второй (знаменатель). Есть четыре варианта:
div_t div(int, int)
ldiv_t ldiv(long, long)
lldiv_t lldiv(long long, long long)
imaxdiv_t imaxdiv(intmax_t, intmax_t
(intmax_t представляет самый большой целочисленный тип, доступный в системе)Структура div_t
выглядит так:
typedef struct
{
int quot; /* Quotient. */
int rem; /* Remainder. */
} div_t;
Реализация просто использует операторы /
и %
, так что это не совсем сложная или необходимая функция, но она является частью стандарта C (согласно определению [ISO 9899:201x][1]).
См. реализацию в GNU libc:
/* Return the `div_t' representation of NUMER over DENOM. */
div_t
div (numer, denom)
int numer, denom;
{
div_t result;
result.quot = numer / denom;
result.rem = numer % denom;
/* The ANSI standard says that |QUOT| <= |NUMER / DENOM|, where
NUMER / DENOM is to be computed in infinite precision. In
other words, we should always truncate the quotient towards
zero, never -infinity. Machine division and remainer may
work either way when one or both of NUMER or DENOM is
negative. If only one is negative and QUOT has been
truncated towards -infinity, REM will have the same sign as
DENOM and the opposite sign of NUMER; if both are negative
and QUOT has been truncated towards -infinity, REM will be
positive (will have the opposite sign of NUMER). These are
considered `wrong'. If both are NUM and DENOM are positive,
RESULT will always be positive. This all boils down to: if
NUMER >= 0, but REM < 0, we got the wrong answer. In that
case, to get the right answer, add 1 to QUOT and subtract
DENOM from REM. */
if (numer >= 0 && result.rem < 0)
{
++result.quot;
result.rem -= denom;
}
return result;
}
numer >= 0 && result.rem < 0
?
- person chux - Reinstate Monica; 06.03.2014
div
as для вычисления numer/denom и numer % denom в одной операции. Начиная с C99, блок if (numer >= 0 && result.rem < 0)
не нужен.
- person chux - Reinstate Monica; 31.10.2018
Да, это так: он вычисляет частное и остаток за одну операцию.
Кроме того, такого же поведения можно добиться с помощью /
+%
(и приличный оптимизатор все равно оптимизирует их в один div
).
Подводя итог: если вы заботитесь о том, чтобы выжать последние биты производительности, это может быть ваша функция выбора, особенно если оптимизатор на вашей платформе не настолько продвинут. Это часто имеет место для встроенных платформ. В противном случае используйте любой способ, который вы считаете более читаемым.
/
и %
двумя умножениями, битовым сдвигом и вычитанием (в большинстве случаев).
- person Ben Voigt; 16.07.2011
DIV
(в семействе Intel)?
- person Vlad; 16.07.2011
div()
из C, поэтому он остается.
- person Jonathan Grynspan; 16.07.2011
div
с константой 10
для преобразования двоичного числа в десятичное. Но да, когда частное является переменным, необходимо использовать инструкцию div
. Библиотечная функция div
в этом особо не помогает.
- person Ben Voigt; 13.09.2014
div
не гарантировано, что он будет скомпилирован в конкретную инструкцию процессора (в конце концов, на целевой платформе ее может не быть). Если умножение/вычитание возможно и быстрее, оптимизирующий компилятор должен предпочесть этот способ.
- person Vlad; 23.09.2014
Семантика div() отличается от семантики % и /, что важно в некоторых случаях. Вот почему следующий код находится в реализации, показанной в ответе psYchotic:
if (numer >= 0 && result.rem < 0)
{
++result.quot;
result.rem -= denom;
}
% может вернуть отрицательный ответ, тогда как div() всегда возвращает неотрицательный остаток.
Проверьте запись в Википедии, в частности, "div всегда округляется до 0, в отличие от обычного целочисленного деления в C, где округление для отрицательных чисел зависит от реализации».
numer < 0
. 2) Начиная с C11, встроенные /
и %
гарантированно усекаются до нуля, поэтому div
определено так же, как /
и %
.
- person Yakov Galka; 03.08.2016
printf("%d\n", div(-7,2).rem);
Я ожидаю, что код вернет -1
.
- person chux - Reinstate Monica; 31.10.2018
div()
удовлетворил потребность до C99: переносимость
Pre C99, направление округления частного a / b
с отрицательным операнд зависел от реализации. При использовании div()
направление округления не является необязательным, а указывается в сторону 0. div()
обеспечивает единообразное переносимое деление. Вторичное использование было потенциальной эффективностью, когда код должен был вычислить как частное, так и остаток.
С C99 и более поздними версиями, div()
и /
, определяющими одно и то же направление раунда, и с лучшими компиляторами, оптимизирующими соседний код a/b
и a%b
, необходимость уменьшилась.
Это было убедительной причиной для div()
и объясняет отсутствие udiv_t udiv(unsigned numer, unsigned denom)
в спецификации C: проблемы зависимых от реализации результатов a/b
с отрицательными операндами не существовали для unsigned
даже до C99.
Вероятно, потому, что на многих процессорах инструкция div выдает оба значения, и вы всегда можете рассчитывать на то, что компилятор распознает, что соседние операторы / и % на одних и тех же входных данных могут быть объединены в одну операцию.
Это стоит меньше времени, если вам нужны обе ценности. ЦП всегда вычисляет остаток и частное при выполнении деления. Если использовать «/» один раз и «%» один раз, процессор вычислит оба числа дважды.
(простите мой плохой английский, я не родной)
div()
, не прибегая к дополнительной проверке. Это проблема, зависящая от платформы. Чек может или может быть необходим.
- person chux - Reinstate Monica; 09.09.2014