c++内部可以表示的0到1之间不舍入的最大和最小的数是什么?

what are the largest and smallest numbers between 0 and 1 that C++ can represent internally without rounding?

本文关键字:舍入 是什么 不舍 之间 内部 表示 c++      更新时间:2023-10-16

我有一个基于简单模型计算概率的c++函数。c++似乎倾向于将非常小的概率舍入为0,而将非常大的概率舍入为1。这将导致在以后的计算中出现问题(取log(p)和log(1-p))。

是否有一种方法可以显式地表示c++内部可以不舍入表示的小于1的最大数字?同样,大于0的最小数是多少?

我可以这样做:

if (probability == 1) 
    probability = 0.999999999;
else if (probability == 0) 
    probability = 0.000000001;

,但这会导致其他数值问题(与累积数字有关)。是否有一个更有原则的方法,也许使用numeric_limits?

虽然它的名字可能有点误导,但std::numeric_limits<T>::min就是您要找的。对于浮点类型,它将为您提供大于零的最小值。

对于仍然小于1的最大数字,如果使用c++ 11,则可以使用std::nexttoward:

代码
#include<cstdio>
#include<cmath>
#include<limits>
int main(){
  printf("Near 0: %1.20enNear 1: %1.20en",
    std::numeric_limits<double>::min(),
    std::nexttoward(1.0, 0.0)
  );
  return 0;
} 
结果

<>之前接近0:2.22507385850720138309e-308近1:9 . 99999999999999999999888978e -01

c++ double变量为双精度浮点数。IEEE 754标准指定binary64具有:

  • 符号位:1位
  • 指数宽度:11位
  • 有效精度:53位(52显式存储)

给出15-17位有效十进制数字的精度。如果将最多包含15位有效数字的十进制字符串转换为IEEE 754双精度表示,然后再转换回具有相同有效数字数量的字符串,则最终字符串应与原始字符串匹配。

您可以通过使用DBL_EPSILON(或FLT_EPSILON根据您的数据类型)来使用<cfloat>头:

DBL_EPSILON被定义为最小的值,这样1.0 + DBL_EPSILON != 1.0应该符合您的要求。

#include <cfloat>
if (probability == 1.0)
  probability = 1.0 - DBL_EPSILON;
else if (probability == 0.0f)
  probability = DBL_EPSILON;

或者你可以使用<limits>头并可能在你的浮点类型上参数化它:

#include <limits>
if (probability == 1.0)
  probability = 1.0 - std::numeric_limit<double>::epsilon();
else if (probability == 0.0f)
  probability = std::numeric_limit<double>::epsilon();

实际上后者返回由第一种方法定义的值,因此在实现上没有区别。