A Comparison of Programming Languages in Economics

There is something like 12 languages in the paper. Probably none of the 2 or 3 reviewers were familiar with Fortran…

Yes, trying to cover multiple languages with a real-world significant case that covers circumstances where specialists may not even be available is handled relatively well by the paper and it’s conclusions are reasonable for the intended audience, but I do wish examples like this were reviewed. Perhaps it is up to the Fortran Discourse community to emphasize that it welcomes reviewing such examples before they are committed to posterity. Not all forums would. But, as noted above this was not in a Fortran textbook and very specifically was not even concentrating on Fortran. The bright side is Fortran was one of the languages considered required to be included.
I am sure if a major review of the other examples were done they could also be improved. I don’t think the audience was looking at this as a resource for finding good Fortran material; I find this much more disturbing when I find similar issues in major Fortran projects and references though.

An unintended consequence of the non-optimal use is that a transpose of a transpose was being done (essentially, a no-op) and one of them was in a loop and all the compilers I tried managed to identify and eliminate that so that correcting it had no significant change in the results. Quite a few interpreted languages with less optimization would likely not have done that; so an unstated conclusion for the paper might be that Fortran is still fast even for someone not an expert in the language; which some of the other results indicate is not true for other languages. It would be an interesting follow up if this were done with domain experts optimizing each example. I suspect that the really slow ones would improve dramatically but would require in-depth knowledge of the language; but that Fortran was near-optimal written in a intuitive form. Just my hunch, would be interesting to see that put to the test. That would be a plus for Fortran for a good sized population of people using small off-the-cuff or single-user programs.

This reminds me of something. To calculate the covariance or correlation matrix of the columns of matrix A, you need to compute

matmul(transpose(A),A)

which results in a symmetric matrix. I wonder if there is a code that speeds up the calculation by recognizing this symmetry. I have tried to do so by writing loops that calculate only the upper diagonal elements of the result, but that function was slower than
the matrix operations that ignore the symmetry.

One answer to this has been posted here:

The Julia code generated by the Linnea tool is

using LinearAlgebra.BLAS
using LinearAlgebra

"""
    algorithm0(ml0::Array{Float64,2})

Compute
A = (X^T X).

Requires at least Julia v1.0.

# Arguments
- `ml0::Array{Float64,2}`: Matrix X of size 100 x 100 with property Non-singular.
"""                    
function algorithm0(ml0::Array{Float64,2})
    # cost: 1e+06 FLOPs
    # X: ml0, full
    ml1 = Array{Float64}(undef, 100, 100)
    # tmp1 = (X^T X)
    syrk!('L', 'T', 1.0, ml0, 0.0, ml1)

    # tmp1: ml1, symmetric_lower_triangular
    for i = 1:100-1;
        view(ml1, i, i+1:100)[:] = view(ml1, i+1:100, i);
    end;

    # tmp1: ml1, full
    # A = tmp1
    return (ml1)
end

It shouldn’t be too hard to adapt this to Fortran. The main differences are the call to ?syrk has a few more arguments.

subroutine tranposeAtimesA(k,n,A,C)
   integer, intent(in) :: k, n
   real(dp), intent(in) :: A(k,n)
   real(dp), intent(inout) :: C(n,n)

   real(dp), parameter :: alpha = 1.0d0, beta = 0.0d0
   integer :: i

  call dsyrk('L','T',n,k,alpha,A,k,beta,C,n)
 
  ! the lower triangular part of C should now contain matmul(transpose(A),A)
  ! we need to copy it into the upper triangular part
   do i = 1, n
      C(i,i+1:n) = C(i+1:n,i)
   end do
end subroutine

:warning: Disclaimer: I haven’t attempted to compile this or verify if it works correctly. I also don’t know if the view calls in Julia are somehow accessing the arrays in a more favorable order. The Fortran version attempts to copy the lower-triangular columns (excluding the diagonal) into the upper-triangular rows.

2 Likes

Even after fixing the accuracy issues introduced in the original code by the authors, I observed other issues in the measured times. Running the C++ and the Fortran codes on my machine, I found the Intel compiler coming on top at 2X the speed of C++. These are my results (allowing highest optimization options for all compilers):

! My Check = 0.1465491436962635
 ! Elapsed time is = 1.24415     C++
 ! Elapsed time is   1.26562500  gfortran 
 ! Elapsed time is   0.6093750   ifort        
 ! Elapsed time is   0.6677110   nvfortran
 ! Elapsed time is   0.861564    Julia 1.8.0
1 Like

I find problems more with 64-bit integer constants, where 1024 is typically used when 1024_dp can be required.
eg

integer*8 ::i ; i = 1024*1024*1024*4  can lead to a 32-bit calculation with some compilers, while
"i = 12345678901" will be flaged as a problem with most compilers.
1 Like

Julia community has this practice of reviewing new manuscripts of books. I am actually curious about how many textbooks using Fortran follow the modern Fortran standard.
The FORTRAN FOR SCIENTISTS & ENGINEERS book by Stephen Chapman only uses upper cases for Fortran codes.

The 4th edition of Chapman’s book uses upper case for keywords but not variable names or intrinsic functions. Here is one of the first programs in the book.

PROGRAM roots
! Purpose:
! This program solves for the roots of a quadratic equation of the form
! A * X**2 + B * X + C = 0. It calculates the answers regardless of the
! type of roots that the equation possesses (Fortran 95/2003 style).
!
IMPLICIT NONE
! Declare the variables used in this program
REAL :: a ! Coefficient of X**2 term of equation
REAL :: b ! Coefficient of X term of equation
REAL :: c ! Constant term of equation
REAL :: discriminant ! Discriminant of the equation
REAL :: imag_part ! Imaginary part of equation (for complex roots)
REAL :: real_part ! Real part of equation (for complex roots)
REAL :: x1 ! First solution of equation (for real roots)
REAL :: x2 ! Second solution of equation (for real roots)
! Prompt the user for the coefficients of the equation
WRITE (*,*) 'This program solves for the roots of a quadratic '
WRITE (*,*) 'equation of the form A * X**2 + B * X + C = 0. '
WRITE (*,*) 'Enter the coefficients A, B, and C:'
READ (*,*) a, b, c
! Echo back coefficients
WRITE (*,*) 'The coefficients A, B, and C are: ', a, b, c
! Calculate discriminant
discriminant = b**2 - 4. * a * c
! Solve for the roots, depending upon the value of the discriminant
IF ( discriminant > 0. ) THEN ! there are two real roots, so...
X1 = ( -b + sqrt(discriminant) ) / ( 2. * a )
X2 = ( -b - sqrt(discriminant) ) / ( 2. * a )
WRITE (*,*) 'This equation has two real roots:'
WRITE (*,*) 'X1 = ', x1
WRITE (*,*) 'X2 = ', x2
ELSE IF ( discriminant == 0. ) THEN ! there is one repeated root, so...
x1 = ( -b ) / ( 2. * a )
WRITE (*,*) 'This equation has two identical real roots:'
WRITE (*,*) 'X1 = X2 = ', x1
ELSE ! there are complex roots, so ...
real_part = ( -b ) / ( 2. * a )
imag_part = sqrt ( abs ( discriminant ) ) / ( 2. * a )
WRITE (*,*) 'This equation has complex roots:'
WRITE (*,*) 'X1 = ', real_part, ' +i ', imag_part
WRITE (*,*) 'X2 = ', real_part, ' -i ', imag_part
END IF
END PROGRAM roots

Recent Fortran textbooks usually do present codes that follow recent standards. It’s the books that use Fortran but are not primarily about Fortran that often do not, for example here (the book is not published yet – maybe the codes will be revised).

Do you suggest that being wrong? The F2018 Standard itself uses upper case in all code snippets shown in NOTEs (both for keywords and (most of) variables) and in all references to the keywords throughout the text. Personally I find the mixed mode (uppercase keywords, lowercase objects) quite useful, especially if the code is intended to be shown as an example (say, to students)

I am not suggesting that is wrong. It is just not easy to read.
A textbook can influence thousands of potential users, which requires the coding style to be as good as it can be. Based on my personal experience, those who code Fortran keywords in upper cases also tend to code the other parts in upper cases. I totally agree that mixed cases are useful.

I tend so use uppercase for global variables in a module or for parameter values only, and not always even for those, but the trial offer of fortPLUS/spag had a large amount of options for case, allowing for parameters of procedures to have a leading uppercase character, for fixed values and/or keywords to be uppercase, and so on. It was interesting to run code through it and look at the various results. Without a tool like that I find it rather tedious to follow a lot of rules not enforced by any compilers (that I know of) so I rarely use case as being significant.

Many people preferred uppercase even when the compiler had an extension to not require it in the past, because uppercase was far more legible on low-res terminals, so the comment about it being unpleasant to read evoked “how times have changed” .

Several people have told me they are used to uppercase meaning “shout” and so find it very disturbing to see all of a code in uppercase.

WIth a lot of utilities that do colored syntax highlighting I find case even less useful than I used to find it (for “highlighting” certain words);to the point I made a little filter program to change everything not in a comment to lowercase that I use quite frequently (only works on free-format Fortran, and does not do anything to cpp(1) lines, which can cause problems with macros if you use them a lot).

Are there other tools other than plusFORT/spag that apply case rules consistently to code?