2012-02-01 61 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; 
    } 
}