【发布时间】:2013-08-22 21:28:24
【问题描述】:
我需要能够在我的 C 开发环境下使用浮点运算(CPU:~12 MHz 摩托罗拉 68000)。标准库不存在,这意味着它是一个简单的 C 并且不 - 由于其他几个问题,它不是 gcc
我尝试编译 SoftFloat 库和另一个 68k 特定的 FP 库(此时我不知道它的名称),但是对于这个特定平台,它们的依赖关系无法解决 - 主要是由于 libc 缺陷。我花了大约 8 小时试图克服链接问题,直到我知道我无法再进一步。
但是,只花了半个小时就想出并实现以下一组函数,这些函数充分模拟了我的需要。
基本思想是小数部分和非小数部分都是16位整数,因此没有位操作。 非小数部分的范围为 [-32767, 32767],小数部分的范围为 [-0.9999, +0.9999] - 这为我们提供了 4 位精度(足以满足我的浮点需求 - 尽管很浪费)。
在我看来,这可以用来制作更快、更小(仅 2 字节大)的浮点替代版本,范围为 [-99, +99] 和 [-0.9, +0.9]
这里的问题是,除了 IEEE 之外,还有哪些其他技术可以使用定点功能来实现基本的浮点功能 (+ - * /)?
稍后,我将需要一些基本的三角函数,但是网上有很多资源。
- 由于硬件有 2 MB 的 RAM,我真的不在乎是否可以为每个软浮点节省 2 个字节(例如,通过在 int 中保留 9 位和 7 位)。因此 - 4 个字节就足够了。
- 此外,通过简要查看 68k 指令手册(以及每条指令的周期成本),我做了一些早期观察:
- 位移很慢,除非性能至关重要(这里不是这种情况),否则我更喜欢轻松调试我的软浮点库而不是 5 个周期更快的代码。此外,由于这是 C 而不是 68k ASM,因此速度显然不是关键因素。
- 8 位操作数与 16 位一样慢(在大多数情况下给或取一个周期),因此为了性能而压缩浮点数似乎没有多大意义。
对于使用定点在 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);
}
【问题讨论】:
-
您希望改进什么?如果性能不重要,您的解决方案提供的范围还可以,并且可读性是一个因素,您为什么还要寻找其他东西?你知道你需要什么范围和精度吗?如果它不是很大,为简单起见,您可以考虑使用单个 int。当您需要实际值时,将其用作常规 int 并执行 div 和 mod 100(或任何您需要的精度)。
-
嗯,这是一个非常暴力、不优雅的解决方案。由于我花了一天时间尝试链接其他库(这就是我发现无法为这个特定平台链接它们的原因)并且只花了半个小时来获得临时的软浮点支持,我愿意花一个一个小时或更长时间以获得更强大/优雅/更快的解决方案。
-
好的,但是你的目标是什么?如果您的所有目标都实现了,为什么您觉得需要编写更多代码?我同意我的解决方案不可扩展并且非常简单,因此“不优雅”。但是,如果它在可预见的将来满足您的所有目标,为什么不使用它呢?它确实有优势 - 它需要的代码少得多,并且允许您使用普通运算符而不是函数。
-
对不起,我的意思是我的解决方案非常不优雅和蛮力,因为它是我想出的第一个。因此,它一定是最糟糕的一个,并且必须有更优雅的解决方案。对我来说,这是第一次涉足嵌入式世界(来自 linux/win 商业环境),但是成千上万的程序员已经在嵌入式 env 中工作了几十年,所以当他们无法使用 switch 时,他们肯定以某种方式接近它-msoft-float(或链接 SoftFloat 库)。你能更具体地说明你的方法吗?你如何处理溢出/下溢?
-
这没什么意义,摩托罗拉在 1982 年,也就是 31 年前生产了 12.5 MHz 版本的 68000。它于 1996 年停产。你到底在编程什么?这是真实的事情还是这是家庭作业?
标签: c floating-point fixed-point 68000