Быстрее ли умножать низкие числа в C/C++ (в отличие от больших чисел)?

Пример вопроса:

Расчет 123*456 быстрее, чем расчет 123456*7890? Или скорость одинаковая?

Меня интересуют 32-битные целые числа без знака, но я не буду игнорировать ответы о других типах (64-битных, со знаком, с плавающей запятой и т. д.). Если отличается, то чем отличается? Являются ли биты 0/1?

Изменить: если это имеет значение, я должен уточнить, что я имею в виду любое число (два случайных числа ниже 100 против двух случайных чисел выше 1000)


person Adventurous    schedule 08.03.2018    source источник
comment
На самом деле это не то, на что можно ответить на общих основаниях, так как это сильно зависит от целевой платформы и, возможно, компилятора. Для вашего конкретного компилятора и цели вы всегда можете выполнить каждое умножение миллион раз и проверить время, необходимое для этого.   -  person Some programmer dude    schedule 08.03.2018
comment
Там нет С/С++. C и C++ - разные языки. Ни один из них не дает вам никаких гарантий скорости. Вам нужно задать вопрос о вашей платформе, а не о языке программирования.   -  person n. 1.8e9-where's-my-share m.    schedule 08.03.2018
comment
Нужно хотя бы указать процессор. Это вопрос об оборудовании и архитектуре. Ничего общего с С++.   -  person llllllllll    schedule 08.03.2018
comment
AFAIK, компилятор C, а также компилятор C++ (внутренне) не имеет умножения для меньших типов, чем int или unsigned. Следовательно, 123 * 456, а также 123456 * 7890 компилируются как int * int, если хотя бы одно из значений хранится в переменной. (Константы умножаются во время компиляции.) Исключением будет оптимизация для степени двойки, как уже упоминалось.   -  person Scheff's Cat    schedule 08.03.2018
comment
Есть некоторые процессоры Atom, где 8-битное деление более эффективно... таким образом, gcc -m8bit-idiv, но это скорее исключение, чем правило. Одно место, где вы найдете такие вещи, — это чрезвычайно сокращенные архитектуры набора команд, где умножение — это микрокодированная инструкция. хм. Заставляет меня задаться вопросом: является ли бит-аккумулятор nand текущим битовым стеком и бит-стеками обмена, если ложная машина Тьюринга завершена?   -  person technosaurus    schedule 08.03.2018


Ответы (3)


Для встроенных типов по крайней мере до размера слова архитектуры (например, 64-битный на современном ПК, 32- или 16-битный на большинстве недорогих ЦП общего назначения за последние пару десятилетий), для каждого компилятора/реализации/версии и ЦП I' Я когда-либо слышал, что код операции ЦП для умножения определенного целочисленного размера занимает определенное количество тактов независимо от задействованных величин. Умножение данных разного размера выполняется по-разному на некоторых процессорах (например, AMD K7 имеет задержку 3 такта для 16-битного IMUL против 4 для 32-битного).

Возможно, что в некоторой архитектуре и сочетании компилятора/флагов тип, подобный long long int, имеет больше битов, чем коды операций ЦП могут обрабатывать в одной инструкции, поэтому компилятор может выдать код для выполнения умножения поэтапно. и это будет медленнее, чем умножение типов, поддерживаемых процессором. Но опять же, небольшое значение, хранящееся во время выполнения в более широком типе, вряд ли будет обрабатываться или выполняться иначе, чем большее значение.

При этом, если одно или оба значения являются константами времени компиляции, компилятор может избежать оператора умножения ЦП и оптимизировать операторы сложения или сдвига битов для определенных значений (например, 1, очевидно, не используется, любая сторона 0 = => 0 результат, * 4 иногда можно реализовать как << 2). Нет ничего особенного в методах остановки, таких как сдвиг битов, используемых для больших чисел, но меньший процент таких чисел может быть оптимизирован в той же степени (например, есть больше степеней двойки, для которых умножение может быть выполнено с использованием сдвига битов влево - от 0 до 1000, чем от 1000 до 2000).

person Tony Delroy    schedule 08.03.2018

Это сильно зависит от архитектуры и модели процессора.

В прежние времена (приблизительно 1980-1990 гг.) количество единиц в двух числах было фактором — чем больше единиц, тем больше времени требовалось для умножения [после корректировки знака, поэтому умножение на -1 было не медленнее, чем умножение на 1, но умножение на 32767 (15 единиц) было заметно медленнее, чем умножение на 17 (2 единицы)]. Это потому, что умножение по существу:

unsigned int multiply(unsigned int a, unsigned int b)
{  
    res = 0;  
    for(number of bits)
    {
        if (b & 1)
        {
           res += a;
        }
        a <<= 1;
        b >>= 1;
    }
}

В современных процессорах умножение выполняется довольно быстро в любом случае, но 64-битное умножение может быть на один или два такта медленнее, чем 32-битное значение. Просто потому, что современные процессоры могут «позволить себе» уложить всю логику для этого за один цикл — как по скорости самих транзисторов, так и по площади, которую эти транзисторы занимают.

Кроме того, в старые времена часто были инструкции для получения результатов 16 x 16 -> 32 бит, но если вы хотели 32 x 32 -> 32 (или 64), компилятор должен был вызвать библиотечную функцию [или встроенную такую ​​​​ функция]. На сегодняшний день я не знаю ни одного современного высокопроизводительного процессора [x86, ARM, PowerPC], который не может выполнять по крайней мере 64 x 64 -> 64, некоторые делают 64 x 64 -> 128, и все это в одной инструкции (не всегда один цикл, хотя').

Обратите внимание, что я полностью игнорирую тот факт, что «наличие данных в кеше является важным фактором». Да, это фактор — и это немного похоже на игнорирование сопротивления ветра при движении со скоростью 200 км/ч — это совсем не то, что вы игнорируете в реальном мире. Впрочем, для ЭТОГО обсуждения это совершенно неважно. Точно так же, как люди, создающие спортивные автомобили, заботятся об аэродинамике, чтобы сложное [или простое] программное обеспечение работало быстро, требуется определенная забота о содержимом кеша.

person Mats Petersson    schedule 08.03.2018
comment
Кроме того, промахи кэша в наши дни обходятся намного дороже, чем операции ALU (на процессорах настольных компьютеров и ноутбуков). - person Basile Starynkevitch; 08.03.2018
comment
Все зависит от того, кого вы спросите. Я бы не назвал AVR или PIC современными (на самом деле они 1970-1980-х годов), но сегодня они продаются как современные, через ложный маркетинг. Посмотрите на всю эту шумиху вокруг Arduino. - person Lundin; 08.03.2018
comment
@Lundin Добавлена ​​формулировка high end, чтобы уточнить, что существуют процессоры меньшей мощности (что идеально подходит для некоторых случаев, поскольку они имеют низкую стоимость, малое энергопотребление и т. д.). - person Mats Petersson; 08.03.2018

Для всех намерений и целей одинаковая скорость (даже если бы были различия в скорости вычислений, они были бы неизмеримы). Если вам интересно, вот ссылка на сравнение различных операций ЦП: http://www.agner.org/optimize/instruction_tables.pdf.

person user1413793    schedule 08.03.2018
comment
Это бред, поскольку существуют 8- и 16-битные процессоры. Ссылка только сравнивает разные ПК. - person Lundin; 08.03.2018