1

固定小数点演算とビットシフトをチェックするために、次のテストコードを作成しました。

void main(){
    float x = 2;
    float y = 3;
    float z = 1;
    unsigned int * px = (unsigned int *) (& x);
    unsigned int * py = (unsigned int *) (& y);
    unsigned int * pz = (unsigned int *) (& z);
    *px <<= 1;
    *py <<= 1;
    *pz <<= 1;
    *pz =*px + *py;
    *px >>= 1;
    *py >>= 1;
    *pz >>= 1;
    printf("%f %f %f\n",x,y,z);
  }

結果は2.0000003.0000000.000000です。

最後の数字が0なのはなぜですか?5.000000が表示されることを期待していました。ある種の固定小数点演算を使用して、画像処理アプリケーションでの浮動小数点数の使用をバイパスしたいと考えています。浮動小数点配列を整数に変換するための最良/最も簡単/最も効率的な方法はどれですか?上記の「コンパイラをだます」は強力な回避策ですか?助言がありますか?

4

4 に答える 4

3

固定小数点を使用する場合は、型 ' float' または ' double' を使用しないでください。これらには内部構造があるためです。float と double には符号用の特定のビットがあります。指数用のビット、仮数用のビット (ここでカラー画像を見てください)。したがって、それらは本質的に浮動小数点です。

データを整数型に手動で格納する固定小数点をプログラムするか、固定小数点ライブラリ (または言語拡張) を使用する必要があります。

GCC で実装された浮動小数点拡張機能の説明があります: http://gcc.gnu.org/onlinedocs/gcc/Fixed_002dPoint.html

C の固定小数点の MACRO ベースの手動実装があります: http://www.eetimes.com/discussion/other/4024639/Fixed-point-math-in-C

于 2012-05-30T15:36:19.620 に答える
2

コンパイラがfloats に IEEE 754 形式を使用している可能性があります。これはビット単位で次のようになります。

SEEEEEEEEFFFFFFFFFFFFFFFFFFFFFFF
^ bit 31                       ^ bit 0

Sは符号ビットです。s = 1 は、数値が負であることを意味します。

Eビットは指数です。0 ~ 255 の範囲を示す 8 つの指数ビットがあります、指数には偏りがあります。実際の指数を取得するには、127 を減算する必要があります。

Fビットは小数部分ですが、前面に目に見えない 1 を想像する必要があるため、分数は常に 1 であり、表示されるのは 2 進数の小数のみです。

数値 2 は 1 x 2 1 = 1 x 2 128 - 127なので、次のようにエンコードされます。

01000000000000000000000000000000

したがって、ビットシフトを使用して右にシフトすると、

10000000000000000000000000000000

慣例により、IEEE754 では -0 であるため、数値を 2 倍するのではなく、シフトによってゼロになります。

数 3 は [1 + 0.5] x 2 128 - 127

これは次のように表されます

01000000010000000000000000000000

その左にシフトすると、

10000000100000000000000000000000

これは -1 x 2 -126または非常に小さい数です。

z についても同じことができますが、おそらく、シフトが浮動小数点数を台無しにするだけであるという考えが得られます。

于 2012-05-30T16:06:19.273 に答える
2

あなたがしていることは、数字に対する残虐行為です。

まず、float 変数に値を代入します。どのように格納されるかはシステムによって異なりますが、通常はIEEE 754 形式が使用されます。したがって、変数は内部的に次のようになります

x = 2.0 = 1 * 2^1   : sign = 0, mantissa = 1,   exponent = 1 -> 0 10000000 00000000000000000000000 = 0x40000000
y = 3.0 = 1.5 * 2^1 : sign = 0, mantissa = 1.5, exponent = 1 -> 0 10000000 10000000000000000000000 = 0x40400000
z = 1.0 = 1 * 2^0   : sign = 0, mantissa = 1,   exponent = 0 -> 0 01111111 00000000000000000000000 = 0x3F800000

これらの数値に対してビットシフト操作を行うと、符号、指数、仮数の間の境界が混同されるため、何かが起こる可能性があり、起こる可能性があります。

あなたの場合:

  • 2.0 は 0x80000000 になり、-0.0 になります。
  • 3.0 は 0x80800000 になり、-1.1754943508222875e-38 になります。
  • 1.0 は 0x7F000000 になり、結果は 1.7014118346046923e+38 になります。

後者は、-0.0 と -1.1754943508222875e-38 を追加することで失われ、後者、つまり 0x80800000 になります。これは、>>1 を加えた後、再び 3.0 になります。なぜそうならないのかわかりませんが、おそらくここで間違いを犯したためです。

残っているのは、信頼できる結果を期待して、フロートでビットシフトを行うことができないということです。

ARM でそれらを整数またはその他の固定小数点に変換し、そのまま回線経由で送信することを検討します。

于 2012-05-30T15:58:51.290 に答える
1

固定小数点はそのようには機能しません。あなたがしたいことは次のようなものです:

void main(){
    // initing 8bit fixed point numbers
    unsigned int x = 2 << 8;
    unsigned int y = 3 << 8;
    unsigned int z = 1 << 8;

    // adding two numbers
    unsigned int a = x + y;

    // multiplying two numbers with fixed point adjustment
    unsigned int b = (x * y) >> 8;

    // use numbers
    printf("%d %d\n", a >> 8, b >> 8);
  }
于 2012-05-30T15:44:19.097 に答える