如何以最小增量(或接近它)改变浮点数?

Owe*_*wen 47 c c++ floating-point

我有一个double价值f,并想要一个稍微大一点(或更小)的方法来获得一个新的值,该值尽可能接近原始值但仍严格大于(或小于)原始值.

它不必靠近最后一位 - 更重要的是,我所做的任何改变都能保证产生不同的值,而不是回到原始值.

Nil*_*nck 62

检查math.h文件.如果你很幸运,你可以定义nextafternextafterf功能.它们以便携式和平台独立的方式完成您想要的任务,并且是C99标准的一部分.

另一种方法(可能是后备解决方案)是将你的浮点数分解为尾数和指数部分.增量很简单:只需在尾数中添加一个即可.如果出现溢出,则必须通过递增指数来处理此问题.减量的工作方式相同.

编辑:正如评论中指出的那样,只需增加浮点数的二进制表示就足够了.尾数溢出将增加指数,这正是我们想要的.

简而言之,这与nextafter的做法相同.

但这不是完全可移植的.您将不得不处理endianess和不是所有机器都有IEEE浮动的事实(好的 - 最后一个原因是更具学术性).

处理NAN和infinite也有点棘手.你不能简单地增加它们,因为它们是定义而不是数字.

  • 你特别不想处理尾数溢出,因为溢出将转移到你想要的指数上. (9认同)
  • 这很酷:)现在可以贬低我的答案的白痴说,请撤消它吗? (2认同)
  • 如果指数增量溢出到符号位,这将如何工作? (2认同)
  • 我认为负值也必须区别对待.如果递增,结果将比原始值更负.顺便说一句 - 我刚刚在VS.NET 2008实现中反汇编了nextafter.它们比我预期的要多得多. (2认同)

小智 23

u64 &x = *(u64*)(&f);
x++;
Run Code Online (Sandbox Code Playgroud)

是的,认真的.

编辑:有人指出,这不适用于-ve数字,Inf,Nan或溢出.以上是更安全的版本

u64 &x = *(u64*)(&f);
if( ((x>>52) & 2047) != 2047 )    //if exponent is all 1's then f is a nan or inf.
{
    x += f>0 ? 1 : -1;
}
Run Code Online (Sandbox Code Playgroud)

  • 未定义的行为,违反严格的别名规则 (2认同)
  • 这也不处理-0。 (2认同)

moo*_*dow 5

就绝对而言,您可以添加到浮点值以生成新的不同值的最小数量将取决于该值的当前大小;它将是类型的机器 epsilon乘以当前指数。

查看浮点表示的IEEE 规范。最简单的方法是将值重新解释为整数类型,加 1,然后通过检查符号和指数位检查(如果您关心)您没有翻转符号或生成 NaN。

或者,您可以使用frexp获取当前尾数和指数,从而计算要添加的值。