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% 小さいか大きいかのように動作します。これは組み込みアプリケーションであり、「通常」の特定の範囲内にあるかどうかをテストする以外に、計算の結果を確認する方法がないためです。2番目の方程式を使用すると、パラメータ内に収まりますが、「簡略化された」(ビットシフトされた) 方程式ではそうではありません。

どんな洞察でも感謝します、ありがとう。

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 番目の式から、8 ビット部分 a と b に分割された 2 つの 16 ビット値を操作していると仮定します。

rear_wheel_speed = 0x0302
front_wheel_speed = 0x6fe2

使用する数式は、 speed= に簡略化できます(front_speed+rear_speed)*4

値から、0x6fe2*4 は 16 ビットにちょうど収まるので、この値は 16 ビット演算で評価できます。しかし、値はそれらのパーツの配置が間違っているように見え、実際の値は 0x036f と 0x02e2 (または 0x03ea と 0x026f) であると感じています。これらの値は、2 つの車輪の速度から予想されるように、互いに近い値です。

また、除算演算で精度が失われないため、式の方が優れているようです。ただし、優れたコンパイラを使用している場合 (組み込みアプリケーションの場合は必ずしもそうではありません)、通常、可能であれば除算/乗算をシフト自体に変換することに注意してください。

于 2009-09-08T08:21:29.693 に答える
0

必要なのは、16 ビットに収まるようにスケーリングされた、rear_wheel_speed と front_wheel_speed の平均です。これらは 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)" は、操作が実行される前に、rear_wheel_speed の下位 4 ビットを破棄し、" front_wheel_speed_b) / 16)" front_wheel_speed の下位 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 );

別の言い方をすれば、 yes
== ((((x * 256) / 16) / 2) * 128)((((x << 8) >> 4) >> 1) << 7)yes
((((x << 8) >> 4) >> 1) << 7)== (x << 10)
yes (((y / 16) / 2 ) * 128 )== (( y >> 5 ) << 7)no != ! いいえ! = !
(( y >> 5 ) << 7)(y << 2)
(((a + b) >> 1) << 7)(((a >> 1) << 7) + (((b >> 1) << 7)

于 2013-04-06T17:53:20.040 に答える