[英]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我用的是gcc(Ubuntu 9.3.0-17ubuntu1~20.04)9.3.0
The c code is: c 代码为:
// 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: Fortran 代码:
! 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 c 程序打印:1362136192.000000
and the Fortran program prints: 1362137216.0000和 Fortran 程序打印: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:如果我不将每个元素乘以自身,就像我在代码注释中的 state 一样,我会为程序的两个版本得到相同的值:
c prigram: 639200.000000 c 程序:639200.000000
Fortran program: 639200.0000 Fortran 程序:639200.0000
Why when I use a multiplication the c and Fortran code produce different results?.为什么当我使用乘法时 c 和 Fortran 代码产生不同的结果?。 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如果将 Fortran 版本更改为
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.即在带有
a
和b
的术语周围添加括号,两种语言的结果相同。 The C version already uses this order of evaluation due to the use of the +=
assignment operator.由于使用了
+=
赋值运算符,C 版本已使用此评估顺序。
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.当我编写程序的 Ada 版本时,我发现我必须将小数精度降低到 6 位小数才能获得 Fortran 的答案。
The Ada version is: Ada 版本是:
with Ada.Text_IO;与 Ada.Text_IO; use Ada.Text_Io;
使用 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:行定义类型 Real 定义了浮点类型的精度:
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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.