fortran fortran中文资料网
手气不错
Article

052.machineLimits_机器精度与数值范围

2026年9月29日基础级

epsilon、tiny和huge是Fortran标准定义的数值模型查询函数。对于实数模型,epsilon描述1附近的相对间隔,tiny给出最小正模型数,huge给出最大有限模型数。它们查询的是参数类型和kind所对应的模型,而不是参数当前值。常用于评估舍入误差、选择与精度相适应的容差,以及在乘法、缩放和迭代计算前检查上溢或下溢风险,适合与iso_fortran_env提供的real32、real64结合使用。

语法结构

relativeSpacing = epsilon(realModelValue)
smallestModelValue = tiny(realModelValue)
largestModelValue = huge(realModelValue)
  • epsilon(x)要求x为实数,返回与x同kind的标量。它满足1+epsilon(x)>1,表示该实数模型在1附近能够分开的相邻数间隔。
  • tiny(x)要求x为实数,返回同kind实数模型中的最小正模型数。在采用IEEE渐进下溢的系统上还可能存在更小的次正规数,但其有效精度会降低。
  • huge(x)可查询整数或实数模型;本文只查询实数。它返回最大有限模型数,并不表示无穷大。
  • 实参只用于选择类型和kind,因此epsilon(1.0_real32)与epsilon(1000.0_real32)相同。查询任意数值附近的实际间隔应使用spacing,不能把epsilon机械地当成所有量级通用的绝对容差。

本文代码

! 比较REAL32与REAL64的模型参数,并用查询结果判断舍入和范围风险。
program machineLimitsDemo
  use iso_fortran_env, only: real32, real64
  implicit none

  real(real32) :: one32, epsilon32, tiny32, huge32
  real(real32) :: largeValue, multiplier, concentration, decayFactor
  real(real64) :: one64

  one32 = 1.0_real32
  one64 = 1.0_real64
  epsilon32 = epsilon(one32)
  tiny32 = tiny(one32)
  huge32 = huge(one32)

  print "(A,ES16.6E3)", "REAL32 epsilon:", epsilon32
  print "(A,ES16.6E3)", "REAL64 epsilon:", epsilon(one64)
  print "(A,ES16.6E3)", "REAL32 tiny:  ", tiny32
  print "(A,ES16.6E3)", "REAL64 tiny:  ", tiny(one64)
  print "(A,ES16.6E3)", "REAL32 huge:  ", huge32
  print "(A,ES16.6E3)", "REAL64 huge:  ", huge(one64)

  print "(A,ES16.6E3)", "加上epsilon/2后的增量:", &
    (one32 + epsilon32 / 2.0_real32) - one32
  print "(A,ES16.6E3)", "加上epsilon后的增量:  ", &
    (one32 + epsilon32) - one32

  largeValue = 0.75_real32 * huge32
  multiplier = 2.0_real32
  print "(A,L1)", "largeValue * multiplier会溢出:", &
    abs(largeValue) > huge32 / abs(multiplier)

  concentration = 1.0e-30_real32
  decayFactor = 1.0e-10_real32
  print "(A,L1)", "衰减结果低于最小正规数:", &
    concentration * decayFactor < tiny32
  print "(A,ES16.6E3)", "衰减结果:", concentration * decayFactor
end program machineLimitsDemo

编译运行

(base) hong@hongdeMacBook-Pro 052.machineLimits % gfortran -Wall -Wextra -std=f2018 exampleMachineLimits.f90 -o machineLimitsDemo
(base) hong@hongdeMacBook-Pro 052.machineLimits % ./machineLimitsDemo
REAL32 epsilon:   1.192093E-007
REAL64 epsilon:   2.220446E-016
REAL32 tiny:     1.175494E-038
REAL64 tiny:     2.225074E-308
REAL32 huge:     3.402823E+038
REAL64 huge:     1.797693E+308
加上epsilon/2后的增量:   0.000000E+000
加上epsilon后的增量:     1.192093E-007
largeValue * multiplier会溢出:T
衰减结果低于最小正规数:T
衰减结果:   9.999946E-041

现象分析

real32的epsilon约为1.192093×10-7,而real64约为2.220446×10-16。后者在1附近的相邻数间隔更小,因此能保留更多有效数字。在默认舍入方式下,real32的epsilon/2不足以使1.0移动到下一个可表示数,先做加法再减去1.0得到0;加入完整epsilon后则得到1.192093×10-7。

real32的正规范围约从1.175494×10-38延伸到3.402823×1038,real64则约从2.225074×10-308延伸到1.797693×10308。这说明real64不仅精度更高,指数范围也远大于real32;但代价通常是每个数占用更多存储空间,并可能增加内存带宽开销。

largeValue等于0.75×huge,若直接再乘2,理论结果为1.5×huge,超出real32最大有限值。代码没有执行危险乘法,而是将条件改写为abs(largeValue)>huge/abs(multiplier);0.75×huge大于0.5×huge,因此输出T。实际程序还应单独处理乘数为零以及符号等边界情况。

浓度1.0×10-30乘衰减因子1.0×10-10,数学结果为1.0×10-40,小于real32的tiny。当前平台支持IEEE次正规数,所以结果没有立即变成零,而是以降低精度的9.999946×10-41保存。tiny标记的是进入次正规或下溢敏感区域的边界,不能简单理解成“任何小于tiny的结果都等于零”。

核心知识点

  • epsilon表示1附近的相对间隔,不是任意量级下通用的绝对误差,也不应直接作为所有浮点比较的固定容差。
  • tiny是最小正模型数;支持渐进下溢时可能存在更小的次正规值,但精度会逐步降低。
  • huge是最大有限模型数。通过除法形式预检乘法范围,可以避免先发生溢出再判断。
  • 三个查询结果由实参的类型和kind决定,与实参当前数值无关;使用查询函数比硬编码特定机器常数更可移植。
  • real64相较real32同时提供更细的有效精度和更宽的指数范围,应根据计算误差、数据规模和资源成本选择。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注