55

私はこれを試しました:

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);

なぜキャストできるのかわかりませんintが、キャストできvoid*ませんfloat

Stack Overflowの質問で説明されている問題を解決するためにこれを行っています。遺伝的アルゴリズムを使用して線形方程式を解く方法は?

4

10 に答える 10

86

言語レベルでは、「浮動小数点数のビット演算」などはありません。C / C ++のビット演算は、数値の値表現で機能します。また、浮動小数点数の値表現はC / C ++では定義されていません(符号なし整数は、シフトが2の補数で格納されている場合に定義されるため、この点では例外です)。浮動小数点数には、値表現のレベルのビットがありません。そのため、浮動小数点数にビット単位の演算を適用することはできません。

実行できるのは、浮動小数点数が占めるrawメモリのビット内容を分析することだけです。そのためには、以下に提案するようにユニオンを使用するか、(同等に、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、±infinity、およびNaNに関してのみ保証されます)。

于 2009-11-12T17:25:08.323 に答える
19

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

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

AndreyTが指摘しているように、このようなユニオンにアクセスすると、未定義の動作が発生し、コンパイラーが腕を伸ばして首を絞める可能性があります。代わりに彼が提案することをしてください。

于 2009-11-12T16:42:33.933 に答える
8
float a = 1.4123;
unsigned int* inta = reinterpret_cast<unsigned int*>(&a);
*inta = *inta & (1 << 3);
于 2009-11-12T16:39:44.207 に答える
7

厳密なエイリアシングルールを回避し、次を使用して、未定義の動作なしで(実装で定義されている場合はほとんどの場合)float型のパンニングとしてビット単位の操作を実行できます。uint32_tmemcpy()

float a = 1.4123f;
uint32_t b;

std::memcpy(&b, &a, 4);
// perform bitwise operation
b &= 1u << 3;
std::memcpy(&a, &b, 4);
于 2019-09-20T16:31:26.857 に答える
5

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

#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; 
}
于 2009-11-13T11:02:21.670 に答える
2

@mobrule:

より良い:

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

/* mutatis mutandis ... */

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

于 2009-11-12T16:56:13.300 に答える
2

FWIW、浮動小数点でのビット単位の演算の実際の使用例があります(最近遭遇したばかりです)-古いバージョンのGLSLのみをサポートするOpenGL実装用に記述されたシェーダー(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);
}
于 2017-04-02T01:55:36.603 に答える
1

浮動小数点ビット演算の浮動小数点ビット演算(Pythonレシピ)でのPython実装は、小数点から左および右に無限に伸びる数値を2進数で表すことによって機能します。浮動小数点数はほとんどのアーキテクチャで符号付きのゼロを持っているため、負の数を表すために1の補数を使用します(実際には、そうするふりをして、いくつかのトリックを使用して外観を実現します)。

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

于 2011-11-28T23:52:15.380 に答える
1

フロートはハードウェア固有であるため、使用しているハードウェアの類似性に関係なく、ビット演算子はフロートでは使用しないでください。「私のマシンでうまく機能した」というリスクを冒したいプロジェクト/ジョブはどれですか?代わりに、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;
}

残りは、希望する実装に基づいて破棄できます。

于 2012-02-08T11:53:14.070 に答える
0

ポインタを使用すると、実際のデータを変更せずにバイトを再解釈できます。次に、シフト(または/および他のビット演算子)を適用し、バイトを再解釈します。

#include <stdint.h>

float shiftLeftFloat(float val, int shiftCount) {
    uint32_t valAsInt = *((uint32_t *) &val);
    valAsInt <<= shiftCount;
    val = *((float *) &valAsInt);
    return val;
}          

gcc 11.2(およびフラグ-O3)を使用するx86-64の場合、これは次のようにコンパイルされます。

movd    eax, xmm0 // copy `val` to eax register
mov     ecx, edi  // copy `shiftCount` to ecx register
sal     eax, cl   // shift eax by value of cl (= the lowest 8 bits of ecx)
movd    xmm0, eax // Move result (=eax) to "return" register (=xmm0)
ret

注:の下位8ビットのみshiftCountが使用されます。したがって、入力値は常にとして処理されshiftCount % 32ます。

salを意味するshift arithmetic left

于 2022-01-13T19:23:42.503 に答える