给定两个浮点数(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,但我想知道是否有一些不错的位魔法,最好没有任何分支。
答案 0 :(得分:0)
自己想出来。在进行重新解释转换时,负数的顺序会反转,因此这是唯一需要修复的内容。这个版本比我希望的要长,但它只是一点点改组,所以它应该很快。
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;
}