基本算术赋予奇异的价值

时间:2018-07-08 23:32:39

标签: math fortran

我正在尝试计算一个值,该值采用功能形式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,我将再次得到正确的答案。但是我不明白为什么。

2 个答案:

答案 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 numberREAL的表示形式取决于处理器。但是,最常见的表示形式是IEEE-754。为此,我们假设您的类型REALIEEE-754 binary32,通常称为单精度浮点格式。

以这种格式,可以精确表示[-16777216,16777216]范围内的整数。此数字类似于2**24(23位小数部分和一个额外的默认值1)。

当与1.0D0相乘时,您将整数转换为DOUBLE PRECISION数,通常由IEEE-754 binary64表示,这种数字通常称为双精度浮点格式。在这里,您可以表示[-9007199254740992,9007199254740992]范围内的所有整数。

如您所见,数字20031111不在IEEE-754 binary32表示形式的范围内,因此是近似值,而它在IEEE-754 binary64表示形式的范围内。