TINY(x) 内在函数

问题描述

我是一名大学讲师,本学期我将使用 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) 没有产生最小的可表示的正数,由于函数调用显示什么?

解决方法

Fortran 标准声明了以下关于真实值的内容:

真实x的模型集由

定义

model representation of a real according to Fortran

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

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

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) 除以二,即从正常到次正常的过渡。

# smallest normal number
0 00000001 000000000000000000000002 = 0080 000016 = 2−126 ≈ 1.1754943508 × 10−38
# smallest subnormal number
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

的值