구식 FORTRAN은 배열의 일부를 함수에 사용 가능하게하려는 프로그래머는 시작 첨자와 종료 첨자 또는 항목 수를 지정하는 하나 이상의 정수 값과 함께 전체 배열에 대한 참조를 전달해야했습니다. . C는 요소 수와 함께 관심있는 부분의 시작 부분에 포인터를 전달하여 이것을 단순화 할 수 있습니다. 직접적으로 말하면, 이것은 일을 더 빨리 할 것입니다 (3 개가 아닌 2 개를 통과). 그러나 간접적으로 컴파일러가 수행 할 수있는 최적화 종류를 제한하여 속도를 늦출 수 있습니다.
기능을 고려하십시오.
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는 restrict
한정자 를 추가하여 C의 상황을 어느 정도 개선하려고 시도했지만 ,이 dest[]
둘은와 src1[]
와 분리 된 배열 src2[]
이거나 프로그래머가 분리 된 버전의 루프를 추가하여 모두 dest
분리 된 경우를 처리하는 경우에만 사용할 수 있습니다.src1
와 src2
, 어디src1[]
와 dest
동일했다 및 src2
해체했다 src2[]
하고 dest[]
있었 읍니다과 src1
해체, 그리고 어디에서 세 가지 배열은 동일했다. 반대로 FORTRAN은 동일한 소스 코드와 동일한 머신 코드를 사용하는 데 어려움없이 4 가지 경우를 모두 처리 할 수 있습니다.