2017-02-02 10 views
3

У меня есть следующая строка в какой-то Fortran код:Оптимизация умножения на ноль

acc = acc + DRSite_t(u, k, s) * Exp(-(max(0.0_dp, t1 - real(s, dp))/TAT(ds, k))) 

где DRSite_t и TAT являются оба массива не функции.

Очевидно, что если значение DRSite_t равно нулю, комплексное вычисление справа от оператора умножения не нужно оценивать.

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

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

ответ

4

Вы имеете в виду, если сначала вычисляет DRSite_t(u, k, s), проверяет, равна ли она 0, а затем потенциально пропускает другую часть выражения?

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

Я даже думаю, что если вы сделаете это вручную, это будет медленнее, если только 0 не приходит очень часто. Но у компилятора нет причин предполагать, что 0 происходит очень часто.

+0

[Не стоит добавлять свой собственный ответ для этого.] Возможно, стоит также отметить, что 'DRSite_t (u, k, s)' being '0' не означает, что все выражение' DRSite_t (u, k, s) * (horrible_thing) 'is' 0': в некоторых случаях это может быть '-0'. По общему признанию, в этом случае это, вероятно, не будет. – francescalus

+0

Это правда. Я часто компилирую с '-ffast-math', поэтому мне не нужны такие тонкости. –

+0

'TAT()' всегда будет положительным, поэтому '(ужасная вещь)' также всегда будет положительной. –

3

Как обычно, когда происходит арифметика с плавающей запятой, все может стать интересным. В этом случае не обязательно, что 0*expr эквивалентно 0.

Рассмотрите возможности выражения в правой части, согласно арифметике IEEE. Мы могли бы получить:

  • a NaN результат для бесконечного (любого знака) или выражения NaN;
  • результат -0, для отрицательного конечного выражения, когда поддерживаются подписанные нули;
  • результат 0, для положительного конечного значения или любое конечное значение, когда подписанные нули не поддерживаются.

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

Также, если expr является ссылкой на функцию, функция может иметь побочные эффекты.

Теперь, в случае вопроса, программист может «знать», что TAT (если функция) не имеет побочных эффектов и является (строго) положительным значением и что экспоненциация там имеет положительный конечный результат. Компилятор должен быть абсолютно уверен в этом или знать, что программисту все равно.

Если TAT(ds,k) не может быть доказано (к удовлетворению компилятора) положительно, при арифметике IEEE было бы неправильно «оптимизировать».

То есть, компилятор должен проверить:

  • является DRSite_t(u, k, s) нулю; и
  • имеет экспоненциальное значение; и
  • Есть ли какая-либо функция, имеющая побочный эффект?

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

В заключение, если вы уверены, что 0*expr действительно эквивалентен 0, стоит рассмотреть пропущенную всю инструкцию присваивания; но это был бы смелый компилятор, чтобы сделать это за вас. Лучший шанс иметь это условное назначение - если TAT - дорогая, но хорошо выполненная функция.

+0

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

+0

Хороший момент, который я включил в ответ. Благодарю. – francescalus