浮点数有2个问题,精度问题和数据不一致问题.
- 精度问题就是由于存储空间有限,二进制里的无限循环存不下而导致的,会干扰判断.
- 数据不一致指浮点数存成二进制数据后,在不同的端可能解析出来的数值有差异.这就是为什么帧同步的协议,都使用自定义整数存储浮点数数据.
基于上述2点,我打算自己封装个以整数存储的浮点数.统一精度,解决上述2个问题.唯二代价就是取值范围缩少和运算时候多了一步个乘/除运算.
原理很简单,假设精度是0.0001(即万分比),那么转换成自定义浮点数的时候,数值要乘以10000
首先是定义个全局的精度. 之前我写成了float S_accuracy,这样是不对的!!!
static int S_accuracy = 10000;//默认精度是0.0001
先定义几个宏,是不是没有除法?因为要判断被除数为0的异常
// == != < <= > >=
#define OPER_FUN_BOOL(Symbol,Type) inline bool operator Symbol(const Type& mdt){\
return data Symbol mdt.data;\
}\
// + -
#define OPER_FUN_MD(Symbol,Type) inline Type operator Symbol(const Type& mdt){\
Type res;\
res.data = data Symbol mdt.data;\
return res;\
}\
// = += -=
#define OPER_FUN_MDREF(Symbol,Type) inline Type& operator Symbol(const Type& mdt){\
data Symbol mdt.data; \
return *this;\
}\
//
#define OPER_FUN_OTHER(Symbol,Type1,Type2) inline Type1 operator Symbol(const Type2& rdata) {\
Type1 res;\
res.data = data Symbol (rdata * S_accuracy);\
return res;\
}\
//
#define MDF_MDD(Symbol,Type) static inline MDdouble operator Symbol(MDfloat left, const Type& rdata) {\
MDdouble res(left);\
res Symbol= rdata;\
return res;\
}\
贴整个mdfloat源码出来
struct MDdouble;
struct MDfloat {
protected:
int data;
public:
MDfloat(double d) {
data = d * S_accuracy;
}
MDfloat(float d) {
data = d * S_accuracy;
}
MDfloat(int d = 0) {
data = d * S_accuracy;
}
MDfloat(char d) {
data = d * S_accuracy;
}
MDfloat(long long d) {
data = d * S_accuracy;
}
MDfloat(const MDdouble& d);
OPER_FUN_BOOL(==,MDfloat)
OPER_FUN_BOOL(!=, MDfloat)
OPER_FUN_BOOL(<,MDfloat)
OPER_FUN_BOOL(<=, MDfloat)
OPER_FUN_BOOL(>, MDfloat)
OPER_FUN_BOOL(>=, MDfloat)
OPER_FUN_OTHER(+, MDfloat, int)
OPER_FUN_OTHER(-, MDfloat, int)
inline MDfloat operator *(const int& rdata) {
MDfloat res;
res.data = data * rdata;
return res;
}
inline MDfloat operator /(const int& rdata) {
if (rdata == 0) {
throw "MDfloat rdata div 0";
}
MDfloat res;
res.data = data / rdata;
return res;
}
OPER_FUN_MD(+, MDfloat);
OPER_FUN_MD(-, MDfloat);
inline MDfloat operator *(const MDfloat& mdt) {
MDfloat res;
res.data = data * mdt.data / S_accuracy;
return res;
}
inline MDfloat operator /(const MDfloat& mdt) {
if (mdt.data == 0) {
throw "MDfloat div 0";
}
return MDfloat(data / mdt.data);
}
OPER_FUN_MDREF(=, MDfloat)
OPER_FUN_MDREF(+=, MDfloat)
OPER_FUN_MDREF(-=, MDfloat)
inline MDfloat& operator *=(const MDfloat& mdt) {
data = data * mdt.data / S_accuracy;
return *this;
}
inline MDfloat& operator /=(const MDfloat& mdt) {
if (mdt.data == 0) {
throw "MDfloat div 0";
}
data = data / mdt.data * S_accuracy;
return *this;
}
inline operator float() {
return data / (float)S_accuracy;
}
inline int getdata() const {
return data;
}
};
以下代码是为了非mdfloat数值和mdfloat相运算
OPER_FUN_OTHER(+, MDfloat, int)
OPER_FUN_OTHER(-, MDfloat, int)
inline MDfloat operator *(const int& rdata) {
MDfloat res;
res.data = data * rdata;
return res;
}
inline MDfloat operator /(const int& rdata) {
if (rdata == 0) {
throw "MDfloat rdata div 0";
}
MDfloat res;
res.data = data / rdata;
return res;
}
以下代码是为了得到真实的float值
inline operator float() {
return data / (float)S_accuracy;
}
//MDfloat遇到long long,要转成MDdouble处理
MDF_MDD(+, long long);
MDF_MDD(-, long long);
MDF_MDD(*, long long);
MDF_MDD(/, long long);
就这样实现了,也贴一下测试代码
void OnFunc_MDfloat1() {
MyDog::S_accuracy = 100;
MDfloat f = 0.01;
MDfloat f2 = 0.02;
auto f3 = f2 * f;
cout << f3 << endl;
f2 += f;
cout << f2 << endl;
}
void OnFunc_MDfloat2() {
int i = 10;
MDfloat f2 = 0.02;
f2 += i;
cout << (float)f2 << endl;
auto f3 = f2 + i;
cout << f3 << endl;
f3 = i + f2;
cout << f3 << endl;
}
void OnFunc_MDfloat3() {
long long i = 10;
MDfloat f2 = 0.02;
cout << i * f2 << endl;//=>i*(float)f2
cout << f2 * i << endl;//=>MDfloat operator *(const int& rdata)
auto f4 = f2 * i;
f2 = f4;
cout << f2 + i + 10 << endl;
int ii = 11;
cout << ii * f2 << endl;
cout << f2 * ii << endl;
auto f3 = i + f2;
cout << f3 << endl;
f3 = f2 + ii + 10;
cout << f3 << endl;
f2 = i;
cout << f2 << endl;
}
虽然有这样的报错:
但对C++来说,可以不管的...我window和linux都运行过测试代码.