复杂表达式中的位移问题

发布于 2024-08-04 07:35:46 字数 879 浏览 4 评论 0原文

我将一个方程简化为:

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%。我这样说是因为这是一个嵌入式应用程序,除了测试它是否在一定的“正常”范围内之外,我无法确认计算结果。当我使用第二个方程时,它落在参数范围内,但使用我的“简化”(位移位)方程则不然,所以我认为我一定是错误地进行了移位(或者我简化了错误,但我三次检查了它)。

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

I've distilled an equation down to this:

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

but for some reason I'm getting unexpected results so I must be doing something wrong. This started out like this:

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

That is the completely unsimplified version that does work. Are they not mathematically equivalents?

all values are signed 16 bit integers. An example data set is:

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;

That boils down to an answer of 6468. But in the first equation, my application behaves as though it is at least 3% smaller or larger. I say it like that because this is an embedded application where I have no way of confirming the outcome of the calculations other than to test if it is within a certain range of "normal". When I use the 2nd equation it falls within the parameters but with my "simplified" (bit shifted) equation it does not so I think I must be doing the shifts incorrectly (or I simplified wrong but I triple checked it).

Any insight is appreciated, thank you.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

旧情勿念 2024-08-11 07:35:46

问题是你遇到了溢出。虽然您转换的方程在数学上是正确的,但一些临时值高于您存储它们的有符号 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 已经溢出,除非它应该是负数。

The problem is that you're getting an overflow. While the equation you've transformed is mathematically correct, some of your interim values are higher than the signed 16-bit ints you're storing them in.

To be specific, the problematic part is

( rear_wheel_speed_a + front_wheel_speed_a ) << 10

With your sample input, the resulting value is 0x1C800 - larger than even an unsigned 16-bit integer!

The original equation seems to already take this into account. Some of the values lose precision slightly when downshifting, but that's better than the integer overflowing. So I recommend using the original equation, but you can replace the multiply and divide with shifts, of course:

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

Another note: Your input front_wheel_speed_b is already overflowing, unless it is supposed to be negative.

内心旳酸楚 2024-08-11 07:35:46

根据第二个公式,我假设您操作 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) - 这些值彼此接近,正如从两个轮子的速度所预期的那样。

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

From the second formula, I assume you operating 2 16bit values separated into their 8bit part a and b:

rear_wheel_speed = 0x0302
front_wheel_speed = 0x6fe2

and the formula you using, can be simplified into speed=(front_speed+rear_speed)*4.

From your values, 0x6fe2*4 just can fit 16bit, so this value can be evaluated in 16-bit arithmetic. But the values look like their parts are arranged wrong, and I have a feeling that real values are 0x036f and 0x02e2 (or 0x03ea and 0x026f) - those values are close to each other, as should be expected from speed of two wheels.

Also it seems your formula is better, because it doesn't introduce loss of precision on divide operations. But keep in mind, that if you're using a good compiler (not always true for embedded applications) it usually converts divide/multiply to shifts itself when possible

复古式 2024-08-11 07:35:46

您想要的是后轮速度和前轮速度的平均值,缩放以适合 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 位。

What you want is the mean of rear_wheel_speed and front_wheel_speed, scaled to fit on 16 bits. Since they are 16-bit values, the sum is on 17 bits, so you have to shift the result to avoid overflow.

Your initial formula takes each speed on 12 bits (xxx/16), then the mean of the values, again on 12 bits, then multiplies by 128. This will require 19 bits: your initial formula will overflow for larger values.

To get the mean on 16 bits without overflow, I suggest the following (assuming the values are positive as you said in your comment):

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

This will give a result on 16 bits without overflow. Each xxx_wheel_speed_h is on 15 bits.

花桑 2024-08-11 07:35:46

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

rear_wheel_speed_b) / 16)”在对rear_wheel_speed进行任何操作之前丢弃rear_wheel_speed的4个低位,“front_wheel_speed_b) / 16)”丢弃rear_wheel_speed的4个低位-front_wheel_speed 的顺序位。然后“/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)!

In the original expression, the division operators are throwing away low-order bits, but clearly your substitute is not throwing away any low-order bits anywhere, so that alone means they can't be equivalent!

"rear_wheel_speed_b) / 16)" discards the 4 low-order bits of rear_wheel_speed before any operations are done on them, and "front_wheel_speed_b) / 16)" discards the 4 low-order bits of front_wheel_speed. Then the "/ 2)" operator discards the low-order bit of the sum.

You can only get exactly the same result if you put something in your expression to zero-out those same bits:

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

becomes

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

To put it another way,
yes ((((x * 256) / 16) / 2) * 128) == ((((x << 8) >> 4) >> 1) << 7),
and yes, ((((x << 8) >> 4) >> 1) << 7)== (x << 10),
and yes (((y / 16) / 2 ) * 128 ) == (( y >> 5 ) << 7),
but no (( y >> 5 ) << 7) != (y << 2)!
and no (((a + b) >> 1) << 7) != (((a >> 1) << 7) + (((b >> 1) << 7)!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文