为什么在 numeric_limits<float>::min()中加1会返回1?

问题描述 投票:0回答:1

为什么从float max中减去1会返回一个合理的值,而在float min中加1会返回1?

我想,如果你加或减一个小于该特定量级的epsilon的值,那么什么都不会发生,也不会有增加或减少。

这是我用g++编译的代码,没有标志,在x86_64上运行。

#include <limits>
#include <iostream>

int main() {
    float min = std::numeric_limits<float>::min() + 1;
    float max = std::numeric_limits<float>::max() - 1;

    std::cout << min << std::endl << max << std::endl;
    return 0;
}

输出的结果是这样的。

1
3.40282e+38

我希望它能输出这样的结果

-3.40282e+38
 3.40282e+38
c++ gcc floating-point x86-64 floating-accuracy
1个回答
5
投票

std::numeric_limits<float>::min() 返回最小的归一化正值。要得到没有比它更小的值,可以使用 std::numeric_limits<float>::lowest().

https:/en.cppreference.comwcpptypesnumeric_limitsmin。


5
投票

min 是最小量级的正向归一化浮点数,是一个非常微小的正数(约为 1.17549e-38),而不是幅度很大的负数。. 请注意 - 是在指数中,这是科学的符号。 e-38 意思是小数点后有38个零。 试着在 https:/www.h-schmidt.netFloatConverterIEEE754.html 在二进制中玩弄位 float.

std::numeric_limits<float>::min() 是最小值 幅度 归一化 float,不 -max. CppReference 甚至有一个关于这可能是令人惊讶的说明。

你知道为什么选择这个值作为min()的值而不是最低的负值吗?与其他类型相比,这似乎是一个异常值。

中的一些复杂性。numeric_limits<T> 喜欢 lowestdenorm_min 是C++11中新增加的,定义什么的选择大多沿袭了C,历史上C重视经济,没有定义很多不同的名字。 (在古代的计算机上,小的比较好,也少了全局命名空间的东西,而全局命名空间是C所能接触到的)。

浮点数类型通常是1 0附近对称(signmagnitude表示),所以C语言没有为最负的float double long double单独命名常数。 只是 FLT_MAXFLT_MIN CPP宏。 C语言没有模板,所以你知道你在写FP代码的时候,可以用一个 - 如果需要的话,可以在适当的常量上使用。

如果你只需要几个命名的常量,那么最有趣的三个常量是。

  • FLT_EPSILON 告诉你可用的精度 (mantissa 位): nextafter(1.0, +INF) - 1.0
  • FLT_MIN FLT_MAX 最小(标准化)和最大的有限浮点数。 这主要取决于一个浮子有多少指数位。

    它们在1.0附近不太对称,原因有二:FLT_MAX中的全一元万字符,以及渐进的下溢(次正态)占据了最低的指数场(0与偏置),但 FLT_MIN 忽略次正态。 FLT_MIN * FLT_MAX 是约3.99999976的 IEEE754二进制32 float. (出于性能的考虑,你通常要避免亚正常值,所以你有逐渐下流的空间,所以FLT_MIN不是有意义的 denorm_min)

(有趣的是。0.0 是亚正态的一个特例:指数场=0,意味着0.xxx而不是1.xxx的万字符)。)

脚注1: CppReference 指出,C++11 std::numeric_limits<T>::lowest() 可以 有别于 -max 用于第三方FP类型,但不是用于标准的C++ FP类型。

lowest 你想要的:最负的有限值。 它在整数和FP类型中是一致的,因为它是最负值,所以例如,你可以将它作为一个模板化搜索循环的初始化器,使用 std::min 来寻找一个数组中的最低值。

C++11还引入了 denorm_min,是FP类型的最小正次正态值,又称去正态值。 在IEEE754中,对象表示法除了万字符的低位有1之外,其他位都是0。


浮点数的结果是 1.0 + 1.17549e-38 (四舍五入后) float)正是 1.0. min 低于 std::numeric_limits<float>::epsilon 所以,当加入到 "四舍五入 "时,整个变化会因四舍五入错误而丢失。1.0.

因此,即使你用全精度打印浮点数(或作为一个十六进制浮点数),它也会是 1.0. 但你只是用默认的格式来打印。cout 其中,四舍五入到一些有限的精度,比如小数点后6位。 https:/en.cppreference.comwcppiomanipsetprecision。

(该问题的早期版本包括数值为 min ~=1.17549e-38;这个答案一开始就是为了解决这个混淆的问题,我还没有去完全重写这些部分)。)

© www.soinside.com 2019 - 2024. All rights reserved.