2017-04-17 110 views
0

给定两个浮点数(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

当操作数的符号相反时,“中点”的定义是什么?例如,'ieeeMidPoint(-1,4)'的期望结果是什么。这不清楚。请注意,尝试按照所示方式(通过指针转换)将存储重新解释为不同类型,会在C和C++中调用未定义的行为。如果您使用更高的优化级别编译,这通常会变得明显。建议:如果使用C,则使用('volatile')'union',如果使用C++,则使用'mempcy()'将浮点数据重新解释为整数,反之亦然。 – njuffa

+0

如果$ [x,z] $中的可表示数字与$ [z,y] $中的数字相同,$ z $就是$ x $和$ y $之间的中点。指数和尾数都有限位,所以这些计数总是有限的。 – Simon

回答

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; 
}