Frage

Ich habe eine Gleichung auf das destilliert:

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

Aber aus irgendeinem Grund bekomme ich unerwartete Ergebnisse, also muss ich etwas falsch machen. Dies begann so:

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

Das ist die völlig nicht festgelegte Version, die funktioniert. Sind sie keine mathematischen Äquivalente?

Alle Werte sind 16 -Bit -Ganzzahlen signiert. Ein Beispieldatensatz ist:

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;

Das läuft auf eine Antwort von 6468 hinaus. In der ersten Gleichung verhält sich meine Anwendung so, als wäre sie mindestens 3% kleiner oder größer. Ich sage es so, weil dies eine eingebettete Anwendung ist, in der ich die Ausgabe der Berechnungen nicht bestätigen kann, als zu testen, ob es sich in einem bestimmten Bereich von "normal" befindet. Wenn ich die zweite Gleichung verwende, fällt sie in die Parameter, aber mit meiner "vereinfachten" (bitveränderten) Gleichung. Ich denke, ich muss die Verschiebungen falsch machen (oder ich habe falsch vereinfacht, aber ich habe es dreifach überprüft).

Jeder Einblick wird geschätzt, danke.

War es hilfreich?

Lösung

Aus der zweiten Formel gehe ich davon aus, dass Sie 2 16 -Bit -Werte in ihren 8 -Bit -Teil A und B betrieben werden:

rear_wheel_speed = 0x0302
front_wheel_speed = 0x6fe2

und die Formel, die Sie verwenden, kann in Geschwindigkeit vereinfacht werden =(front_speed+rear_speed)*4.

Aus Ihren Werten kann 0x6Fe2*4 einfach 16 Bit passen, sodass dieser Wert in 16-Bit-Arithmetik bewertet werden kann. Aber die Werte sehen so aus, als ob ihre Teile falsch angeordnet sind, und ich habe das Gefühl, dass echte Werte 0x036F und 0x02e2 (oder 0x03ea und 0x026f) sind - diese Werte liegen nahe beieinander, wie es von der Geschwindigkeit von zwei Rädern erwartet werden sollte.

Es scheint auch, dass Ihre Formel besser ist, da sie keinen Präzisionsverlust für die Divide -Operationen einführt. Denken Sie jedoch daran, dass, wenn Sie einen guten Compiler verwenden (nicht immer für eingebettete Anwendungen)

Andere Tipps

Das Problem ist, dass Sie einen Überlauf bekommen. Während die von Ihnen verwandte Gleichung mathematisch korrekt ist, sind einige Ihrer Zwischenwerte höher als die signierten 16-Bit-INTs, in denen Sie sie speichern.

Um spezifisch zu sein, ist der problematische Teil

( rear_wheel_speed_a + front_wheel_speed_a ) << 10

Bei Ihrer Stichprobeneingabe beträgt der resultierende Wert 0x1c800 - größer als selbst eine nicht signierte 16 -Bit -Ganzzahl!

Die ursprüngliche Gleichung scheint dies bereits zu berücksichtigen. Einige der Werte verlieren beim Herunterschalten leicht Präzision, aber das ist besser als der ganze Überfluss. Ich empfehle also, die ursprüngliche Gleichung zu verwenden, aber Sie können das Multiplikum ersetzen und natürlich durch Verschiebungen teilen:

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

Ein weiterer Hinweis: Ihre Eingangs -Front_Wheel_Speed_B ist bereits überfüllt, es sei denn, sie soll negativ sein.

Was Sie wollen, ist der Mittelwert von rard_wheel_speed und vorne_wheel_speed, der so skaliert ist, dass er auf 16 Bit passt. Da sie 16-Bit-Werte sind, liegt die Summe auf 17 Bit, sodass Sie das Ergebnis verändern müssen, um Überlauf zu vermeiden.

Ihre anfängliche Formel nimmt jede Geschwindigkeit auf 12 Bit (xxx/16), dann der Mittelwert der Werte, wieder auf 12 Bit, dann mit 128 multipliziert. Dies erfordert 19 Bits: Ihre anfängliche Formel überläuft für größere Werte.

Um den Mittelwert auf 16 Bit ohne Überlauf zu erhalten, schlage ich Folgendes vor (vorausgesetzt, die Werte sind positiv, wie Sie in Ihrem Kommentar gesagt haben):

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

Dies ergibt ein Ergebnis auf 16 Bit ohne Überlauf. Jeder xxx_wheel_speed_h ist auf 15 Bits.

Im ursprünglichen Ausdruck werfen die Divisionsbetreiber Bit niedriger Ordnung weg, aber Ihr Ersatz wirft eindeutig keine Bit mit niedriger Ordnung weg, so dass allein dies bedeutet, dass sie sie bedeutet kippen äquivalent sein!

"rear_wheel_speed_b) / 16)"Verwirrt die 4 Bits von RECKWHEEL_SPEED mit niedriger Ordnung, bevor alle Operationen auf ihnen ausgeführt werden, und"front_wheel_speed_b) / 16)"Verwirrt die 4 Tiefsts in niedriger Ordnung von Front_Wheel_Speed. Dann das"/ 2)"Der Bediener verwirft das Bit der Summe niedriger.

Sie können nur genau das gleiche Ergebnis erzielen, wenn Sie etwas in Ihren Ausdruck aufnehmen, um dieselben Bits zu null:

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

wird

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

Um es anders zu sagen,
Jawohl ((((x * 256) / 16) / 2) * 128) == ((((x << 8) >> 4) >> 1) << 7),
und ja, ((((x << 8) >> 4) >> 1) << 7)== (x << 10),
und ja (((y / 16) / 2 ) * 128 ) == (( y >> 5 ) << 7),
aber nein (( y >> 5 ) << 7) != (y << 2)!
und nein (((a + b) >> 1) << 7) != (((a >> 1) << 7) + (((b >> 1) << 7)!

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top