1

浮動小数点数を2で割るアルゴリズムを書いています。数値がすでに正規化されている場合(指数ビットは> 0)、プロセスは非常に簡単だと思います。指数フィールドを1つ減らしてから、その値を元に戻すのが正しいアプローチだと思います。

すでに非正規化されている浮動小数点数を処理する方法を思い付くのに問題があります(指数ビットはすべて0です)。非正規化数とは何かを理解しており、それらを除算することの意味を一般的に理解していると思います。私は別のプログラムを介して作成したアルゴリズムを実行しています。これが私を混乱させる1つのメッセージです。

値0x7fffffを関数に渡すと、3fffffが返されます。この関数は0x400000を返すことになっています。

ここで何が起こっているのか、そしてなぜこれがこの指定された値を返すことになっているのか、私は本当に理解していません。これを試して説明できる人はいますか?なぜこの値を返すことになっているのですか?

非正規化数を処理するための私の最初のアプローチは、小数ビットを1ずつ右シフトする(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;
}
4

2 に答える 2

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;
    }
}
于 2012-05-11T07:25:40.000 に答える
2

非正規化された場合は、おそらく値を丸めることになっています。あなたはシフトで0x7fffff最後のビットを切り取っているからです。1代わりに、たとえば次のように値を切り上げることが期待されているようです。

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

切り上げるか切り下げるかは、記号によっても異なる場合があります。

于 2012-02-01T03:43:49.977 に答える