浮点数在 Fortran 数组构造函数中造成问题
Floats causing trouble in Fortran array constructor
我遇到了一些与 Fortran 数组构造函数相关的错误。也许你能帮我理解错误?我有两个问题(见下文)。
我的最小工作示例是:
program debug
use ieee_arithmetic
implicit none
integer :: ii
real, parameter :: KZERO = 1
real, parameter :: LAMBDA = 1.3
integer, parameter :: pad = 5
integer, parameter :: nsh = 60 + 2*pad
integer, parameter :: top=nsh-pad, bot=pad+1
real(kind=8), parameter :: dt2 = 1.0D-5/2
real(kind=8), parameter :: VK_SS = 6.0D-10
real(kind=8), parameter :: VM_SS = 6.0D-05
real(kind=8), parameter,dimension(nsh) :: k = [(KZERO*LAMBDA**(ii-pad), ii=1, nsh)]
real(kind=8), parameter,dimension(nsh) :: NUK_K = [(-dt2*VK_SS*k(ii)**2, ii=1, nsh)]
real(kind=8), parameter,dimension(nsh) :: NUK_M = [(-dt2*VM_SS*k(ii)**2, ii=1, nsh)]
real(kind=8), parameter, dimension(nsh) :: A = [(.0,ii=1,pad), ( REAL(exp(NUK_K(ii))), ii=bot, top), (.0,ii=1,pad)]
real(kind=8), parameter, dimension(nsh) :: B = [(.0,ii=1,pad), ( REAL( NUK_M(ii) ), ii=bot, top), (.0,ii=1,pad)]
!real(kind=8), parameter, dimension(nsh) :: C = [(.0,ii=1,pad), ( REAL(exp(NUK_M(ii))), ii=bot, top), (.0,ii=1,pad)]
print *,A
print *,'-------------------------'
print *,B
print *,'-------------------------'
!print *,C
end program debug
第一个问题: 为什么我需要在定义了 A、B 和 C 的构造函数中使用 REAL() 进行类型转换?如果我不这样做,我会得到这个错误:
/opt/intel/composer_xe_2011_sp1.9.293/bin/intel64/ifort -o debug debug.f90
debug.f90(23): error #7113: Each ac-value expression in an array-constructor must have the same type and type parameters. [EXP]
real(kind=8), parameter, dimension(nsh) :: A = [(.0,ii=1,pad), ( exp(NUK_K(ii)), ii=bot, top), (.0,ii=1,pad)]
--------------------------------------------------------------------^
...但是 do-loop 元素已经是 REAL kind=8 因为 NUK_K 是?
第二个问题: 当我取消注释定义 C 的行(也是通过数组构造函数)时,出现以下错误:
/opt/intel/composer_xe_2011_sp1.9.293/bin/intel64/ifort -o debug debug.f90
debug.f90(25): warning #7919: The value was too small when converting to REAL(KIND=4); the result is zero.
real(kind=8), parameter, dimension(nsh) :: C = [(.0,ii=1,pad), ( REAL(exp(NUK_M(ii))), ii=bot, top), (.0,ii=1,pad)]
--------------------------------------------------------------------^
debug.f90(25): error #7768: This operation on this data type is currently inaccurate.
real(kind=8), parameter, dimension(nsh) :: C = [(.0,ii=1,pad), ( REAL(exp(NUK_M(ii))), ii=bot, top), (.0,ii=1,pad)]
--------------------------------------------------------------------^
..警告没问题,因为我猜这意味着编译器建议 exp(-[large number]) -> 0,对吗?
但是我该如何处理错误 "This operation on this data type is currently inaccurate." ?
我已经解决这个问题很长时间了,希望你能帮助我!
编辑
首先非常感谢您的热心解答!我很感激。然而,不准确的问题仍然存在。有任何想法吗?我最初的猜测是使用四边形而不是双精度,然后将结果转换为双精度(我的 CPU 本身不支持四边形)。这也不起作用。我的新最小工作示例是(注意我删除了零填充以使示例更简单):
program debug
use ieee_arithmetic
use ISO_Fortran_env
implicit none
integer, parameter :: rd = real64
integer, parameter :: rq = real128
integer, parameter :: df = rq ! Default float kind
real(df), parameter :: KZERO = 1
real(df), parameter :: LAMBDA = 1.3
integer, parameter :: pad = 5
integer, parameter :: nsh = 60 + 2*pad
integer, parameter :: top=nsh-pad, bot=pad+1
real(df), parameter :: dt2 = 1.0D-5/2
real(df), parameter :: VK_SS = 6.0D-10
real(df), parameter :: VM_SS = 6.0D-05
integer :: ii
real(df), parameter,dimension(nsh) :: k = [(KZERO*LAMBDA**(ii-pad), ii=1, nsh)]
real(df), parameter,dimension(nsh) :: NUK_K = [(-dt2*VK_SS*k(ii)**2, ii=1, nsh)]
real(df), parameter,dimension(nsh) :: NUK_M = [(-dt2*VM_SS*k(ii)**2, ii=1, nsh)]
real(df), parameter, dimension(nsh) :: A = [ ( exp(NUK_K(ii)) , ii=1, nsh) ]
real(df), parameter, dimension(nsh) :: B = [ ( NUK_M(ii) , ii=1, nsh) ]
real(df), parameter, dimension(nsh) :: C = [ ( exp(NUK_M(ii)) , ii=1, nsh) ]
print *,A
print *,'-------------------------'
print *,B
print *,'-------------------------'
print *,C
end program debug
但这仍然报错
/opt/intel/composer_xe_2011_sp1.9.293/bin/intel64/ifort -o debug debug.f90
debug.f90(30): error #7768: This operation on this data type is currently inaccurate.
real(df), parameter, dimension(nsh) :: C = [ ( exp(NUK_M(ii)) , ii=1, nsh) ]
--------------------------------------------------^
第一个问题:
您正在尝试将默认类型 real(4)
的数组 (.0,ii=1,pad)
与 ( REAL(exp(NUK_K(ii))), ii=bot, top)
数组 real(8)
连接起来。最简单的解决方案是将第一个数组也变成 real(8)
数组,例如将浮点数 .0
替换为 0.0d0
(双精度数的科学计数法)。
示例:
real(kind=8), parameter, dimension(nsh) :: A = [(0.0d0,ii=1,pad), ( exp(NUK_K(ii)), ii=bot, top), (0.0d0,ii=1,pad)]
real(kind=8), parameter, dimension(nsh) :: B = [(0.0d0,ii=1,pad), ( NUK_M(ii) , ii=bot, top), (0.0d0,ii=1,pad)]
real(kind=8), parameter, dimension(nsh) :: C = [(0.0d0,ii=1,pad), ( exp(NUK_M(ii)), ii=bot, top), (0.0d0,ii=1,pad)]
第二个问题:
默认情况下,real(num)
不会将数字 num
类型转换为 real(8)
,而是类型转换为默认类型 real(4)
。如果您想将其类型转换为 real(8)
,您必须使用符号 real(num,kind=8)
明确地这样做。
所以换句话说,您一直在做的是显式地将 ( exp(NUK_M(ii)), ii=bot, top)
从双精度类型转换为单精度浮点数,然后将其与单精度零数组连接起来,然后将结果再次为双精度数组。这就是编译器抱怨精度损失的原因。
可能感兴趣的人的跟进:
我决定做一个 hacky 解决方案来解决有关内部函数 exp() 精度的问题。
问题是我希望计算 exp(-[非常大的数字]),它变得太接近于零,以至于偶数四边形浮点数无法表示大(负)指数。问题是,我不能简单地将这些条目设置为零,因为这会扰乱我的完整问题的数字。
因此,我所做的是用 exp(-7.0D2) 替换 exp(-[number lager than 7.0D2]),这接近于使用双精度表示的极限。
我遇到了一些与 Fortran 数组构造函数相关的错误。也许你能帮我理解错误?我有两个问题(见下文)。
我的最小工作示例是:
program debug
use ieee_arithmetic
implicit none
integer :: ii
real, parameter :: KZERO = 1
real, parameter :: LAMBDA = 1.3
integer, parameter :: pad = 5
integer, parameter :: nsh = 60 + 2*pad
integer, parameter :: top=nsh-pad, bot=pad+1
real(kind=8), parameter :: dt2 = 1.0D-5/2
real(kind=8), parameter :: VK_SS = 6.0D-10
real(kind=8), parameter :: VM_SS = 6.0D-05
real(kind=8), parameter,dimension(nsh) :: k = [(KZERO*LAMBDA**(ii-pad), ii=1, nsh)]
real(kind=8), parameter,dimension(nsh) :: NUK_K = [(-dt2*VK_SS*k(ii)**2, ii=1, nsh)]
real(kind=8), parameter,dimension(nsh) :: NUK_M = [(-dt2*VM_SS*k(ii)**2, ii=1, nsh)]
real(kind=8), parameter, dimension(nsh) :: A = [(.0,ii=1,pad), ( REAL(exp(NUK_K(ii))), ii=bot, top), (.0,ii=1,pad)]
real(kind=8), parameter, dimension(nsh) :: B = [(.0,ii=1,pad), ( REAL( NUK_M(ii) ), ii=bot, top), (.0,ii=1,pad)]
!real(kind=8), parameter, dimension(nsh) :: C = [(.0,ii=1,pad), ( REAL(exp(NUK_M(ii))), ii=bot, top), (.0,ii=1,pad)]
print *,A
print *,'-------------------------'
print *,B
print *,'-------------------------'
!print *,C
end program debug
第一个问题: 为什么我需要在定义了 A、B 和 C 的构造函数中使用 REAL() 进行类型转换?如果我不这样做,我会得到这个错误:
/opt/intel/composer_xe_2011_sp1.9.293/bin/intel64/ifort -o debug debug.f90
debug.f90(23): error #7113: Each ac-value expression in an array-constructor must have the same type and type parameters. [EXP]
real(kind=8), parameter, dimension(nsh) :: A = [(.0,ii=1,pad), ( exp(NUK_K(ii)), ii=bot, top), (.0,ii=1,pad)]
--------------------------------------------------------------------^
...但是 do-loop 元素已经是 REAL kind=8 因为 NUK_K 是?
第二个问题: 当我取消注释定义 C 的行(也是通过数组构造函数)时,出现以下错误:
/opt/intel/composer_xe_2011_sp1.9.293/bin/intel64/ifort -o debug debug.f90
debug.f90(25): warning #7919: The value was too small when converting to REAL(KIND=4); the result is zero.
real(kind=8), parameter, dimension(nsh) :: C = [(.0,ii=1,pad), ( REAL(exp(NUK_M(ii))), ii=bot, top), (.0,ii=1,pad)]
--------------------------------------------------------------------^
debug.f90(25): error #7768: This operation on this data type is currently inaccurate.
real(kind=8), parameter, dimension(nsh) :: C = [(.0,ii=1,pad), ( REAL(exp(NUK_M(ii))), ii=bot, top), (.0,ii=1,pad)]
--------------------------------------------------------------------^
..警告没问题,因为我猜这意味着编译器建议 exp(-[large number]) -> 0,对吗? 但是我该如何处理错误 "This operation on this data type is currently inaccurate." ?
我已经解决这个问题很长时间了,希望你能帮助我!
编辑
首先非常感谢您的热心解答!我很感激。然而,不准确的问题仍然存在。有任何想法吗?我最初的猜测是使用四边形而不是双精度,然后将结果转换为双精度(我的 CPU 本身不支持四边形)。这也不起作用。我的新最小工作示例是(注意我删除了零填充以使示例更简单):
program debug
use ieee_arithmetic
use ISO_Fortran_env
implicit none
integer, parameter :: rd = real64
integer, parameter :: rq = real128
integer, parameter :: df = rq ! Default float kind
real(df), parameter :: KZERO = 1
real(df), parameter :: LAMBDA = 1.3
integer, parameter :: pad = 5
integer, parameter :: nsh = 60 + 2*pad
integer, parameter :: top=nsh-pad, bot=pad+1
real(df), parameter :: dt2 = 1.0D-5/2
real(df), parameter :: VK_SS = 6.0D-10
real(df), parameter :: VM_SS = 6.0D-05
integer :: ii
real(df), parameter,dimension(nsh) :: k = [(KZERO*LAMBDA**(ii-pad), ii=1, nsh)]
real(df), parameter,dimension(nsh) :: NUK_K = [(-dt2*VK_SS*k(ii)**2, ii=1, nsh)]
real(df), parameter,dimension(nsh) :: NUK_M = [(-dt2*VM_SS*k(ii)**2, ii=1, nsh)]
real(df), parameter, dimension(nsh) :: A = [ ( exp(NUK_K(ii)) , ii=1, nsh) ]
real(df), parameter, dimension(nsh) :: B = [ ( NUK_M(ii) , ii=1, nsh) ]
real(df), parameter, dimension(nsh) :: C = [ ( exp(NUK_M(ii)) , ii=1, nsh) ]
print *,A
print *,'-------------------------'
print *,B
print *,'-------------------------'
print *,C
end program debug
但这仍然报错
/opt/intel/composer_xe_2011_sp1.9.293/bin/intel64/ifort -o debug debug.f90
debug.f90(30): error #7768: This operation on this data type is currently inaccurate.
real(df), parameter, dimension(nsh) :: C = [ ( exp(NUK_M(ii)) , ii=1, nsh) ]
--------------------------------------------------^
第一个问题:
您正在尝试将默认类型 real(4)
的数组 (.0,ii=1,pad)
与 ( REAL(exp(NUK_K(ii))), ii=bot, top)
数组 real(8)
连接起来。最简单的解决方案是将第一个数组也变成 real(8)
数组,例如将浮点数 .0
替换为 0.0d0
(双精度数的科学计数法)。
示例:
real(kind=8), parameter, dimension(nsh) :: A = [(0.0d0,ii=1,pad), ( exp(NUK_K(ii)), ii=bot, top), (0.0d0,ii=1,pad)]
real(kind=8), parameter, dimension(nsh) :: B = [(0.0d0,ii=1,pad), ( NUK_M(ii) , ii=bot, top), (0.0d0,ii=1,pad)]
real(kind=8), parameter, dimension(nsh) :: C = [(0.0d0,ii=1,pad), ( exp(NUK_M(ii)), ii=bot, top), (0.0d0,ii=1,pad)]
第二个问题:
默认情况下,real(num)
不会将数字 num
类型转换为 real(8)
,而是类型转换为默认类型 real(4)
。如果您想将其类型转换为 real(8)
,您必须使用符号 real(num,kind=8)
明确地这样做。
所以换句话说,您一直在做的是显式地将 ( exp(NUK_M(ii)), ii=bot, top)
从双精度类型转换为单精度浮点数,然后将其与单精度零数组连接起来,然后将结果再次为双精度数组。这就是编译器抱怨精度损失的原因。
可能感兴趣的人的跟进:
我决定做一个 hacky 解决方案来解决有关内部函数 exp() 精度的问题。 问题是我希望计算 exp(-[非常大的数字]),它变得太接近于零,以至于偶数四边形浮点数无法表示大(负)指数。问题是,我不能简单地将这些条目设置为零,因为这会扰乱我的完整问题的数字。 因此,我所做的是用 exp(-7.0D2) 替换 exp(-[number lager than 7.0D2]),这接近于使用双精度表示的极限。