2017-04-17 108 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; 
}