float input = whatever;
long output = (long)(0.5f + input);
這對使用編譯器提供的浮點附加支持庫在MSP430上的應用程序是低效的。將有符號單精度浮點四捨五入到最近整數的有效方法是什麼?
我在想,這種特殊類型的「最接近的整數」舍入可能會有一個聰明的「竅門」,避免純浮點加法,或許是直接「點綴」浮點表示,但我還沒有找到這樣的。任何人都可以提出這樣一個把IEEE 754 32位浮點數捨去的技巧嗎?
float input = whatever;
long output = (long)(0.5f + input);
這對使用編譯器提供的浮點附加支持庫在MSP430上的應用程序是低效的。將有符號單精度浮點四捨五入到最近整數的有效方法是什麼?
我在想,這種特殊類型的「最接近的整數」舍入可能會有一個聰明的「竅門」,避免純浮點加法,或許是直接「點綴」浮點表示,但我還沒有找到這樣的。任何人都可以提出這樣一個把IEEE 754 32位浮點數捨去的技巧嗎?
按位操作轉換非常簡單,下面的C代碼演示了它。根據關於MSP430上數據類型的評論,代碼假定int
包含16位,並且long
32位。
我們需要一種手段,儘可能有效地將float
的位模式轉換爲unsigned long
。此實現爲此使用union
,您的平臺可能具有更高效的機器特定方式,例如,一種內在的。在最壞的情況下,使用memcpy()
複製字節。
只有幾種情況可以區分。我們可以檢查float
輸入的指數字段以區分它們。如果參數太大或NaN,轉換失敗。一種慣例是在這種情況下返回最小的負整數操作數。如果輸入小於0.5,結果爲零。在消除這些特殊情況之後,我們留下那些需要一點點計算才能轉換的輸入。
對於足夠大的參數,float
始終是一個整數,在這種情況下,我們只需要將尾數模式轉換爲正確的位位置。如果輸入太小而不是整數,我們將轉換爲32.32定點格式。四捨五入然後基於最重要的分數位,並且在平局的情況下,也是最不重要的整數位,因爲關係必須舍入爲偶數。
如果領帶箱子都應該總是輪遠離零,在代碼舍入邏輯簡化爲
r = r + (t >= 0x80000000UL);
下面是實現上面討論的方法,將具有一個測試框架,測試此沿着float_to_long_round_nearest()
徹底實施。
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
long float_to_long_round_nearest (float a)
{
volatile union {
float f;
unsigned long i;
} cvt;
unsigned long r, ia, t, expo;
cvt.f = a;
ia = cvt.i;
expo = (ia >> 23) & 0xff;
if (expo > 157) { /* magnitude too large (>= 2**31) or NaN */
r = 0x80000000UL;
} else if (expo < 126) { /* magnitude too small (< 0.5) */
r = 0x00000000UL;
} else {
int shift = expo - 150;
t = (ia & 0x007fffffUL) | 0x00800000UL;
if (expo >= 150) { /* argument is an integer, shift left */
r = t << shift;
} else {
r = t >> (-shift);
t = t << (32 + shift);
/* round to nearest or even */
r = r + ((t > 0x80000000UL) | ((t == 0x80000000UL) & (r & 1)));
}
if ((long)ia < 0) { /* negate result if argument negative */
r = -(long)r;
}
}
return (long)r;
}
long reference (float a)
{
return (long)rintf (a);
}
int main (void)
{
volatile union {
float f;
unsigned long i;
} arg;
long res, ref;
arg.i = 0x00000000UL;
do {
res = float_to_long_round_nearest (arg.f);
ref = reference (arg.f);
if (res != ref) {
printf ("arg=%08lx % 15.8e res=%08lx ref=%08lx\n",
arg.i, arg.f, res, ref);
return EXIT_FAILURE;
}
arg.i++;
} while (arg.i);
return EXIT_SUCCESS;
}
所以你正在尋找'long float_to_long_round_nearest(float)'函數的實現,對嗎?在您的平臺上「長」包含多少位?轉換能夠正確處理哪些「float」操作數範圍?應該如何處理領帶案件:聯繫一致,還是聯繫起來?似乎期望的轉換過程不應該涉及浮點運算,因爲這些是在這個平臺上模擬的?我認爲它的編程語言是C? – njuffa
軟件浮點運行緩慢。解決緩慢軟件浮點問題的唯一方法是使用硬件浮點。 –
使用直接在位級表示上操作的位操作方法將IEEE-754「float」轉換爲「long」當然是可能的,但是有一個精確的規範會很有幫助。今天晚些時候,我應該可以爲此製作一些C代碼。 – njuffa