c – 查找浮点计数器的最大值

如果以前曾经问过我,我很抱歉,但我找不到它.

我想知道是否有办法计算用作计数器的单精度浮点数达到’最大值’的点(由于丢失而无法再添加其他值的点)精确).

例如,如果我连续向浮点数添加0.1f,我将最终到达值不会改变的点:

const float INCREMENT = 0.1f;
float value = INCREMENT;
float prevVal = 0.0f;

do {
  prevVal = value;
  value += INCREMENT;
} while (value != prevVal);

cout << value << endl;

在海湾合作委员会,这输出2.09715e 06

有没有办法以数学方式计算INCREMENT的不同值?我认为理论上它应该是当浮点数的指数部分需要超过23位的移位时,导致丢失尾数并简单地加0.

解决方法

给定一些正y用作增量,添加y不产生大于X的结果的最小X是2的最小幂,不小于y除以浮点格式的“epsilon”的一半.它可以通过以下方式计算:
Float Y = y*2/std::numeric_limits<Float>::epsilon();
int e;
std::frexp(Y,&e);
Float X = std::ldexp(.5,e);
if (X < Y) X *= 2;

证据如下.我假设IEEE-754二进制浮点运算使用round-to-nearest-ties-even.

当在IEEE-754浮点运算中添加两个数字时,结果是精确的数学结果四舍五入到所选方向上最接近的可表示值.

关于表示法的注释:源代码格式的文本表示浮点值和操作.其他文字是数学的.因此,x y是x和y的精确数学和,x是浮点格式的x,x y是在浮点运算中添加x和y的结果.另外,我将使用Float作为C中的浮点类型.

给定浮点数x,考虑使用浮点算法x y添加正值y.在什么条件下结果会超过x?

令x1为浮点格式中可表示的大于x的下一个值,并让xm为x和x1之间的中点.如果x y的数学值小于x m,则浮点计算x y向下舍入,因此它产生x.如果x y大于xm,则它向上舍入并产生x1,或者它产生更大的数字,因为y足够大以将总和移动到x1以上.如果x y等于xm,则结果为x或x1中的任何一个具有偶数低位.由于我们将看到的原因,在与此问题相关的情况下,这总是x,因此计算向下舍入.

因此,当且仅当x y超过xm时,x y产生大于x的结果,这意味着y超过从x到x1的距离的一半.注意,从x到x1的距离是x的有效数字的低位数中的值1.

在其有效数字中具有p位的二进制浮点格式中,低位的位置值是高位数的位置值的21-p倍.例如,如果x是2e,则其有效数中的最高位表示2e,最低位表示2e 1-p.

问题是,给定一个y,x y不会产生大于x的结果的最小x是多少?它是x的最小值,y不超过x的有效数字的低位数值的一半.

设2e为x的有效位的高位的位置值.那么y≤½•2e 1-p = 2e-p,所以y•2p≤2e.

因此,给定一些正y,x y不产生大于x的结果的最小x具有其前导位2e,等于或超过y·2p.实际上它必须正好是2e,因为其前导位具有位置值2e的所有其他浮点数在其有效数中设置了其他位,因此它们更大. 2e是前导位代表2e的最小数.

因此,x是2的最小幂,等于或超过y•2p.

在C中,std :: numeric_limits< Float> :: epsilon()(来自< limits>标头)是从1到下一个可表示值的步骤,意味着它是21-p.所以y•2p等于y * 2 / std :: numeric_limits< Float> :: epsilon(). (除非溢出到∞,否则此操作是准确的.)

让我们将它赋给变量:

Float Y = y*2/std::numeric_limits<Float>::epsilon();

我们可以通过使用frexp(来自< cmath>标头)从Y和ldexp(也是< cmath>)的浮点表示中提取指数来找到由Y的有效数字的最高位表示的位置值,以应用该值exponent到一个新的有效数字(.5因为frexp和ldexp使用的比例):

int e;
std::frexp(Y,e);

那么X是2的幂,它小于或等于Y.它实际上是2的最大幂不大于Y,因为2的2X的下一个更大的幂大于Y.但是,我们想要两个不小于Y的最小功率.我们可以找到:

if (X < Y) X *= 2;

得到的X是问题所寻求的数字.

相关文章

本程序的编译和运行环境如下(如果有运行方面的问题欢迎在评...
水了一学期的院选修,万万没想到期末考试还有比较硬核的编程...
补充一下,先前文章末尾给出的下载链接的完整代码含有部分C&...
思路如标题所说采用模N取余法,难点是这个除法过程如何实现。...
本篇博客有更新!!!更新后效果图如下: 文章末尾的完整代码...
刚开始学习模块化程序设计时,估计大家都被形参和实参搞迷糊...