2

我已经提炼出一个方程式:

speed = ( ( rear_wheel_speed_a + front_wheel_speed_a ) << 10 ) +
        ( ( rear_wheel_speed_b + front_wheel_speed_b ) << 2 );

但由于某种原因,我得到了意想不到的结果,所以我一定做错了什么。这开始是这样的:

speed = ((((rear_wheel_speed_a * 256 + rear_wheel_speed_b) / 16) +
        ((front_wheel_speed_a * 256 + front_wheel_speed_b) / 16)) / 2) * 128;

那是完全不简化的版本。它们不是数学上的等价物吗?

所有值都是带符号的 16 位整数。一个示例数据集是:

rear_wheel_speed_a = 0x03;
rear_wheel_speed_b = 0x6F; //<-- I originally swapped
front_wheel_speed_a = 0x02; //<-- these two values. Sorry!
front_wheel_speed_b = 0xE2;

这归结为 6468 的答案。但在第一个等式中,我的应用程序表现得好像它至少小了 3% 或大了 3%。我这样说是因为这是一个嵌入式应用程序,除了测试它是否在某个“正常”范围内之外,我无法确认计算结果。当我使用第二个方程时,它属于参数,但使用我的“简化”(位移)方程时,它没有,所以我认为我必须错误地进行移位(或者我简化错误但我三重检查了它)。

任何见解表示赞赏,谢谢。

4

4 回答 4

12

问题是你正在溢出。虽然您转换的方程式在数学上是正确的,但您的一些中间值高于您存储它们的有符号 16 位整数。

具体来说,有问题的部分是

( rear_wheel_speed_a + front_wheel_speed_a ) << 10

使用您的示例输入,结果值为 0x1C800 - 甚至比无符号 16 位整数还要大!

原始方程似乎已经考虑到了这一点。有些值在降档时会稍微失去精度,但这比整数溢出要好。所以我推荐使用原始方程,但是你可以用移位来代替乘除,当然:

((((rear_wheel_speed_a << 8) + rear_wheel_speed_b) >> 4) + (((front_wheel_speed_a << 8) + front_wheel_speed_b) >> 4)) << 6;

另一个注意事项:您的输入 front_wheel_speed_b 已经溢出,除非它应该是负数。

于 2009-09-08T07:46:50.830 回答
4

从第二个公式中,我假设您将 2 个 16 位值分为它们的 8 位部分 a 和 b:

rear_wheel_speed = 0x0302
front_wheel_speed = 0x6fe2

并且您使用的公式可以简化为 speed= (front_speed+rear_speed)*4

从您的值来看,0x6fe2*4 刚好适合 16 位,因此可以在 16 位算术中评估该值。但是这些值看起来它们的部分排列错误,我感觉实际值是 0x036f 和 0x02e2(或 0x03ea 和 0x026f) - 这些值彼此接近,正如两个轮子的速度所预期的那样。

此外,您的公式似乎更好,因为它不会导致除法运算的精度损失。但请记住,如果您使用的是一个好的编译器(对于嵌入式应用程序并不总是如此),它通常会尽可能将除法/乘法转换为移位本身

于 2009-09-08T08:21:29.693 回答
0

您想要的是后轮速度和前轮速度的平均值,按比例缩放以适合 16 位。由于它们是 16 位值,因此总和为 17 位,因此您必须移动结果以避免溢出。

您的初始公式采用 12 位 (xxx/16) 上的每个速度,然后是值的平均值,再次在 12 位上,然后乘以 128。这将需要 19 位:您的初始公式将溢出更大的值。

为了在没有溢出的情况下获得 16 位的平均值,我建议如下(假设值是正的,如您在评论中所说):

rear_wheel_speed_h = (rear_wheel_speed_a << 7) | (rear_wheel_speed_b >> 1)
front_wheel_speed_h = (front_wheel_speed_a << 7) | (front_wheel_speed_b >> 1)
speed = rear_wheel_speed_h + front_wheel_speed_h

这将给出 16 位的结果而不会溢出。每个 xxx_wheel_speed_h 为 15 位。

于 2009-09-08T14:42:16.260 回答
0

在原始表达式中,除法运算符正在丢弃低位,但显然您的替代品不会在任何地方丢弃任何低位,因此仅此一项就意味着它们不能等价!

" rear_wheel_speed_b) / 16)" 在对其进行任何操作之前丢弃后轮速度的低 4 位,并且 " front_wheel_speed_b) / 16)" 丢弃前轮速度的低 4 位。然后“ / 2)”运算符丢弃和的低位。

如果您在表达式中添加一些内容以将这些相同的位清零,则只能获得完全相同的结果:

speed = ((((rear_wheel_speed_a * 256 + rear_wheel_speed_b) / 16) +
        ((front_wheel_speed_a * 256 + front_wheel_speed_b) / 16)) / 2) * 128;

变成

speed = ( ( rear_wheel_speed_a + front_wheel_speed_a ) << 10 ) +
        ( ( ( ( rear_wheel_speed_b & ~0x0F ) + ( front_wheel_speed_b & ~0x0F ) ) & ~1) << 2 );

换句话说,
是的((((x * 256) / 16) / 2) * 128)== ((((x << 8) >> 4) >> 1) << 7)
是的((((x << 8) >> 4) >> 1) << 7)== (x << 10)
是的(((y / 16) / 2 ) * 128 )== (( y >> 5 ) << 7)
不是 (( y >> 5 ) << 7)!= (y << 2)
没有 (((a + b) >> 1) << 7) = (((a >> 1) << 7) + (((b >> 1) << 7)

于 2013-04-06T17:53:20.040 回答