2012-02-01 64 views
1

我正在寫一個算法,將浮點數除以2. 在數字已經規範化(指數位> 0)的情況下,我認爲這個過程非常簡單。我認爲簡單地將指數字段減1,然後將該值粘貼回來是一種正確的方法。將非規格化數除以2

我遇到了如何處理已經非規範化的浮點數(指數位全爲0)的問題。 我明白什麼是非正規化的數字,並且相信我通常明白劃分它們的意義。我正在運行我通過另一個程序編寫的算法,這裏有一條消息讓我困惑:

將值0x7fffff傳遞給函數返回3fffff。該函數應該返回0x400000。

我真的不明白這裏發生了什麼,爲什麼這應該返回這個指定的值。有沒有人可以嘗試解釋這個,爲什麼它應該返回這個值?

我最初處理非規格化數字的方法是將小數位右移一位(除以2),這似乎並不是所需的過程。

以下是我有:

unsigned float_half(unsigned uf) { 

    unsigned exp = uf & (0x7F800000); 
    unsigned sign = uf & (0x80000000); 
    unsigned fract = uf & (0x007FFFFF); 
    // Check for NaN or infinity 
    if(exp == 0x7F800000) { 
    return uf; 
    } 
    // Check for denormalized numbers 
    if(exp == 0x00000000) { 
    // Need to do something here, not really sure... 

    return sign | exp | fract; 
    } 
    // Check for exponent of 1 (going to a denormalized number changes things) 
    if(exp == 0x00800000) { 
    fract = (0x00FFFFFF & uf) >> 1; 
    return fract | sign; 
    } 

    exp--; 
    exp = exp & (0x7F800000); 
    return sign | exp | fract; 
} 
+0

@caf:是不是我已經這樣做了嗎?你爲什麼覺得有必要提一提? – 2012-02-01 03:54:18

+0

對不起,你是 - 我只是對你的第一段文本作出反應,你沒有提到指數1的例外,而不是你所做的代碼。 – caf 2012-02-01 04:44:32

+0

@caf:沒問題,謝謝你的輸入。 – 2012-02-01 04:50:04

回答

2

你可能應該一輪的非規範化的情況下的值。對於0x7fffff,您正在切換最後的1位。看來你預計回合的分數值。相反,例如像這樣:

if(exp == 0x00000000) { 
    fract = (0x00FFFFFF & uf) >> 1; 
    if (0x00000001 & uf) 
    fract++; 
    return fract | sign; 
} 

如果你都應該四捨五入向上或向下也可能取決於標誌。

+0

沒有理由相信所需的舍入不是最接近的,因爲這是IEEE 754默認值,並且與該函數應該返回0x400000 [用於0x7fffff]在兼容性問題中兼容。 – 2013-11-12 20:45:10

4

該函數應該返回0x400000是爲了滿足循環模式。 這裏是我的功能:

unsigned float_half(unsigned uf){ 
    unsigned sign = uf & (0x80000000); 
    unsigned exp = uf >> 23 & 0xff; 
    unsigned frac = f & 0x7fffff; 

    if(exp == 0xff) 
     return uf; 
    else if (exp > 1) 
     return sign | --exp << 23 | frac; 
    else { 
     if (exp == 1) 
      frac |= 1 << 23; 
     if ((frac & 3) == 3) 
      frac++; 
     frac >>= 1; 
     return sign | frac; 
    } 
} 

另一個

unsigned float_half(unsigned uf){ 
    unsigned sign = uf & (0x80000000); 
    unsigned exp_frac = uf & 0x7fffffff; 

    if (exp_frac >= 0x7f800000) 
     return uf; 
    else if (exp_frac > 0x00ffffff) 
     return uf + 0xff800000; 
    else { 
     if ((exp_frac & 3) == 3) 
      exp_frac++; 
     exp_frac >> 1; 
     return sign | exp_frac; 
    } 
}