【问题标题】:TINY(x) intrinsic functionTINY(x) 内在函数
【发布时间】:2021-04-15 20:29:31
【问题描述】:

我是一名大学讲师,本学期我将使用 Fortran 90/95 作为编程语言来教授数值方法课程。课程的开始是从数字的表示开始,我想谈谈可以用 REAL(4)、REAL(8) 和 REAL(16) 表示的数字的限制。我打算在 OnlineGDB 上使用以下代码(这样学生就不必在他们的计算机上安装任何东西,这在远程学习时可能会很痛苦):

Program declare_reals

implicit none 

real(kind = 4)  :: a_huge, a_tiny ! single precision ; default if kind not specified

!real(4) :: a ! Equivalent to real(kind = 4) :: a

a_huge = huge(a_huge)
print*, "Max positive for real(4) : ", a_huge
a_tiny = tiny(a_tiny)
print*, "Min positive for real(4) : ", a_tiny 
print*, 

End Program declare_reals

有了这段代码,我得到了

 Max positive for real(4) :    3.40282347E+38                                                                                                                          
 Min positive for real(4) :    1.17549435E-38

但是,如果我写a_tiny = tiny(a_tiny)/2.0,输出就变成了

Min positive for real(4) :    5.87747175E-39

查看 gfortran 的文档(OnlineGDB 将其用作 f95 编译器),我的印象是tiny(x) 以下的任何内容都可能导致下溢,并且将显示零而不是非零数字。谁能帮我理解这里发生了什么?如果tiny(x) 没有产生可表示的最小正数,函数调用会显示什么?

【问题讨论】:

  • 说实话,不。你能解释一下吗?
  • 注意,特别是如果你在教这个,使用 4 和 8 以及其他字面常量作为种类值不是最佳实践,不能保证编译器会支持这些值。因此,不能保证上面的代码会编译。看看使用 iso_fortran_env 中的参数 real32 和 real64,它们会起作用。
  • 代码现在编译的事实根本没有任何意义。这种做法是完全错误的,代码将无法编译,例如,使用默认设置的 Simply Fortran 或 NAG。确实,如果您正在教 Fortran,请不要使用 4 8 或 16 之类的幻数进行教学,请参阅 stackoverflow.com/questions/838310/fortran-90-kind-parameter 虽然独立程序员可以做他喜欢做的事,但如果没有其他人在该代码上工作,那么教师的标准和期望高得多。
  • @kvantour 当然。但是学生需要从一些东西开始,最好是一些他们甚至可以在自己的机器上进行实验的广泛应用。因为在 PDP-4 上可能有所不同,所以从不告诉任何事情,这不是一种好的教学方式。该标准故意避免讲述现实生活中发生的事情。并不意味着现实生活不存在。

标签: fortran fortran90


【解决方案1】:

Fortran 标准对实数值作了如下规定:

真实x的模型集由

定义

其中bp是大于一的整数;每个 fk 是 小于b的非负整数,f1 非零; s 是 +1 或 -1; e 是一个整数,介于某个整数最大值 emax 和某个整数最小值 emin 之间 包括在内。对于x = 0,它的指数e和数字fk 被定义为零。整数参数bpeminemax 确定模型浮点数的集合。

满足此定义的实数值被称为型号普通浮点数。您的系统可以表示的浮点数,即机器可表示的数字是型号的超集。它们可以但不一定必须包含 f1 的值 — 也称为 subnormal floating point numbers — 并且可以填补零附近的下溢缺口。

Fortran 函数tiny(x), huge(x), epsilon(x), spacing(x) 都是针对型号定义的。

tiny(x) 的值由 bemin − 1 给出,对于单精度浮点数 ( binary32) 由 2−126 给出,是最小的模型(正常)编号。当您的系统遵循 IEEE754 时,机器可表示数也将包含次正规数。最小的次正规正数由tiny(x)*epsilon(x) 给出,在 binary32 中是 2-126 × 2-23。这就解释了为什么您可以将tiny(x) 除以 2,即从正常到次正常的过渡。

# 最小的正常数 0 00000001 000000000000000000000002 = 0080 000016 = 2−126 ≈ 1.1754943508 × 10−38 # 最小的次正规数 0 00000000 000000000000000000000012 = 0000 000116 = 2−126 × 2−23 ≈ 1.4012984643 × 10−45

注意:当您将tiny(x)*epsilon(x) 除以 2 时,gfortran 返回算术下溢错误。


Ref:取自Wikipedia: Single precision floating-point format的值

【讨论】:

  • 答案可能与型号有关。我的理解是那些不依赖于 IEEE 标准——以及它对正常或非正常的定义,只依赖于那些模型参数。
  • 顺便说一句,逐渐下溢是不需要发生的事情。并且不会发生,例如,与 gfortran 一起使用 -ffast-math。另一个有趣的点是,在我的 gfortran 中,spacing(0.) 返回与 tiny 相同的答案,即使一个使用型号定义而另一个使用可表示的数字定义,允许更密集。
  • @VladimirF 我在答案中添加了一些型号。
  • 好的,它是最近的,我混淆了最近和间距,不知道为什么。 Nearest 确实会随着 --ffast-math 的变化而改变,即使是以一种奇怪的方式。
猜你喜欢
  • 2012-11-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-01
  • 2014-11-17
  • 2012-11-05
  • 1970-01-01
相关资源
最近更新 更多