2017-04-17 10 views
0

2つの浮動小数点数(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; 
} 

理由は再解釈キャストを行う時(subnormalsと無限大を含む)正のIEEE浮動小数点数は、その順序を維持することである動作します。 (これは80ビット拡張フォーマットでは当てはまりませんが、とにかくその必要はありません)。

ここで、数字のいずれかまたは両方が否定的である場合も含めて、同じことを行うためのエレガントな方法を探しています。もちろん、ifの束とはやりやすいですが、枝分かれしないビットマジックがあるかどうかは不思議です。

+0

オペランドの符号が反対の場合の「中点」の定義は何ですか?たとえば、 'ieeeMidPoint(-1,4)'の望ましい結果は何か。これは明らかではない。示された方法で(ポインタ変換によって)異なるタイプにストレージを再解釈しようとすると、CおよびC++の両方で未定義の動作が呼び出されることに注意してください。これは通常、より高い最適化レベルでコンパイルすると明らかになります。提案:Cを使用する場合は 'union'を使用し、C++を使用する場合は' mempcy() 'を使用して浮動小数点データを整数に、またはその逆に再解釈します。 – njuffa

+0

$ [z、y] $と同じ数の表現可能な数字が$ [x、z] $にある場合、$ 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; 
} 
関連する問題