C 计算浮点数据类型的范围

C 计算浮点数据类型的范围,c,C,是否可以在不读取float.h和使用ANSI C的情况下,以可移植的方式计算float、double和long double数据类型的范围?所谓便携式,我的意思是包括目标机器不符合IEEE 754标准的情况 我正在阅读K&R手册,练习2-1要求我“计算”它们,因此我认为这意味着完全避免float.h,其中包括FLT_MIN、FLT_MAX、DBL_MIN和DBL_MAX(直接读取这些值肯定不会归类为“计算”).您可以尝试将浮点变大,直到其溢出。对于99.99%的应用程序,您应该假设IEEE 75

是否可以在不读取float.h和使用ANSI C的情况下,以可移植的方式计算float、double和long double数据类型的范围?所谓便携式,我的意思是包括目标机器不符合IEEE 754标准的情况


我正在阅读K&R手册,练习2-1要求我“计算”它们,因此我认为这意味着完全避免float.h,其中包括FLT_MIN、FLT_MAX、DBL_MIN和DBL_MAX(直接读取这些值肯定不会归类为“计算”).

您可以尝试将浮点变大,直到其溢出。

对于99.99%的应用程序,您应该假设IEEE 754并使用
中定义的常量。在其他0.01%的情况下,您将使用非常专业的硬件,在这种情况下,您应该知道基于硬件使用什么。

可以(至少对于IEEE 754
float
double
值)通过(伪代码)计算最大的浮点值:

在进行位旋转之前,我们必须先将浮点值转换为整数,然后再转换回来。这可以通过以下方式完成:

uint64_t m_one, half;
double max;

*(double *)(void *)&m_one = -1.0;
*(double *)(void *)&half = 0.5;
*(uint64_t *)(void *)&max = ~m_one | half;
那么它是如何工作的呢?为此,我们必须知道浮点值将如何编码

最高位编码符号,下一个
k
位编码指数,最低位保存小数部分。对于
2
的幂,小数部分为
0

指数将以
2**(k-1)-1的偏差(偏移量)存储,这意味着
0的指数对应于除最高位设置外的所有模式

有两种具有特殊含义的指数位模式:

  • 如果未设置位,则如果分数部分为零,则值将为
    0
    ;否则,该值低于正常值
  • 如果设置了所有位,则值为
    无穷大
    NaN
这意味着将通过设置除最低位之外的所有位对最大正则指数进行编码,最低位对应于
2**k-2
2**(k-1)-1
(如果减去偏差)

对于
double
值,
k=11
,即最高指数为
1023
,因此最大浮点值的顺序为
2**1023
,大约为
1E+308

最大的价值将是

  • 符号位设置为
    0
  • 除最低指数位设置为
    1
  • 所有分数位设置为
    1
现在,我们可以了解我们的神奇数字是如何工作的:

  • -1.0
    设置了符号位,指数是偏差-即除最高位之外的所有位都存在-小数部分是
    0
  • ~(-1.0)
    仅设置了最高指数位和所有分数位
  • 0.5
    具有符号位和
    0
    的小数部分;指数将是偏差减去
    1
    ,即除最高和最低指数位外,所有其他位都将出现
当我们通过逻辑or组合这两个值时,我们将得到我们想要的位模式


计算也适用于x86 80位扩展精度值(也称为长双精度),但位旋转必须按字节进行,因为没有足够大的整数类型可以在32位硬件上保存值

实际上,偏差不需要是
2**(k-1)-1
——它可以用于任意偏差,只要它是奇数。偏差必须是奇数,否则
1.0
0.5
指数的位模式将在最低位以外的其他位置不同

如果浮点类型的基
b
(又称基数)不是
2
,则必须使用
b**(-1)
,而不是
0.5=2**(-1)

如果未保留最大指数值,请使用
1.0
而不是
0.5
。无论基值或偏差如何(这意味着它不再局限于奇数)。使用
1.0
的区别在于最低指数位不会被清除


总结如下:

~(-1.0) | 0.5
只要基数为
2
,偏差为奇数且保留了最高指数,就可以工作

~(-1.0) | 1.0

适用于任何基数或偏差,只要不保留最高指数。

冒着回答多余的风险:

~(-1.0) | 1.0

没有。没有一种便携式的方法来计算范围。这就是为什么要提供
标题的原因-因为没有一种可移植的方法来派生其中包含的信息。

这就是我对整数类型所做的-但是溢出一个长的double不需要很长时间吗?如果通过指数搜索,溢出速度足够快。你甚至可以使数字增长得更快(例如,指数搜索的最大指数与指数搜索的最大值),为什么你认为这意味着要避免浮点?我想它想让你使用一些函数,比如ldexp,FLT_RADIX(或者它叫什么名字)和stuffWell,因为float.h已经有了最小/最大值,这在这种情况下看起来像是作弊。但是是的,float.h中还定义了一些其他常数,可能用于确定实际范围。说“for IEEE 754”否定了这个问题的前提。@Jonathan:至少“for”不是“only for”的意思,而是“only for”-这适用于偏差
2**(k-1)的每个浮点值-1
和保留指数
2**k-1
,该指数包括一半和四倍精度值以及80位扩展精度值x86@Jonathan:如果不限制可能的编码方案,您还想如何“计算”某些内容?只是没有一个算法可以适用于所有编码!这是真的-但是有一些计算将适用于范围广泛的编码方案!