Подтвердить что ты не робот

Зачем использовать div или ldiv в C/С++?

Есть ли конкретная причина использовать ldiv или div вместо '/' или '%' для разделения/модуля на две переменные?

4b9b3361

Ответ 1

Да. C99 §7.20.6.2/2 гласит:

div, ldiv и lldiv, вычисляют функции numer / denom и numer % denom за одну операцию.

Ответ 2

Идея состоит в том, что результаты из/и% можно определить из одной инструкции DIV на процессоре. Таким образом, исторически, div() используется для обеспечения оптимизированного способа получения обоих.

Тем не менее, я обнаружил, что новые компиляторы в любом случае могут оптимизировать операцию/и% в один разделитель. Например, я видел эту оптимизацию на Microsoft Visual С++. В этих случаях div() действительно не дает преимущества и, по сути, может даже быть медленным, если задействован вызов.

Ответ 3

Это должно быть быстрее, чем использование операторов / и %, если вы хотите одновременно вычислить как фактор, так и остаток.

Ответ 4

Короткий ответ: не в современной среде.

Люди объяснили, почему преимущество div является слабым или даже несуществующим. На самом деле это еще хуже: div и друзья вводят тип связи, которая вредит хорошей практике (см. раздел ниже).

Преимущество: возможно, нет

Как сказано в других ответах, вызов div вместо / и %, скорее всего, гарантирует, что операция выполняется только один раз на уровне сборки.

Но в большинстве современных контекстов:

  • ЦП имеет так хорошо оптимизированные математические операции, что, за исключением самого внутреннего цикла вычислений, выполненного за миллион раз, любая производительность, вызванная повторением операции, вероятно, меньше, чем другие удары производительности (например, другой код, пропущен кеш и т.д..). = > Преимущество div, если таковое имеется, вообще незначительно.
  • Даже при использовании / и % современных компиляторов в любом случае все в порядке, генерируя только одну команду разделения, получая от нее коэффициент и остаток. = > Нет фактического преимущества для div.

Недостаток: div и друзья связывают ваш код с определенным типом

Если точный тип чисел (например, int или long) статически известен (т.е. ваш код явно использует int или long всегда), используя div для int и ldiv для долго все в порядке.

Но если вы будете следовать хорошей практике программирования небольшими частями, избегая ненужных предположений, вы быстро поймете, что использование div и ldiv связывает код с типами int или long соответственно. Наоборот, / и % будут автоматически настраиваться на любой тип, который фактически используется в данном случае, сохраняя очиститель кода.

Это особенно заметно в двух случаях:

  • вы используете typedef для абстрагирования фактических типов - div неуклюже даже в C!
  • вы используете шаблоны для абстрагирования фактических типов - div шаблоны поражений.

Пример

В приведенном ниже примере показано, что код с использованием '/' и '%' является чистым, простым и не привязан к int, long, long long или что-то еще, тогда как код с использованием div и друзей становится неуклюжим.

Testing with int
my_math_func_div_WRONG  says 6
my_math_func_OVERKILL   says 6  // Works but overkill cast to long
my_math_func_GOOD   says 6      // No div no headache.

Testing with int in long type
my_math_func_div_WRONG  says 6
my_math_func_OVERKILL   says 6  // Works but overkill cast to long
my_math_func_GOOD   says 6      // No div no headache.

Testing with actual long
my_math_func_div_WRONG  says 70503280   // FAIL
my_math_func_OVERKILL   says 500000006
my_math_func_GOOD   says 500000006      // No div no headache.

Исходный код:

#include <iostream>

// '/' and '%' are smart about type.
// This code is simple and will work with int, long, longlong, char, whatever.
template<typename T>
T my_math_func_GOOD( T number )
{
    T quotient = number / 10;
    T remainder = number % 10;
    // do something
    return quotient + remainder;
}

// div and friends are not smart about type.
// How do you write code smart about type with them ?

// Plus adds dependency on C stdlib.
#include <stdlib.h>
template<typename T>
T my_math_func_div_WRONG( T number )
{
    // This will always downcast to int. Defeats purpose of template.
    div_t result = div( number, 10 );
    T quotient = result.quot;
    T remainder = result.rem;
    // do something
    return quotient + remainder;
}

template<typename T>
T my_math_func_OVERKILL( T number )
{
    // This will always cast to long (up from int, OVERKILL, possibly down from long long, FAIL). Defeats purpose of template.
    ldiv_t result = ldiv( number, 10 );
    T quotient = result.quot;
    T remainder = result.rem;
    // do something
    return quotient + remainder;
}

template<typename T>
void my_math_func_test( T number )
{
    T n;
    n = my_math_func_div_WRONG( number );
    std::cout << "my_math_func_div_WRONG\tsays " << n << std::endl; // writes 6
    n = my_math_func_OVERKILL( number );
    std::cout << "my_math_func_OVERKILL\tsays " << n << std::endl; // writes 6
    n = my_math_func_GOOD( number );
    std::cout << "my_math_func_GOOD\tsays " << n << std::endl; // writes 6
}

// C99 allows absence of int argc, char **argv
int main()
{
    std::cout << std::endl << "Testing with int" << std::endl;
    my_math_func_test<int>( 42 );
    std::cout << std::endl << "Testing with int in long type" << std::endl;
    my_math_func_test<long>( 42 );
    std::cout << std::endl << "Testing with actual long" << std::endl;
    my_math_func_test<long>( 5000000042 );
    // std::cout << std::endl << "Testing with long long" << std::endl;
    // my_math_func_test<long long>( 50000000000000000042 );
}

Ответ 5

Хорошо, это старше, но я просто споткнулся. Наиболее важная разница здесь: определяется результат div(). В стандарте C не говорится, как обойти фактор. Это связано с тем, что компилятор должен иметь возможность использовать реализацию машины, которая зависит от процессора. Существуют две различные реализации: - округление по направлению к бесконечности - округление до 0 ,

div(), однако, указан для последнего и поэтому переносится.