17

IEEE 754 浮動小数点数を表す 32 ビットが与えられた場合、(機械命令またはコンパイラ操作を使用して変換するのではなく) 表現に対して整数またはビット操作を使用して、どのように数値を整数に変換できますか?

次の機能がありますが、場合によっては失敗します。

入力: int x (IEEE 754 形式の 32 ビット単精度数を含む)

  if(x == 0) return x;

  unsigned int signBit = 0;
  unsigned int absX = (unsigned int)x;
  if (x < 0)
  {
      signBit = 0x80000000u;
      absX = (unsigned int)-x;
  }

  unsigned int exponent = 158;
  while ((absX & 0x80000000) == 0)
  {
      exponent--;
      absX <<= 1;
  }

  unsigned int mantissa = absX >> 8;

  unsigned int result = signBit | (exponent << 23) | (mantissa & 0x7fffff);
  printf("\nfor x: %x, result: %x",x,result);
  return result;
4

7 に答える 7

23

C には、このタイプのデータ ビューを処理するための「共用体」があります。

typedef union {
  int i;
  float f;
 } u;
 u u1;
 u1.f = 45.6789;
 /* now u1.i refers to the int version of the float */
 printf("%d",u1.i);
于 2013-11-22T18:23:25.620 に答える
16

&xx のアドレスを与えるため、float*型があります。

(int*)&xintそのポインターをポインターへの、つまりint*モノへのポインターにキャストします。

*(int*)&xそのポインターをint値に逆参照します。異なるサイズのマシンではint、あなたが信じていることはしません。float

また、エンディアンの問題が発生する可能性があります。

このソリューションは、高速逆平方根アルゴリズムで使用されました。

于 2012-09-09T21:01:27.780 に答える
7

(誰かがこの回答、特に境界ケースと負の値の丸めを再確認する必要があります。また、最も近い値への丸めについて書きました。C の変換を再現するには、これをゼロ方向への丸めに変更する必要があります。)

基本的に、プロセスは次のとおりです。

32 ビットを 1 つの符号ビット ( s )、8 つの指数ビット ( e )、および 23 の仮数ビット ( f ) に分割します。これらを 2 の補数の整数として扱います。

eが 255 の場合、浮動小数点オブジェクトは無限大 ( fがゼロの場合) または NaN (それ以外の場合) のいずれかです。この場合、変換は実行できず、エラーが報告されます。

それ以外の場合、eがゼロでない場合は、2 24fに追加します。( eが 0 でない場合、仮数の前には暗黙的に 1 ビットがあります。2 24を追加すると、そのビットがfで明示的になります。)

eから 127 を引きます。(これにより、指数がバイアスされた/エンコードされた形式から実際の指数に変換されます。任意の値への一般的な変換を行う場合、eがゼロの場合の特殊なケースを処理する必要があります。127 ではなく 126 を減算します。整数の結果に変換するだけなので、これらの小さな入力数値に対して整数の結果がゼロである限り、このケースは無視できます。)

sが 0 (符号は正) でeが 31 以上の場合、値は符号付き 32 ビット整数 (2 31 以上) をオーバーフローします。変換を実行できず、エラーが報告されます。

sが 1 (符号は負) でeが 31 より大きい場合、値は符号付き 32 ビット整数 (-2 32以下) をオーバーフローします。sが 1、eが 32、fが 2 24より大きい場合(元の仮数ビットのいずれかが設定されている場合)、値は符号付き 32 ビット整数をオーバーフローします (-2 31未満です。元のfゼロだった場合、正確に -2 31になり、オーバーフローしません)。これらのいずれの場合も、変換は実行できず、エラーが報告されます。

これで、オーバーフローしない値の se、およびfが得られたので、最終的な値を準備できます。

sが 1の場合、 f-fに設定します。

指数値は 1 (含む) と 2 (含まない) の間の仮数ですが、仮数は 2 24のビットから始まります。そのため、それに合わせて調整する必要があります。eが 24 の場合、仮数は正しく、完了です。したがって、結果としてfを返します。eが 24 より大きいか 24 より小さい場合は、仮数を適切にシフトする必要があります。また、 fを右にシフトする場合は、最も近い整数に丸められた結果を得るために、丸める必要がある場合があります。

eが 24 より大きい場合、fe -24 ビット左にシフトします。結果としてfを返します。

eが -1 より小さい場合、浮動小数点数は -½ から ½ の間 (排他的) です。結果として 0 を返します。

それ以外の場合は、 fを右に 24 -eビットシフトします。ただし、最初に丸めに必要なビットを保存します。f を符号なし 32 ビット整数にキャストし、それを 32-(24- e ) ビット左にシフトした結果をrに設定します (同等に、8+ eビットだけ左にシフトします)。これは、 f (以下)からシフトアウトされるビットを取得し、32 ビットでそれらを「左に調整」するため、開始位置が固定されます。

f右に 24 -eビットシフトします。

rが 2 31未満の場合、何もしません (これは切り捨てです。シフトが切り捨てられたビットです)。rが 2 31より大きい場合、 fに 1 を追加します (これは切り上げです)。rが 2 31に等しい場合、 fの下位ビットをfに追加します。( fが奇数の場合、 f に 1 を加算します。2 つの等しく近い値のうち、これは偶数の値に丸められます。) fを返します。

于 2012-09-09T23:49:34.390 に答える
5
float x = 43.133;
int y;

assert (sizeof x == sizeof y);
memcpy (&y, &x, sizeof x);
...
于 2012-09-09T21:28:52.743 に答える
1

参照を使用して float をキャストできます。このようなキャストは、コードを生成するべきではありません。

C++

float f = 1.0f;
int i = (int &)f;
printf("Float %f is 0x%08x\n", f, i);

出力:

Float 1.000000 is 0x3f800000

C++ スタイルのキャストが必要な場合は、次のように reinterpret_cast を使用します。

int i = reinterpret_cast<int &>(f);

式では機能しません。変数に格納する必要があります。

    int i_times_two;
    float f_times_two = f * 2.0f;
    i_times_two = (int &)f_times_two;

    i_times_two = (int &)(f * 2.0f);
main.cpp:25:13: error: C-style cast from rvalue to reference type 'int &'
于 2015-08-11T20:41:24.550 に答える
0

この方法では、浮動小数点数を「整数」(signed intまたはint) に (意味のある) 変換することはできません。

整数型になる可能性がありますが、実際には IEEE754 のエンコーディング空間への単なるインデックスであり、それ自体は意味のある値ではありません。

unsignedint はビット パターンと整数値の両方の目的を果たしていると主張するかもしれませんが、そうでintはありません。


また、signed int のビット操作に関するプラットフォームの問題もあります。

于 2012-09-09T21:00:03.220 に答える