19

When I was studying in the university I often heard the idea that Fortran compilers produced faster code than C compilers for an equivalent program.

The key reasoning went like this: a Fortran compiler emits on average 1,1 processor instruction per line of code, while a C compiler emits on average 1,6 processor instruction per line of code - I don't remember the exact numbers but the idea was that C compilers emitted noticeably more machine code and therefore produced slower programs.

How valid is such comparison? Can we say that Fortran compilers produce faster programs than C compilers or vice versa and why does this difference exist?

6
  • 21
    That may simply mean that Fortran programs are more verbose than C... A meaningful comparison could only be done by implementing the same functionality in both languages and comparing the resulting machine code (size and speed). Mar 21, 2011 at 8:35
  • Also, does the generated code support parallel execution?
    – user1249
    Mar 21, 2011 at 9:00
  • @Péter Török, it simply means that, say, BLAS and LAPACK in Fortran used to perform much better then any of their C/C++ ports. Now the gap is shrinking quickly.
    – SK-logic
    Mar 21, 2011 at 9:48
  • 6
    You can only argue that one compiler produces faster code if you have a 100% equivalent program in both languages, written by experts who know their compilers and who can account for performance.
    – Falcon
    Mar 21, 2011 at 12:16
  • The former Fortran did not support recursion and thus did not necessarily had to push the function call arguments onto the stack since there would be a statically allocated space for the arguments of each funcion. This is one of the reasons why it might have been faster. I guess you may find a more complete answer here: amazon.com/Programming-Language-Pragmatics-Third-Edition/dp/…
    – Pedro Rolo
    Dec 10, 2014 at 16:48

7 Answers 7

41

IIRC one of the main reasons why Fortran is said to be faster is the absence of pointer aliasing, so they can use optimizations that C compilers can't use:

In FORTRAN, function arguments may not alias each other, and the compiler assumes they do not. This enables excellent optimization, and is one major reason for FORTRAN's reputation as a fast language. (Note that aliasing may still occur within a FORTRAN function. For instance, if A is an array and i and j are indices which happen to have the same value, then A[i] and A[j] are two different names for the same memory location. Fortunately, since the base array must have the same name, index analysis can be done to determine cases where A[i] and A[j] cannot alias.)

But I agree with others here: Comparing the average number of assembler instructions generated for a line of code is complete nonsense. For instance a modern x86 core can execute two instructions in parallel if they don't access the same registers. So you can (in theory) gain a performance increase of 100% for the same set on instructions just by reordering them. Good compilers will also often generate more assembly instructions to get faster code (think loop unrolling, inlining). The total number of assembler instructions says very little about the performance of a piece of code.

8
  • Another reason for better optimisations is the native support for complex numbers.
    – SK-logic
    Mar 21, 2011 at 10:52
  • Certainly correct for Fortran IV or so. Not sure if modern FORTRANs still don't have pointers, dynamic meory etc.
    – Ingo
    Mar 21, 2011 at 15:33
  • 3
    That's the same reason we often dropped down to a bit of inline assembly when developing in C and C++ in the games industry. People can claim as often as they like that "compilers can optimize better than humans writing assembly", fact is, pointer aliasing means that they often cannot. The code we can write by hand would be technically illegal for the compiler to emit, knowing as it does nothing about pointer aliasing. Mar 21, 2011 at 19:45
  • 7
    C's restrict keyword allows the author of a function to specify that a pointer has no aliases. Is this sufficient to address the difference, or is there more to it?
    – bk.
    Oct 21, 2012 at 2:26
  • @bk.: C's "restrict" attacks "half the problem"; it makes it possible to say that a specific pointer won't alias anything else within its lifetime, but there's no way to tell a compiler that an object whose address was passed to a function will not be aliased by anything once that function returns.
    – supercat
    May 28, 2016 at 18:30
10

Completely invalid comparison.

First, as @Péter Török points out, you must first compare the number of lines in equivalent programs from Fortran and C for this to even be a valid comparison on the number of lines produced.

Second, less lines of code doesn't always equal faster programs. Not all machine instructions take the same number of cycles to execute, but you also have other issues such as memory access, caching, etc.

On top of that, long code runs can be faster since it results in a lower number of execute lines (ie, Line Count != Executed Line Count).

5

Dan is correct, longer programs don't mean slower programs. It depends greatly one what they are doing.

I'm no expert on Fortran, I know a bit. Comparing them, I would think well written C would do much better in performance with more complex data structures and functionality than Fortran. Someone (please) correct me if I'm wrong here, but I do think Fortran is somewhat on a 'lower level' than C. If so, I'm sure for some problems would come out faster on Fortran.

Another thing, at first glance I thought you were asking if the compilers are faster. I actually do think that Fortran will generally compile faster for similar amounts of code, but the resulting program and how it runs would be a different story. It is just simpler to parse through.

3
  • 2
    If you are using complex data structures FORTRAN is probably the wrong choice. FORTRAN is optimized to do simple number crunching very fast.
    – Zachary K
    Mar 21, 2011 at 13:05
  • 2
    Fortran is designed for “formula translation”. It it often used in science and engineering for numerical and technical computing. It is also often used for business applications on IBM mainframes, as an alternative to COBOL. It makes it easy for non-programmers to write safe, correct, and robust software that is also easy to audit. So if a physicist is going to write software to control a nuclear power plant, Fortran reduces the risk that he will lay waste to half the eastern seaboard. C, however, makes it much easier to cause a nuclear meltdown. May 14, 2021 at 23:43
  • On the other hand, Fortran is very bad at certain things, like bit fiddling, low-level memory adressing. Fortran 77 did not even support recursion and dynamic memory allocation. Built-in i/o commands are also lousy compared to what we can do with C. As a consequence, almost any Fortran program actually uses a combination of C and Fortran, lately also Python and Fortran (with C as glue). May 14, 2021 at 23:57
5

Old-style FORTRAN required that a programmer who wanted to make part of an array available to a function needed to pass a reference to the whole array, along with one or more integer values specifying the starting subscript and either the ending subscript or number of items. C makes it possible to simplify this to passing a pointer to the start of the portion of interest along with the number of elements. In direct terms, this would make things faster (passing two things rather than three). Indirectly, however, it may end up slowing things down by limiting the kinds of optimization a compiler can perform.

Consider the function:

void diff(float dest[], float src1[], float src2[], int n)
{
  for (int i=0; i<n; i++)
    dest[i] = src1[i] - src2[i];
}

if a compiler knew that each of the pointers would identify the start of an array, it could generate code that would act upon elements of the array in parallel, or in any order, since for any x!=y, operations on dest[x] will not affect src1[y] nor src2[y]. For example, on some systems a compiler may benefit from generating code equivalent to:

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
}

Note that every operation that loads or computes a value has at least one more operation between it and the next operation that uses that value. Some processors can overlap the processing of different operations when such conditions are met, thus improving performance. Note, however, that because a C compiler has no way of knowing that the code won't be passed pointers to partially-overlapping regions of a common array, a C compiler can't make the above transformation. FORTRAN compilers given equivalent code, however, could and did make such a transformation.

While a C programmer could attempt to achieve comparable performance by explicitly writing out code that unrolled the loop and overlapped the operations of adjacent passes, such code could easily degrade performance if it used so many automatic variables that a compiler had to "spill" them to memory. A FORTRAN compiler's optimizer would likely know more than a programmer about what forms of interleaving would yield optimal performance in a given scenario, and such decisions are often best left to such compilers. While C99 attempted to improve C's situation somewhat by adding a restrict qualifier, that could only be used here if dest[] was a separate array from both src1[] and src2[], or if the programmer added separate versions of the loop to handle the cases where all dest was disjoint from src1 and src2, where src1[] and dest were equal and src2 was disjoint, where src2[] and dest[] were equal and src1 was disjoint, and where all three arrays were equal. FORTRAN, by contrast, could handle all four cases without difficulty using the same source code and the same machine code.

4

I think part of it is that FORTRAN compilers are designed to do some types of math very fast. Which is kind of why people use FORTRAN, to do calculations as fast as possible

4

The statement may have been true in the old days (circa late 70s) when C was in its infancy, and Fortran was supported by all major manufacturers and were highly optimized. Early Fortrans were based on the IBM architecture so simple stuff like the arithmetic if would certainly have been one statement per assembly instruction. This is true of the older machines like Data General and Prime, which had 3 way jumps. This doesn't work on modern instruction sets which do not have a 3 way jump.

Lines of code does not equal statements of code. Earlier versions of Fortran only allowed one statement per line. Later versions of Fortran can take multiple statements per line. C can have multiple statements per line. On the faster production compilers like Intel's IVF (formerly CVF, MS Powerstation) and Intel's C, there really is no difference between the two. These compilers are highly optimized.

0

It used to be true, and started not being true anymore because of technicality. Most recent Fortran compilers are written in C. Some would even internally convert the Fortran code to some C equivalent before compiling, thus somewhat compromising the high performance aspect.

The point is that an optimally written number-crunching Fortran program will match and perhaps even outperform a C equivalent, if the problem is formulated properly.

I notice a few claims in previous answers that are just incorrect. "Supercat" above claims that C allows passing a part of an array to a function, because one passes a pointer to some portion of interest of a larger array, hinting that that cannot be done in Fortran. Here is a bit of code that proves otherwise:

  PROGRAM atest
  INTEGER array(100)
  INTEGER i,j

  DO i=1,100
    array(i)=i
  ENDDO

  j=5
  CALL DISPLAY(array(41),j)

  CALL DISPLAY(array(61),j)

  STOP
  END

  SUBROUTINE DISPLAY(iarr,j)
  INTEGER j
  INTEGER iarr(j)
  INTEGER i
  DO i=1,j
   WRITE(6,*) iarr(i)
  ENDDO
  RETURN
  END

Try to run this, and you will see the following result: 41 42 43 44 45 61 62 63 64 65

Magic, right?

Fortran requires manual optimisation to some degree; alignment of large arrays access, for instance, could result in code that runs orders of magnitude faster (or slower, if done wrong). Most other languages would not allow one to set up the memory map -- Fortran would do that with the COMMON block, which forces variables to constitute a contiguous memory block, in the order indicated -- and the resulting performance could depend on how well the compiler guesses how the data will be accessed. Or even go with dynamic allocation (which may have value if you do not know how big your problem is and need to adapt to it). But if you know how much data needs to be processed (say a large CFD matrix) your performance may be better with Fortran than with anything else short of optimized assembly. But, you need to know what you are doing.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.