【问题标题】:Behavior of Float overflow in CC 中浮点溢出的行为
【发布时间】:2017-05-15 20:46:44
【问题描述】:

我是 C 的新手,到目前为止,我只使用过 OOP 语言,而不必过多地关注内存或位的工作​​方式,我需要帮助来了解这里发生的事情。

我必须通过将变量初始化为数据类型的最小/最大值并尝试加或减 1 来测试 C 中每种数据类型的最小和最大界限。我已经超越了整数类型,现在我对 Float 类型的行为感到困惑。我一直在阅读的很多内容有点过头了,如果有人能帮助我了解这些类型的工作原理,我将不胜感激。

这是我用来测试浮点数的:

void DisplayFloatMinimumAndMaximum()
{
// Declare variables
float fltMinimum = 0;
float fltMaximum = 0;

// Set min/max values
fltMinimum = -3.4e38;
fltMaximum = 3.4e38;

printf("Float Minimum and Maximum\n");
printf("------------------------------------------------\n");
printf("Float Minimum : %.10e\n", fltMinimum);
printf("Float Maximum : %.10e\n", fltMaximum);
printf("\n");

fltMinimum -= 1.0f;
fltMaximum += 1.0f;

printf("Confirmation\n");
printf("Float Minimum : %.10e\n", fltMinimum);
printf("Float Maximum : %.10e\n", fltMaximum);
printf("\n");
}

我得到的结果是:

Float Minimum and Maximum
------------------------------------------------
Float Minimum : -3.3999999521e+38
Float Maximum : 3.3999999521e+38

Confirmation
Float Minimum : -3.3999999521e+38
Float Maximum : 3.3999999521e+38

似乎什么也没发生。
这是正确的行为吗?如果是这样,为什么?如果不是,为什么?

(我使用的是 Visual Studio 2015)

【问题讨论】:

    标签: c


    【解决方案1】:

    由于数据的浮点性质,向如此大的数字添加/减去 1 没有任何作用,因为该值被“吸收”(正如 Weather 评论的那样,在添加两个操作数之前,必须对它们进行归一化,以便尾数表示为 2 的幂次方。这样做时,如果较小的操作数向下滚动到 0,则其所有意义都将丢失)

    值保持不变,您无法达到上溢/下溢。

    http://www.fact-index.com/f/fl/floating_point_1.html

    添加更改数字的最小值由machine epsilon确定

    玩极限的最好方法不是加,而是乘以(1+FLT_EPSILON)(等于FLT_EPSILON的加数)

    #include <float.h>
    #include <stdio.h>
    
    int main()
    {
     float f = FLT_MAX;
    
     f *= (1+FLT_EPSILON/2);
     printf("%f\n",f);
    
    return 0;
    }
    

    这将打印数字,不变。吸收忽略了乘法。

    现在这样做:

    #include <float.h>
    #include <stdio.h>
    
    int main()
    {
     float f = FLT_MAX;
    
     f *= (1+FLT_EPSILON);
     printf("%f\n",f);
    
    return 0;
    }
    

    输出是

    1.#INF00
    

    FLT_MAX的情况下,在我的机器上,要添加触发溢出的限制数远远超过1:它是40564816789451702000000000000000.000000

    【讨论】:

    • @user3691838 也许尝试将 large 值添加到最大值(就像刚刚添加到答案中一样)。
    • 我没有想到这一点。如果我在 +=1 上循环无数次,我将永远不会改变这个值。我的意思是我知道 float 的精度有限,但这仍然是一个惊喜。
    • @user3691838 在添加两个操作数之前,必须对它们进行归一化,以便两个尾数都表示为 2 的相同幂。这样做时,如果较小的操作数向下滚动到 0意义丧失。 (当操作数相乘、尾数相乘和指数相加时,情况就不一样了)。
    • @WeatherVane 你需要一个 laaaaaaarge 值,例如 > 40564816789451702000000000000000
    • @WeatherVane 很好的解释。我没有走那么远。请允许我在我的回答中引用您的评论。
    【解决方案2】:

    浮点限制

    有定义限制的宏。 FLT_MAXFLT_MIN分别是float类型的最大值和最小值。

    还有其他宏,例如FLT_MAX_EXP(以FLT_RADIX 定义的最大指数,通常值为2)和FLT_MAX_10_EXP(以10 为底定义的最大指数)。

    float 中可表示的最小数字是浮点 epsilon,在 FLT_EPSILON 宏中定义,值为 1E-5

    这些宏可以在float.h找到

    精度

    注意:在这个解释中,我将使用基数 10 来进行说明。然而,C 使用上面提到的FLT_RADIX 宏定义的基数(通常值为 2)。

    浮点数通过有效数和指数表示:

    1234 = 1.234 x 10^3

    在 C 语言中,单精度浮点数将为您提供 24 位有效数字和 8 位指数。这意味着,如果您的有效数字的位数多于可以在有效位中编码的数字,它就会开始失去精度。

    一个非常大的数字将显示一个有效数字和一个指数。

    1000000000000001 将变为 1.000000000000001 x 10^15

    此有效位将被四舍五入,因为它太大而无法在有效位中编码。同样,向该数字添加少量也会导致有效数字四舍五入,因此不会产生增量。

    【讨论】:

    • 浮点数通常使用 2 的指数幂进行编码,而不是 10。
    • @WeatherVane,IEEE754 使用二进制基数,是的。我选择了一个十进制示例只是为了说明这个概念。
    猜你喜欢
    • 2018-02-17
    • 1970-01-01
    • 1970-01-01
    • 2023-03-16
    • 1970-01-01
    • 2023-03-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多