web-dev-qa-db-ja.com

浮動小数点数でビット演算を実行する方法

私はこれを試しました:

float a = 1.4123;
a = a & (1 << 3);

&のオペランドをfloat型にすることはできないというコンパイラエラーが発生します。

私がする時:

float a = 1.4123;
a = (int)a & (1 << 3);

プログラムを実行します。唯一のことは、ビット単位の演算が、四捨五入後に取得された数値の整数表現で行われることです。

以下も許可されていません。

float a = 1.4123;
a = (void*)a & (1 << 3);

intvoid*にキャストできるが、floatにキャストできない理由がわかりません。

スタックオーバーフローの質問遺伝的アルゴリズムを使用して線形方程式を解く方法?で説明されている問題を解決するためにこれを行っています。

44
Rohit Banga

言語レベルでは、「浮動小数点数のビット単位の操作」などはありません。 C/C++のビット演算は、数値の値表現で機能します。また、浮動小数点数の値表現は、C/C++では定義されていません。浮動小数点数には値表現のレベルのビットがありません。そのため、ビット単位の演算を浮動小数点数に適用することはできません。

できることは、浮動小数点数が占める生メモリのビット内容を分析することだけです。そのためには、以下に示すようにユニオンを使用するか、(同様に、C++のみで)浮動小数点オブジェクトをunsigned charオブジェクトの配列として再解釈する必要があります。

float f = 5;
unsigned char *c = reinterpret_cast<unsigned char *>(&f);
// inspect memory from c[0] to c[sizeof f - 1]

また、他の回答が示唆するように、floatオブジェクトをintオブジェクトとして再解釈しようとしないでください。それはあまり意味がなく、違法であり、最適化の厳密なエイリアス規則に従うコンパイラで動作することは保証されていません。 C++でメモリコンテンツを検査する唯一の正当な方法は、[signed/unsigned] charの配列として再解釈することです。

また、システム上の浮動小数点表現がIEEE754であることは技術的に保証されていないことに注意してください(実際には、明示的に許可しない限り、-0.0、±∞、およびNaNに関してのみ許可されます)。

71
AnT

浮動小数点表現のビットを変更しようとしている場合、次のようなことができます。

union fp_bit_twiddler {
    float f;
    int i;
} q;
q.f = a;
q.i &= (1 << 3);
a = q.f;

AndreyTが指摘しているように、このような共用体にアクセスすると未定義の動作が呼び出され、コンパイラーが武器を増やして絞め殺す可能性があります。代わりに彼が提案することをしてください。

18
mob
float a = 1.4123;
unsigned int* inta = reinterpret_cast<unsigned int*>(&a);
*inta = *inta & (1 << 3);
8
Chap

以下をご覧ください。高速逆平方根に触発された:

#include <iostream>
using namespace std;

int main()
{
    float x, td = 2.0;
    int ti = *(int*) &td;
    cout << "Cast int: " << ti << endl;
    ti = ti>>4;
    x = *(float*) &ti;
    cout << "Recast float: " << x << endl;
    return 0; 
}
6
Justin

@mobrule:

より良い:

#include <stdint.h>
...
union fp_bit_twiddler {
    float f;
    uint32_t u;
} q;

/* mutatis mutandis ... */

これらの値 intの場合は大丈夫ですが、一般に、算術シフトの影響を避けるためにビットシフトには符号なしintを使用する必要があります。また、uint32_tは、intが32ビットではないシステムでも機能します。

4
Tim Schaeffer

Pythonでの実装浮動小数点ビット演算(Pythonレシピ)浮動小数点ビット演算浮動小数点数はほとんどのアーキテクチャで符号付きゼロであるため、負の表現には one'sの補数 を使用します。数字(まあ、実際にはそうするふりをして、いくつかのトリックを使用して外観を実現しています)。

C++で動作するように適合させることができると確信していますが、指数を等化するときに右シフトがオーバーフローしないように注意する必要があります。

2
Pyry Pakkanen

フロートはハードウェア固有のものであるため、ビットごとの演算子はフロートで使用すべきではありません。 「私のマシンでうまくいった」というリスクを冒したいプロジェクト/ジョブはどれですか?代わりに、C++の場合、floatの「オブジェクト」ラッパーでストリーム演算子をオーバーロードすることで、ビットシフト演算子の同様の「感触」を得ることができます。

// Simple object wrapper for float type as templates want classes.
class Float
{
float m_f;
public:
    Float( const float & f )
    : m_f( f )
    {
    }

    operator float() const
    {
        return m_f;
    }
};

float operator>>( const Float & left, int right )
{
    float temp = left;
    for( right; right > 0; --right )
    {
        temp /= 2.0f;
    }
    return temp;
}

float operator<<( const Float & left, int right )
{
    float temp = left;
    for( right; right > 0; --right )
    {
        temp *= 2.0f;
    }
    return temp;
}

int main( int argc, char ** argv )
{
    int a1 = 40 >> 2; 
    int a2 = 40 << 2;
    int a3 = 13 >> 2;
    int a4 = 256 >> 2;
    int a5 = 255 >> 2;

    float f1 = Float( 40.0f ) >> 2; 
    float f2 = Float( 40.0f ) << 2;
    float f3 = Float( 13.0f ) >> 2;
    float f4 = Float( 256.0f ) >> 2;
    float f5 = Float( 255.0f ) >> 2;
}

残りがあり、必要な実装に基づいて破棄できます。

1
Kit10
float a = 1.4123;
int *b = (int *)&a;
*b = *b & (1 << 3);
// a is now the IEEE floating-point value caused by the manipulation of *b
// equals 1.121039e-44 (tested on my system)

これは、aと同じレジスタ内のビットのビューのみを作成することを除いて、ジャスティンの応答に似ています。したがって、*baの値はそれに応じて変化します。

1
Patrick Roberts

FWIW、浮動小数点でのビット単位操作の実際の使用例があります(最近私はそれに遭遇しました)-古いバージョンのGLSLのみをサポートするGPU用に作成されたシェーダー(1.2以前はビット単位演算子をサポートしていませんでした) 、およびfloatがintに変換された場合に精度が失われる場所。

ビット単位の演算は、剰余(モジュロ)および不等式チェックを使用して、浮動小数点数に実装できます。例えば:

float A = 0.625; //value to check; ie, 160/256
float mask = 0.25; //bit to check; ie, 1/4
bool result = (mod(A, 2.0 * mask) >= mask); //non-zero if bit 0.25 is on in A

上記は、Aが[0..1)の間にあり、チェックするマスクに「ビット」が1つしかないことを前提としていますが、より複雑な場合には一般化できます。

このアイデアは is-it-possible-to-implement-bitwise-operators-using-integer-arithmetic にある情報の一部に基づいています

組み込みのmod関数さえなければ、それもかなり簡単に実装できます。例えば:

float mod(float num, float den)
{
    return num - den * floor(num / den);
}
1
djulien