Я пытаюсь реализовать простой тип с плавающей точкой с половинной точностью, целиком предназначенный для хранения (без арифметики, конвертирует в двойную неявно), но я получаю странное поведение. Я получаю совершенно неправильные значения для Half
между -0,5 и 0,5. Также я получаю неприятное «смещение» для значений, например 0.8 декодируется как 0.7998.Внедрение числа с плавающей запятой с половиной точности в C++
Я очень новичок в C++, поэтому мне было бы здорово, если бы вы могли указать на мою ошибку и помочь мне с улучшением точности. Мне также интересно, насколько переносимым является это решение. Благодаря!
Вот результат - двойное значение и фактическое значение декодируется из половины:
-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;
}
}
Там есть аналогичный вопрос здесь: http://stackoverflow.com/questions/3316130/changing-float-type-to-short-but-with-same-behaviour-as-float- type-variable –
Попробуйте преобразовать 0,8 в двоичный код и использовать только количество бит, которое вы имеете для хранения. чем пытаться преобразовать его обратно в десятичное и увидеть результат. Если у вас есть только 2 десятичных бита, вы можете использовать только 1/2 и 1/4, тем самым пытаясь сохранить, например. .8 будет отображаться как 1/2 + 1/4 = .75, это ближе к .8, чем к 1, но все же у вас есть то, что вы называете 'offset' – ted