我正在尝试计算一个值,该值采用功能形式x + 10(y + 10(z + 10(w + 10(u + 1000v))))))。假设x = y = z = w = 1,u = 3且v =2。那么这应该出现在20031111上。我希望这是一个浮点数,而不是整数。当我使用代码
output = x+10(y+10(z+10(w+10(u+1000v)))))
我得到预期的20031111。但是,当我使用
output = 1.0(x+10(y+10(z+10(w+10(u+1000v))))))
我得到20031112.000,这是错误的。这是怎么回事?
顺便说一句,如果我乘以1.D0而不是1.0,我将再次得到正确的答案。但是我不明白为什么。
答案 0 :(得分:2)
浮点数是实数的approximations。 Fortran中的默认实型不能精确表示具有8种重要算法的数字。然后,该值的最佳近似值将存储在变量中,在您的情况下为2.0031112E+07
。
您可以进行以下测试:
real :: output
integer :: x = 1, y = 1, z = 1, w = 1, u = 3, v = 2
! (...)
output = 1.0 *(x + 10 *(y + 10 * (z + 10 * (w + 10 * (u + 1000 * v)))))
print*, output + 2 ! prints: 2.0031114+07
print*, output + 1 ! prints: 2.0031112+07
print*, output ! prints: 2.0031112+07
print*, output - 1 ! prints: 2.0031112+07
print*, output - 2 ! prints: 2.0031110+07
作为解决方案,您必须使用带有类型参数的实类型,该类型参数可以以所需的精度表示数据。 Fortran提供了一个内在函数,可帮助您选择适合精度的最小类型selected_real_kind
。
示例:
integer, parameter :: wp = selected_real_kind(8) ! 8 precision digits
real(wp) :: output ! <- here you use wp as the kind parameter
integer :: x = 1, y = 1, z = 1, w = 1, u = 3, v = 2
! (...)
! you can also apply the kind parameter to litreals as below, like 1.0_wp
output = 1.0_wp *(x + 10 *(y + 10 * (z + 10 * (w + 10 * (u + 1000 * v)))))
print*, output + 2 ! prints: 20031113.0000000
print*, output + 1 ! prints: 20031112.0000000
print*, output ! prints: 20031111.0000000
print*, output - 1 ! prints: 20031110.0000000
print*, output - 2 ! prints: 20031109.0000000
顺便说一句,如果我乘以1.D0而不是1.0,我将再次得到正确的答案。但是我不明白为什么。
后缀D0
是使用与double precision
类型规范相对应的kind参数声明真实文字的便捷捷径,(在您的系统中)具有足够的精度来准确表示该值。 (请注意,要使其正常工作,您需要将output
声明为double precision
变量。)
但是,建议使用我之前建议的方法,该方法具有可移植性,可让您更好地控制数据类型。
答案 1 :(得分:1)
您正在达到浮点表示形式中可表示整数的极限。
通过将结果乘以1.0
,可以将结果转换为默认值REAL
,这样的数字只能精确地表示几个整数。
Fortran standard从未声明任何类型的REAL
应该代表IEEE-754 floating point number。 REAL
的表示形式取决于处理器。但是,最常见的表示形式是IEEE-754。为此,我们假设您的类型REAL
是IEEE-754 binary32,通常称为单精度浮点格式。
以这种格式,可以精确表示[-16777216,16777216]
范围内的整数。此数字类似于2**24
(23位小数部分和一个额外的默认值1)。
当与1.0D0
相乘时,您将整数转换为DOUBLE PRECISION
数,通常由IEEE-754 binary64表示,这种数字通常称为双精度浮点格式。在这里,您可以表示[-9007199254740992,9007199254740992]
范围内的所有整数。
如您所见,数字20031111
不在IEEE-754 binary32表示形式的范围内,因此是近似值,而它在IEEE-754 binary64表示形式的范围内。