Почему Math.DivRem неэффективен?

Здесь много правильных ответов, но я хотел добавить это (для полноты):

Если вы в нижней части файла cpp реализации выполняете явное инстанцирование всех типов, которые будут использоваться шаблоном с, компоновщик сможет найти их как обычно.

Изменить: добавление примера явного создания экземпляра шаблона. Используется после того, как шаблон определен, и определены все функции-члены.

template class vector<int>;

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

Вышеприведенный пример бесполезен, поскольку вектор полностью определен в заголовках, за исключением случаев, когда common include file (precompiled header?) использует extern template class vector<int>, чтобы не создавать его из всех других (1000?) файлов, которые используют вектор.

34
задан Peter Mortensen 23 October 2017 в 07:43
поделиться

9 ответов

Grrr. Единственная причина этой функции для существования состоит в том, чтобы использовать в своих интересах инструкцию ЦП для этого, и они даже не сделали этого!

17
ответ дан Joshua 23 October 2017 в 07:43
поделиться

Ничего себе, это действительно выглядит глупым, не так ли?

проблема состоит в том, что - согласно книге Microsoft Press ".NET Ассемблер IL" Lidin - rem IL и отделение atithmetic инструкции точно что: вычислите остаток и вычислите делитель.

Все арифметические операции кроме операции отрицания берут два операнда от стека и помещают результат на стек.

, По-видимому, способ, которым разработан ассемблерный язык IL, не возможно иметь инструкцию IL, которая производит два вывода и продвигает их на стопку оценки. Учитывая, что ограничение, у Вас не может быть инструкции подразделения в ассемблере IL, который вычисляет обоих путь, x86 DIV или инструкции IDIV делают.

IL был разработан для безопасности, verifiability, и устойчивости, НЕ для производительности. Любой, кто имеет вычисление - интенсивное приложение и заинтересован, прежде всего, с производительностью, будет использовать собственный код и не.NET.

я недавно посетил Супервычисления '08, и на одном из технических семинаров, евангелист для Microsoft Compute Server дал грубое эмпирическое правило, что.NET обычно была половиной скорости собственного кода - который точно имеет место здесь!.

13
ответ дан Die in Sente 23 October 2017 в 07:43
поделиться

Ответ, вероятно, что никто не думал это приоритет - это достаточно хорошо. То, что это не было зафиксировано ни с какой новой версией Платформы.NET, является индикатором того, как редко это используется - скорее всего, никто никогда не жаловался.

2
ответ дан Sander 23 October 2017 в 07:43
поделиться

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

2
ответ дан rmeador 23 October 2017 в 07:43
поделиться

Кто-либо еще получает противоположное при тестировании этого?

Math.DivRem = 11.029 sec, 11.780 sec
MyDivRem = 27.330 sec, 27.562 sec
DivRem = 29.689 sec, 30.338 sec

FWIW, я выполняю Intel Core 2 Duo.

числа выше были с отладочная сборка...

Со сборкой конечных версий:

Math.DivRem = 10.314
DivRem = 10.324
MyDivRem = 5.380

Похож на команду IL "rem", менее эффективно, чем "mul, sub" комбинация в MyDivRem.

1
ответ дан Austin Salonen 23 October 2017 в 07:43
поделиться

Эффективность может зависеть от включенных чисел. Вы тестируете КРОШЕЧНУЮ часть доступного пространства задач и всех загруженных с передней стороны. Вы проверяете первый 1 миллион * 10 = 1 миллиард непрерывных входных комбинаций, но фактическое пространство задач является приблизительно 4,2 миллиардами, в квадрате, или 1.8e19 комбинации.

выполнение общих математических операций библиотеки как это должно быть амортизировано по целому пространству задач. Мне было бы интересно видеть результаты более нормализованного входного распределения.

1
ответ дан Chris Ammerman 23 October 2017 в 07:43
поделиться

Вот мои числа:

15170 MyDivRem
29579 DivRem (same code as below)
29579 Math.DivRem
30031 inlined

тест был немного изменен; я добавил присвоение на возвращаемое значение и выполнял сборку конечных версий.

Core 2 Duo 2.4

Мнение:

Вы, казалось, нашли хорошую оптимизацию ;)

0
ответ дан 2 revs, 2 users 87% 23 October 2017 в 07:43
поделиться

Это находится частично в природе зверя. Нет насколько я знаю никакого общего быстрого способа вычислить остаток от подразделения. Это собирается взять соответственно большое количество тактов, даже с x сто миллионов транзисторов.

-1
ответ дан Peter Mortensen 23 October 2017 в 07:43
поделиться

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

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

0
ответ дан 27 November 2019 в 17:08
поделиться
Другие вопросы по тегам:

Похожие вопросы: