2

浮動小数点数があるとします。数値の基数 2 表現ですべての 1 桁の位置を抽出したいと思います。

たとえば、10.25 = 2^-2 + 2^1 + 2^3 なので、底 2 の位置は {-2, 1, 3} です。

数値の基数 2 の累乗のリストを取得したらn、次は常に true を返す必要があります (疑似コード)。

sum = 0
for power in powers:
    sum += 2.0 ** power
return n == sum

ただし、C および C++ で float に対してビット ロジックを実行するのはやや難しく、移植性を高めるのはさらに困難です。

少数の CPU 命令を使用して、いずれかの言語でこれをどのように実装しますか?

4

2 に答える 2

4

移植性をあきらめ、IEEEfloatと 32 ビットを想定しますint

// Doesn't check for NaN or denormalized.
// Left as an exercise for the reader.
void pbits(float x)
{
    union {
        float f;
        unsigned i;
    } u;
    int sign, mantissa, exponent, i;
    u.f = x;
    sign = u.i >> 31;
    exponent = ((u.i >> 23) & 255) - 127;
    mantissa = (u.i & ((1 << 23) - 1)) | (1 << 23);
    for (i = 0; i < 24; ++i) {
        if (mantissa & (1 << (23 - i)))
            printf("2^%d\n", exponent - i);
    }
}

これにより、指定された浮動小数点数になる 2 のべき乗が出力されます。例えば、

$ ./a.out 156
2^7
2^4
2^3
2^2
$ ./a.out 0.333333333333333333333333
2^-2
2^-4
2^-6
2^-8
2^-10
2^-12
2^-14
2^-16
2^-18
2^-20
2^-22
2^-24
2^-25

1/3 がどのように切り上げられるかを確認できますが、小数点以下の桁数に関係なく常に小数点以下を切り捨てるため、直感的ではありません。

脚注:次のことは行わないでください。

float x = ...;
unsigned i = *(unsigned *) &x; // no

のトリックは、union警告を生成したり、コンパイラを混乱させたりする可能性がはるかに低くなります。

于 2012-08-03T21:50:39.357 に答える
4

浮動小数点数のエンコーディングを扱う必要はありません。C には、移植可能な方法で浮動小数点値を操作するためのルーチンが用意されています。以下の作品。

#include <math.h>
#include <stdio.h>
#include <stdlib.h>


int main(int argc, char *argv[])
{
    /*  This should be replaced with proper allocation for the floating-point
        type.
    */
    int powers[53];
    double x = atof(argv[1]);

    if (x <= 0)
    {
        fprintf(stderr, "Error, input must be positive.\n");
        return 1;
    }

    // Find value of highest bit.
    int e;
    double f = frexp(x, &e) - .5;
    powers[0] = --e;
    int p = 1;

    // Find remaining bits.
    for (; 0 != f; --e)
    {
        printf("e = %d, f = %g.\n", e, f);
        if (.5 <= f)
        {
            powers[p++] = e;
            f -= .5;
        }
        f *= 2;
    }

    // Display.
    printf("%.19g =", x);
    for (int i = 0; i < p; ++i)
        printf(" + 2**%d", powers[i]);
    printf(".\n");

    // Test.
    double y = 0;
    for (int i = 0; i < p; ++i)
        y += ldexp(1, powers[i]);

    if (x == y)
        printf("Reconstructed number equals original.\n");
    else
        printf("Reconstructed number is %.19g, but original is %.19g.\n", y, x);

    return 0;
}
于 2012-08-04T01:39:40.963 に答える