如何在MatLAB中获得Fortran精度
我有一段用Fortran和Matlab编写的代码。他们做了完全相同的计算,即如何在MatLAB中获得Fortran精度,matlab,fortran,double-precision,Matlab,Fortran,Double Precision,我有一段用Fortran和Matlab编写的代码。他们做了完全相同的计算,即 构造一个tanh-字段并找到它的拉普拉斯算子 将一些项相乘 此乘法的结果产生一个矩阵,其(4,4)次和(6,6)次I相减 在Fortran语言中,它们的差别是~1e-20 在Matlab中,它们的差值相同为零 这个问题非常关键,因为我测试这个数字是否小于零。 问题:是否有一种方法可以执行计算,使我在Matlab中获得与Fortran相同的精度 我列出以下代码: MatLAB clear all weights
tanh
-字段并找到它的拉普拉斯算子- 在Fortran语言中,它们的差别是~1e-20
- 在Matlab中,它们的差值相同为零李>
MatLAB
clear all
weights = [4./9, 1./9,1./9,1./9,1./9, 1./36,1./36,1./36,1./36];
dir_x = [ 0, 1, 0, -1, 0, 1, -1, -1, 1];
dir_y = [ 0, 0, 1, 0, -1, 1, 1, -1, -1];
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% CONSTANTS
length_y = 11; length_x = length_y;
y_center = 5; x_center = y_center;
densityHigh = 1.0;
densityLow = 0.1;
radius = 3.0;
c_width = 1.0;
average_density = 0.5*(densityHigh+densityLow);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
for x=1:length_x
for y=1:length_y
for i=1:9
fIn(i, x, y) = weights(i)*densityHigh;
test_radius = sqrt((x-x_center)*(x-x_center) + (y-y_center)*(y-y_center));
if(test_radius <= (radius+c_width))
fIn(i, x, y) = weights(i)*( average_density - 0.5*(densityHigh-densityLow)*tanh(2.0*(radius-sqrt((x-x_center)*(x-x_center) + (y-y_center)*(y-y_center))/c_width)) );
end
end
end
end
ref_density_2d = ones(length_x)*average_density;
for i=1:length_x
ref_density(:,:,i) = abs(ref_density_2d(:, i)');
end
rho = sum(fIn);
laplacian_rho = (+1.0*(circshift(rho(1,:,:), [0, -1, -1]) + circshift(rho(1,:,:), [0, +1, -1]) + circshift(rho(1,:,:), [0, -1, +1]) + circshift(rho(1,:,:), [0, +1, +1])) + ...
+4.0*(circshift(rho(1,:,:), [0, -1, +0]) + circshift(rho(1,:,:), [0, +1, +0]) + circshift(rho(1,:,:), [0, +0, -1]) + circshift(rho(1,:,:), [0, +0, +1])) + ...
-20.0*rho(1,:,:));
psi = 4.0*0.001828989483310*(rho-densityLow).*(rho-densityHigh).*(rho-ref_density) - laplacian_rho*(1.851851851851852e-04)/6.0;
psi(1,4,4)-psi(1,6,6)
全部清除
权重=[4./9,1./9,1./9,1./9,1./9,1./9,1./36,1./36,1./36,1./36];
dir_x=[0,1,0,-1,0,1,-1,1];
dir_y=[0,0,1,0,-1,1,1,-1,-1];
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%常数
长度y=11;长度x=长度y;
y_中心=5;x_中心=y_中心;
密度高=1.0;
密度低=0.1;
半径=3.0;
c_宽度=1.0;
平均密度=0.5*(密度高+密度低);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
对于x=1:长度x
对于y=1:长度
对于i=1:9
翅片(i,x,y)=重量(i)*密度高;
测试半径=sqrt((x-x_中心)*(x-x_中心)+(y-y_中心)*(y-y_中心));
如果(test_radius您仍然没有因此在代码中使用双精度,例如:
beta = 12.D0*0.0001/(1.D0*( (1.0 - 0.1)**4 ))
还有更多。如果我强制编译器使用双精度作为浮点的默认值(对于gfortran
,编译选项是-fdefault-real-8
),那么代码的结果是:
0.000000000000000000000000000000000000
因此,您需要修复代码。例如,引用的行应为:
beta = 12.D0*0.0001D0/(1.D0*( (1.0D0 - 0.1D0)**4 ))
[虽然我鄙视符号D0
,但这是另一回事]因此,您在代码中仍然没有使用双精度,例如:
beta = 12.D0*0.0001/(1.D0*( (1.0 - 0.1)**4 ))
还有更多。如果我强制编译器使用双精度作为浮点的默认值(对于gfortran
,编译选项是-fdefault-real-8
),那么代码的结果是:
0.000000000000000000000000000000000000
因此,您需要修复代码。例如,引用的行应为:
beta = 12.D0*0.0001D0/(1.D0*( (1.0D0 - 0.1D0)**4 ))
[虽然我鄙视符号D0
,但那是另一回事]尽管在回答这个问题的另一个版本()时有人建议你不要这样做,但你仍然在Fortran代码中使用单精度数字。默认情况下,0.1
是Fortran中的单精度实数(除非你使用了编译器选项来调整通常的行为,我打赌你没有,你是不是这个小流氓?).这也许可以解释你观察到的差异。在你探索的这个阶段,你至少应该已经研究过这种可能性。我改变了它,使它使用双精度,但结论是一样的——结果仍然不同。我花了很长时间研究,相信我……对不起,但没有人可能会经历那么多代码(使用两种语言),运行并调试它。缩小问题范围。找出结果分歧的第一个地方。除了上面@HighPerformanceMark所说的之外,还请参阅我对上一个问题的评论–您需要检查像abs
,sqrt
,tanh
等函数(甚至除法)在所有情况下返回相同的结果。并通过“检查”我的意思不是简单地打印到小数点后几位。@horchler我知道,我不能期望任何人这样做……但说真的,这太令人沮丧了,我无法让它工作。我还试着跟进tanh
-的事情,他们在小数点后19位左右有所不同。但我没有办法补救这一点……我收回了我对是一个问题,并投票决定关闭另一个问题。@AlexanderVogt的回答是正确的,下面的答案是正确的,但属于这个问题,而不是另一个缺少Fortran代码的问题。尽管在对这个问题的另一个版本的回答中有其他建议()您仍然在Fortran代码中使用单精度数字。默认情况下,0.1
是Fortran中的单精度实数(除非您使用了编译器选项来调整通常的行为,我打赌您没有,您是不是小流氓?).这也许可以解释你观察到的差异。在你探索的这个阶段,你至少应该已经研究过这种可能性。我改变了它,使它使用双精度,但结论是一样的——结果仍然不同。我花了很长时间研究,相信我……对不起,但没有人可能会经历那么多代码(使用两种语言),运行并调试它。缩小问题范围。找出结果分歧的第一个地方。除了上面@HighPerformanceMark所说的之外,还请参阅我对上一个问题的评论–您需要检查像abs
,sqrt
,tanh
等函数(甚至除法)在所有情况下返回相同的结果。并通过“检查”我的意思不是简单地打印到小数点后几位。@horchler我知道,我不能期望任何人这样做……但说真的,这太令人沮丧了,我无法让它工作。我还试着跟进tanh
-的事情,他们在小数点后19位左右有所不同。但我没有办法补救这一点……我收回了我对是一个问题,投票决定关闭另一个。@AlexanderVogt是正确的,下面的答案是正确的,但不属于这个问题,而属于另一个缺少Fortran代码的问题。有一些编译器警告应该会有所帮助。我不记得它们是如何包含在-Wall
中的(我不记得具体的标志)。我尝试了-Wconversion
,但没有收到任何警告:([我总是启用-Wall-Wextra-g-fbacktrace
]我的意思是-Wconversio