FORTRAN старого стиля требовал, чтобы программисту, который хотел сделать часть массива доступной для функции, требовалось передать ссылку на весь массив вместе с одним или несколькими целочисленными значениями, указывающими начальный индекс и либо конечный индекс, либо количество элементов. , C позволяет упростить это, передав указатель на начало интересующей части вместе с количеством элементов. Прямо говоря, это ускорит процесс (пропуская две вещи, а не три). Однако косвенным образом это может привести к замедлению работы за счет ограничения видов оптимизации, которые может выполнять компилятор.
Рассмотрим функцию:
void diff(float dest[], float src1[], float src2[], int n)
{
for (int i=0; i<n; i++)
dest[i] = src1[i] - src2[i];
}
если бы компилятор знал, что каждый из указателей будет идентифицировать начало массива, он мог бы генерировать код, который будет воздействовать на элементы массива параллельно или в любом порядке, поскольку для любого x! = y выполняются операции с dest [x ] не повлияет на src1 [y] и src2 [y]. Например, в некоторых системах компилятор может получить выгоду от генерации кода, эквивалентного:
void dif(float dest[], float src1[], float src2[], int n)
{
int i=0;
float t1a,t1b,t2a,t2b,tsa,tsb;
if (n > 2)
{
n-=4;
t1a = src1[n+3]; t1b = src2[n+3]; t1b=src2[n+2]; t2b = src2[n+2];
do
{
tsa = t1a-t2a;
t1a = src1[n+1]; t2a = src2[n+1];
tsb = t2b-t2b;
dest[n+3] = tsa;
t1b = src1[n]; t2b = src2[n];
n-=2;
dest[n+4] = tsb;
} while(n >= 0);
... add some extra code to handle cleanup
}
else
... add some extra code to handle small values of n
}
Обратите внимание, что каждая операция, которая загружает или вычисляет значение, имеет по крайней мере еще одну операцию между ним и следующей операцией, которая использует это значение. Некоторые процессоры могут перекрывать обработку различных операций при соблюдении таких условий, что повышает производительность. Обратите внимание, однако, что поскольку компилятор C не может знать, что код не будет передаваться указатели на частично перекрывающиеся области общего массива, компилятор C не может выполнить вышеуказанное преобразование. Однако компиляторы FORTRAN, имеющие эквивалентный код, могли и действительно осуществили такое преобразование.
В то время как программист на C мог бы попытаться достичь сопоставимой производительности, явно написав код, который развернул цикл и перекрыл операции смежных проходов, такой код мог бы легко снизить производительность, если бы он использовал так много автоматических переменных, что компилятор должен был «пролить» их на Память. Оптимизатор компилятора FORTRAN, скорее всего, будет знать больше, чем программист, о том, какие формы чередования дадут оптимальную производительность в данном сценарии, и такие решения часто лучше оставить таким компиляторам. В то время как C99 пытался несколько улучшить ситуацию с C, добавив restrict
классификатор, он мог бы использоваться здесь только в том случае, если он dest[]
был отдельным массивом от обоих src1[]
и src2[]
, или если программист добавил отдельные версии цикла для обработки случаев, когда все dest
было не разделеноsrc1
и src2
, где src1[]
и dest
были равны и src2
не пересекались, где src2[]
и dest[]
были равны и src1
не пересекались, и где все три массива были равны. В отличие от этого, FORTRAN может без проблем обрабатывать все четыре случая, используя один и тот же исходный код и один и тот же машинный код.