C++ Std::stof 不适用于小于 FLT_MIN 的浮点数?



我在以下代码行中遇到问题:

float temp = std::stof("-8.34416e-46");

我的程序一到达此行就会中止。很明显,这个浮点数小于FLT_MIN,但这样的浮点数是允许存在的。(例如,float temp = -8.34416e-46;工作正常。stof方法是否应该只适用于 FLT_MIN 到 FLT_MAX 之间的值?

如果是这样,将字符串("-8.34416e-46")放入浮点数的好选择是什么?

另一种选择

使用std::stod转换为double,然后分配给float。如果需要,添加边界检查。

转换 "-8.34416e-46">

C++ 标准允许将字符串转换为float以报告下溢,如果结果在低于正常范围内,即使它是可表示的。

当使用四舍五入到最接近的可表示值时,−8.34416•10−46float范围内(在C++使用 IEEE-754 二进制 32 表示float的实现中,这很常见),但它在次正常范围内。C++标准说stof调用strtof然后遵从C标准来定义strtof。C 标准指出strtof可能会下溢,关于这一点,它说"如果数学结果的大小太小,以至于数学结果无法在指定类型的对象中表示,如果没有特别的舍入误差,则结果下溢。这是尴尬的措辞,但它指的是遇到低于正常值时发生的舍入误差。(次正态值的相对误差大于正常值,因此它们的舍入误差可能非同寻常。

因此,C++ 标准允许C++实现对次正常值进行下溢,即使它们是可表示的。

二进制32格式中最小的正星等是2−149,约为1.4•10−45。 8.34416•10−46 小于此值,但大于 2−149的一半。这意味着,在 0 到 2−149 之间,它更接近后者,因此四舍五入到最接近的可表示值的转换将产生 2−149而不是零。遗憾的是,您的strtof实现选择报告下溢,而不是完成到最接近的可表示值的转换。

正常

值和次正常值

对于 IEEE-754 32 位二进制浮点数,正常范围是从2-126到 2128-2104。在此范围内,每个数字都用一个有效位数(浮点表示的分数部分)表示,该有效位数具有前导 1 位后跟 23 个附加位,因此将此范围内的任何实数舍入到最接近的可表示值时发生的误差最多是前导位位置值的2-24倍。

除了这个正常范围之外,还有一个从 2−149到 2−126−2−149的次正常范围。在此区间内,浮点格式的指数部分已达到其最小值,不能再减小。为了表示此区间中越来越小的数字,有效数将降低到正常最小值 1 以下。它以 0 开头,后跟 23 个附加位。在此区间内,将实数舍入到最接近的可表示值时发生的误差可能大于前导位位置值的2-24倍。由于指数不能进一步减小,因此此区间中的数字随着越来越小,前导 0 位的数量不断增加。因此,使用这些数字所涉及的相对误差会增加。

无论出于何种原因,C++都表示,实现可能会在此间隔内报告下溢。(IEEE-754标准以复杂的方式定义了下溢,并且还允许实现一些选择。

最新更新