简体   繁体   中英

Why the c and fortran versions of this same program produce different results?

I use gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0

The c code is:

// Compile with:
//  gcc -o little_c little.c
#include <stdio.h>  // printf

void main(void) {
    int n = 800;
    float a[n][n], b[n][n], c[n][n];
    int i, j, k;

    for (i = 0; i < n; i++) {
        for (j = 0; j < n; j++) {
            a[i][j] = (float) (i+j);
            b[i][j] = (float) (i-j);
        }
    }

    for (i = 0; i < n; i++) {
        for (j = 0; j < n; j++) {
            float t = (float) 0.0;
            for (k = 0; k < n; k++)
                t += a[i][k] * a[i][k] + b[k][j] * b[k][j];
                //t += a[i][k] + b[k][j]; // If I comment the above line and uncomment this, the c and fortran reults are the same
            c[i][j] = t;
        }
    }
    printf("%f", c[n-1][n-1]); // prints the very last element

}

Fortran code:

! Compile with:
!  gfortran -o little_fort little.f90 

program little

implicit none

integer, parameter  :: n = 800
real                :: a(n,n), b(n,n), c(n,n)
real                :: t
integer             :: i, j, k  ! Counters

do i = 1, n
    do j = 1, n
        a(i,j) = real(i-1+j-1)      ! Minus one, for it to be like the c version
        b(i,j) = real(i-1-(j-1))    ! because in c, the index goes from 0 to n-1
    end do
end do

do i = 1, n
    do j = 1, n
        t = 0.0
        do k = 1, n
            t = t + a(i,k) * a(i,k) + b(k,j) * b(k,j)
            !t = t + a(i,k) + b(k,j) ! If I comment the above line and uncomment this, the c and fortran reults are the same
        end do
        c(i,j) = t
    end do
end do
    
write (*,"(F20.4)") c(n,n)  ! This is the same as c[n-1][n-1] in c


end program little

The c program prints: 1362136192.000000

and the Fortran program prints: 1362137216.0000

If I do not multiply each element by itself, as I state in the comments in the code, I get the same value for both versions of the program:

c prigram: 639200.000000

Fortran program: 639200.0000

Why when I use a multiplication the c and Fortran code produce different results?. Does it have to be with different implementations of the real numbers?

The difference is due to the order of evaluation combined with the limited precision of the floating point type.

If you change the Fortran version to

t = t + (a(i,k) * a(i,k) + b(k,j) * b(k,j))

ie add parenthesis around the terms with a and b , you get the same result for both languages. The C version already uses this order of evaluation due to the use of the += assignment operator.

As mentioned in the comments, this is expected behavior at the limits of the available precision.

When I wrote an Ada version of the program I found that I had to reduce the decimal precision to 6 decimals to achieve the Fortran answer.

The Ada version is:

with Ada.Text_IO; use Ada.Text_Io;

procedure Main is
   type Real is digits 6;
   package Real_IO is new Ada.Text_IO.Float_IO(Real);
   use Real_IO;
   
   subtype Index is integer range 1..800;
   type Matrix is array(Index, Index) of Real;
   
   A : Matrix;
   B : Matrix;
   C : Matrix;
   T : Real := 0.0;
begin
   for I in Index loop
      for J in Index loop
         A(I,J) := Real(I - 1 + J - 1);
         B(I,J) := Real(I - 1 - (J - 1));
      end loop;
   end loop;
   
   for I in Index loop
      for J in Index loop
         T := 0.0;
         for K in Index loop
            T := T + A(I,K) * A(I,K) + B(K,J) *B(K,J);
         end loop;
         C(I,J) := T;
      end loop;
   end loop;
   
   Put(Item => C(Index'Last, Index'Last), Exp => 0, Aft => 4);
   New_Line;
end Main;

The line defining type Real defines the precision of the floating point type:

type Real is digits 6;

The value produced using six digits of precision is

1362137216.0000

Use of higher precision floating point types resulted in the value

1362135200.0000

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM