但是,只需半小时就能完成并实现以下一组功能,这些功能可以充分满足我的需求。
基本思想是分数和非分数部分都是16位整数,因此没有位操作。 非分式部分的范围为< -32767,32767>。分数部分< -0.9999,+ 0.9999> - 它给我们4位数的精度(足以满足我的浮点需求 - 虽然浪费)。
在我看来,这样可以用来制作一个更快,更小 - 只是2字节 - 大 - 替代版本的浮点数,范围<-99,+ 99&gt;和&lt; -0.9,+ 0.9&gt;
这里的问题是,除了IEEE之外的其他技术是否可以使用定点功能实现基本浮点功能(+ - * /)? 稍后,我将需要一些基本的三角函数,但网上有很多资源。
您建议使用定点在C中实现浮点而不依赖于其他库/代码有哪些改进/方法?
也许可以使用不同的方法同时对压裂和非压裂部件进行操作?
这是代码(仅使用计算器进行测试),请忽略C ++ - 在函数中间的声明和初始化(稍后我会将其重新格式化为C风格):
inline int Pad (int f) // Pad the fractional part to 4 digits
{
if (f < 10) return f*1000;
else if (f < 100) return f*100;
else if (f < 1000) return f*10;
else return f;
}
// We assume fractional parts are padded to full 4 digits
inline void Add (int & b1, int & f1, int b2, int f2)
{
b1 += b2;
f1 +=f2;
if (f1 > 9999) { b1++; f1 -=10000; }
else if (f1 < -9999) { b1--; f1 +=10000; }
f1 = Pad (f1);
}
inline void Sub (int & b1, int & f1, int b2, int f2)
{
// 123.1652 - 18.9752 = 104.1900
b1 -= b2; // 105
f1 -= f2; // -8100
if (f1 < 0) { b1--; f1 +=10000; }
f1 = Pad (f1);
}
// ToDo: Implement a multiplication by float
inline void Mul (int & b1, int & f1, int num)
{
// 123.9876 * 251 = 31120.8876
b1 *=num; // 30873
long q = f1*num; //2478876
int add = q/10000; // 247
b1+=add; // 31120
f1 = q-(add*10000);//8876
f1 = Pad (f1);
}
// ToDo: Implement a division by float
inline void Div (int & b1, int & f1, int num)
{
// 123.9876 / 25 = 4.959504
int b2 = b1/num; // 4
long q = b1 - (b2*num); // 23
f1 = ((q*10000) + f1) / num; // (23000+9876) / 25 = 9595
b1 = b2;
f1 = Pad (f1);
}
答案 0 :(得分:0)
您正在考虑使用简单的定点实现的错误基础。如果对小数位使用位,则会容易得多。例如使用16位作为整数部分,16位作为小数部分(范围-32767/32767,精度为1/2 ^ 16,这比你的精度高很多)。
最好的部分是加法和减法很简单(只需将两个部分加在一起)。乘法有点棘手:您必须注意溢出,因此有助于在64位中进行乘法运算。您还必须在乘法后移位结果(无论多少位都在十进制中)。
typedef int fixed16;
fixed16 mult_f(fixed16 op1, fixed16 op2)
{
/* you may need to do something tricky with upper and lower if you don't
* have native 64 bit but the compiler might do it for us if we are lucky
*/
uint64_t tmp;
tmp = (op1 * op2) >> 16;
/* add in error handling for overflow if you wish - this just wraps */
return tmp & 0xFFFFFFFF;
}
分部是类似的。
有人可能已经实现了几乎完全符合您的需求(或者可以被黑客攻击以使其正常工作),这被称为libfixmath
答案 1 :(得分:0)
如果您决定使用定点,则整数(即int和小数部分)应该在同一个基数中。如上所述,对于int部分使用二进制和对小数部分使用十进制不是非常优化,并且会减慢计算速度。使用二进制定点,您只需要在执行操作后移动适当的数量,不需要像您的想法那样进行长时间的调整。如果你想使用Q16.16那么libfixmath就像上面提到的dave是个不错的选择。如果您想要不同的精度或浮点位置,例如Q14.18,Q19.13,那么请编写自己的库。
如果你想要更大的范围,那么浮点可能是更好的选择。根据您自己的要求编写库,选择最容易实现且速度最快的格式,除非您打算与其他设备交换数据,否则无需遵循IEEE 754规范。例如,e.s.m的格式,其中7个指数位后跟符号位,然后是24位尾数。指数不需要有偏差,因此要使基数仅需要算术移位25,符号位也将被扩展。但是如果偏移比减法慢,则过量-n更好。