计算浮点中点

compute midpoint in floating point

给定两个浮点数(IEEE 单精度或双精度),我想找到位于它们中间的数字,但不是 (x+y)/2 意义上的,而是相对于实际上可表示的数字。

如果 x 和 y 均为正数,则以下工作

float ieeeMidpoint(float x, float y)
{
    assert(x >= 0  && y >= 0);
    int xi = *(int*)&x;
    int yi = *(int*)&y;
    int zi = (xi+yi)/2;
    return *(float*)&zi;
}

这样做的原因是正 ieee 浮点数(包括次正规数和无穷大)在进行重新解释转换时会保持它们的顺序。 (这对于 80 位扩展格式不是真的,但我不需要它)。

现在我正在寻找一种优雅的方法来做同样的事情,包括其中一个或两个数字都为负数的情况。当然,用一堆 if 很容易做到,但我想知道是否有一些不错的位魔术,最好没有任何分支。

我自己想出来了。在进行重新解释转换时,负数的顺序被颠倒了,所以这是唯一需要修复的东西。这个版本比我希望的要长,但它只是一些位改组,所以应该很快。

float ieeeMidpoint(float x, float y)
{
    // check for NaN's (Note that subnormals and infinity work fine)
    assert(x ==x && y == y);

    // re-interpreting cast
    int xi = *(int*)&x;
    int yi = *(int*)&y;

    // reverse negative numbers
    // (would look cleaner with an 'if', but I like not branching)
    xi = xi ^ ((xi >> 31) & 0x3FFFFFFF);
    yi = yi ^ ((yi >> 31) & 0x3FFFFFFF);

    // compute average of xi,yi (overflow-safe)
    int zi = (xi >> 1) + (yi >> 1) + (xi & 1);

    // reverse negative numbers back
    zi = zi ^ ((zi >> 31) & 0x3FFFFFFF);

    // re-interpreting back to float
    return *(float*)&zi;
}