Forum: Mikrocontroller und Digitale Elektronik signed 18bit Integer richtig darstellen


von Jens (Gast)


Lesenswert?

Hallo zusammen,

ich bräuchte Hilfe.
Ich habe ein IC, das 18bit signed Werte ausgibt. Jetzt will ich die 
Werte auf der Konsole mit printf() ausgeben.
Das Problem ist nun, dass die negativen Werte nicht richtig dargestellt 
werden. Ich bekomme ständig Überläufe.
Der Wertebereich liegt ja zwischen 131071 und -131072. Aber da ich die 
Zahlen auf int32_t casten muss (der µC kann ja keine 18bit Werte). Daher 
werden die Werte alle als positive Zahl behandelt.

Zwischen positiven und negativen Zahlen zu unterscheiden kann ich, wenn 
ich einfach das 17te Bit anschaue. Wenn das 1 ist, dann ist die Zahl 
negativ.
Und jetzt kommt das Problem.
Ich begreife nicht, wie ich nun die int32_t Zahl zusammenbauen muss, 
dass die Zahlen den richtigen Wertebereich zwischen 131071 und -131072 
haben.
Eigentlich müsste es doch reichen, wenn ich die Bits 19 bis 31 auf 1 
setzt, wenn es eine negative Zahl ist und dann die 18bit Zahl einfach an 
die unteren Stellen kopiere.
Aber irgendwie bekomme ich das nicht hin.
Oder kann man das über eine normale Rechenoperation machen? Die Zeit 
spielt ja keine Rolle.

Ich wollte die Funktion so bauen, dass man die Bitbreite mit übergibt, 
so dass man auch 24bit Werte wandeln könnte (Das IC liefert auch solche 
- Ist ein Prototyp IC).

Der Compiler ist auf die erste Optimierungsstufe eingestellt und ich hab 
die Vermutung, dass da auch noch was reinfunkt.

Hat jemand von euch einen Gedankenanstoß für mich?

Danke euch!

Grüße, Jens

von Harry L. (mysth)


Lesenswert?

Quick&dirty:
1
if (x & 0x20000) x = (x & 0x1ffff) | 0x10000000);

: Bearbeitet durch User
von Anja (Gast)


Lesenswert?

Jens schrieb:
> die Bits 19 bis 31 auf 1
Das sind nur 13 Bits, da fehlt noch eines

Gruß Anja

von Andi (Gast)


Lesenswert?

val32 = val18 << 14 >> 14;

von Jens (Gast)


Lesenswert?

Hallo zusammen,

@Harry: Das funktioniert leider nicht. Muss man da nicht alle führenden 
Stellen auf eins setzen? nicht nur das Vorzeichenbit? Beim Überlauf auf 
die negative Zahl kommt da nicht das Richtige raus.

@Anja:
Du hast Recht, es muss heißen: Bit 18 bis 31.
Danke.

Grüße, Jens

von Jens (Gast)


Lesenswert?

@Andi:
Das könnte gehen. Du meinst man macht die Zahl linksbündig. Dann erkennt 
der Compiler die negative Zahl und wenn ich die danach wieder nach 
rechts schiebe zieht er führende 1er rein.
Das muss ich versuchen.

Oder meintest du das anders?

Grüße, Jens

von Oliver S. (oliverso)


Lesenswert?

Harry L. schrieb:
> Quick&dirty:

Quick und sauber:
1
 if (x & 0x20000) x |= 0xfffc0000;

Oliver

von Harry L. (mysth)


Lesenswert?

Harry L. schrieb:
> Quick&dirty:
>
1
> if (x & 0x20000) x = (x & 0x1ffff) | 0x10000000);
2
>

Das war natürlich ein Schnellschuss und Quatsch - sorry dafür!

Wurde ja oben bereits korrekt gelöst.

von Jens (Gast)


Lesenswert?

Hallo zusammen,

die Lösung von Andi scheint super zu funktionieren. Das muss ich morgen 
nochmal intensiv testen.
Diese Lösung finde ich sehr schön, da man durch das Schiften sehr leicht 
auf andere Wertebereiche ändern kann. Ich übergebe die Länge der Zahl im 
Funktionsaufruf. Dann ist es egal ob das 18bit oder 24bit oder was auch 
immer ist.

@Harry: Deine Lösung funktioniert vermutlich auch (ich hab es jetzt 
nicht getestet) aber die Bitmasken müsste man sich je nach Länge 
zusammenbasteln. Das ist dann mehr Aufwand als einfach nach links und 
rechts zu shiften.

Viele, vielen Dank an alle!
Ihr habt mir echt geholfen!

Grüße, Jens

von EAF (Gast)


Lesenswert?

Jens schrieb:
> aber die Bitmasken müsste man sich je nach Länge
> zusammenbasteln. Das ist dann mehr Aufwand als einfach nach links und
> rechts zu shiften.

Die Masken macht man sich zur Kompilezeit.
Das Schieben zur Laufzeit.
Nicht jeder µC hat einen Barrel-Shifter

von Anja (Gast)


Lesenswert?

Jens schrieb:
> die Lösung von Andi scheint super zu funktionieren.
Aber nur solange Du den Compiler nicht wechselst.
Rechtsschieben von signed Zahlen ist "implementation specific" in C.

Gruß Anja

von Andi (Gast)


Lesenswert?

Anja schrieb:
> Jens schrieb:
>> die Lösung von Andi scheint super zu funktionieren.
> Aber nur solange Du den Compiler nicht wechselst.
> Rechtsschieben von signed Zahlen ist "implementation specific" in C.
>
> Gruß Anja

Das stimmt zwar, aber normalerweise wird bei signed integer auch 
vorzeichenrichtig geschoben.

Wenn nicht:
 x << 14 >>> 14
oder:
 (x << 14) / 16384

von Kaj (Gast)


Lesenswert?

Du sagst es ja selbst:
Andi schrieb:
> normalerweise

von Tek (Gast)


Lesenswert?

> Die Masken macht man sich zur Kompilezeit.
+++

> Das Schieben zur Laufzeit.
> Nicht jeder µC hat einen Barrel-Shifter
Ein guter Compiler sollte erkennen, dass die Schieberei
nicht noetig ist, und aequivalenten Code erzeugen.

Vermutlich wuerde ich es aber auch nicht darauf ankommen lassen.

von A. S. (Gast)


Lesenswert?

Jens schrieb:
> der µC kann ja keine 18bit Werte)

Doch. In einer Struktur als Bitfeld.

Dass Chip und uC beide 2er-Komplement haben, können wir nur vermuten.

Wenn Du schieben willst (statt direkt die Maske zu definieren), geht 
auch (mit n=Anzahl Bits)
1
#define M (0xFFFFFFFF<<n) //mask
2
3
   if(M&x) x|=M;
4
5
Oder alternativ:
6
7
#define m (1UL<<n) 
8
9
    If(x>=m/2) x-=m;

von Rolf M. (rmagnus)


Lesenswert?

Andi schrieb:
> vorzeichenrichtig geschoben.

Du meinst, es wird ein "arithmetischer Shift" statt eines logischen 
ausgeführt.

Jens schrieb:
> @Harry: Deine Lösung funktioniert vermutlich auch (ich hab es jetzt
> nicht getestet) aber die Bitmasken müsste man sich je nach Länge
> zusammenbasteln. Das ist dann mehr Aufwand als einfach nach links und
> rechts zu shiften.

Ändert sich die Anzahl an Bits, die dein IC ausgibt, denn ständig?

: Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.