0

完全にストレージの目的で単純な半精度浮動小数点型を実装しようとしています (算術なし、暗黙的に倍精度に変換されます) が、奇妙な動作が発生します。Half-0.5 から 0.5 の間で完全に間違った値を取得します。また、値の厄介な「オフセット」を取得します。たとえば、0.8 は 0.7998 としてデコードされます。

私はC++に非常に慣れていないので、私の間違いを指摘して、精度を少し改善するのを手伝っていただければ幸いです. また、このソリューションの移植性にも興味があります。ありがとう!

ここに出力があります - double 値と半分からの実際のデコードされた値:

-1 -1
-0.9 -0.899902
-0.8 -0.799805
-0.7 -0.699951
-0.6 -0.599854
-0.5 -0.5
-0.4 -26208
-0.3 -19656
-0.2 -13104
-0.1 -6552
-1.38778e-16 -2560
0.1 6552
0.2 13104
0.3 19656
0.4 26208
0.5 32760
0.6 0.599854
0.7 0.699951
0.8 0.799805
0.9 0.899902

これまでのコードは次のとおりです。

#include <stdint.h>
#include <cmath>
#include <iostream>

using namespace std;

#define EXP 4
#define SIG 11

double normalizeS(uint v) {
    return (0.5f * v / 2048 + 0.5f);
}

uint normalizeP(double v) {
    return (uint)(2048 * (v - 0.5f) / 0.5f);
}

class Half {

    struct Data {
        unsigned short sign : 1;
        unsigned short exponent : EXP;
        unsigned short significant : SIG;
    };

public:
    Half() {}
    Half(double d) { loadFromFloat(d); }

    Half & operator = (long double d) {
        loadFromFloat(d);
        return *this;
    }

    operator double() {
        long double sig = normalizeS(_d.significant);
        if (_d.sign) sig = -sig;
        return ldexp(sig, _d.exponent /*+ 1*/);
    }

private:
    void loadFromFloat(long double f) {
        long double v;
        int exp;
        v = frexp(f, &exp);
        v < 0 ? _d.sign = 1 : _d.sign = 0;
        _d.exponent = exp/* - 1*/;
        _d.significant = normalizeP(fabs(v));
    }

    Data _d;
};

int main() {

        Half a[255];

        double d = -1;

        for (int i = 0; i < 20; ++i) {
            a[i] = d;
            cout << d << " " << a[i] << endl;
            d += 0.1;
        }
}
4

2 に答える 2

0

私は、必要な範囲のすべての値を表すことができる、非常に単純な (本当に素朴な) ソリューションになりました: 0 - 64 の精度で 0.001。

doubleアイデアはストレージに使用することなので、解像度を損なうことなく変換できるため、実際にはこれの方が優れています。また、高速です。実際には、より良い最小ステップを持つという名目でいくらかの解像度 (16 ビット未満) を失うため、近似なしで任意の入力値を表すことができます。したがって、この場合、LESS は MORE です。浮動コンポーネントに完全な 2^10 解像度を使用すると、10 進数値を正確に表すことができない奇妙なステップが発生します。

class Half {
public:
    Half() {}
    Half(const double d) { load(d); }
    operator double() const { return _d.i + ((double)_d.f / 1000); }
private:
    struct Data {
        unsigned short i : 6;
        unsigned short f : 10;
    };
    void load(const double d) {
        int i = d;
        _d.i = i;
        _d.f = round((d - i) * 1000);
    }
    Data _d;
};
于 2013-08-09T17:28:07.717 に答える