Forum: Mikrocontroller und Digitale Elektronik Aufrundfunktion?


von Reinhold (Gast)


Lesenswert?

Hallo,

ich brauche folgende "Umrechnung":

0 -> 0
1-8 -> 8
9-16 -> 16
17-24 -> 24
25-32 -> 32

Wie würdet ihr das am effektivsten in C implementieren?

Gruß
Reinhold

von Dussel (Gast)


Lesenswert?

Eine einfache if-else-Konstruktion ist sicher nicht ineffektiv. Wenn der 
Compiler einigermaßen gut ist, sind das wenige Takte und relativ wenig 
Code. Etwas Effektiveres fällt mir spontan nicht ein.
Da die 'Bereichsgrenzen' Vielfache von acht sind, könnte man vielleicht 
nochwas über das dritte Bit machen, aber selbst wenn das geht, wird das 
nicht viel kürzer und schneller werden als mit if.

von Simon B. (nomis)


Lesenswert?

Reinhold schrieb:
> ich brauche folgende "Umrechnung":
>
> 0 -> 0
> 1-8 -> 8
> 9-16 -> 16
> 17-24 -> 24
> 25-32 -> 32
>
> Wie würdet ihr das am effektivsten in C implementieren?
1
((x + 7) / 8) * 8;

Viele Grüße,
        Simon

von raketenfred (Gast)


Lesenswert?

mit dem vielfachen von 8 kann man wirklich was machen:

die zahl in 2 teile splitten:

1. Teil: bit(0,1,2)
2. Teil: bit(3,4,5,6,...)
und dann nur noch ausgabe:
return (2.teil+1.teil!=0)+"000"

die letzten 3 stellen sind 0 wegen runden und der vordere teil ggf. +1 
wenn wir kein vielfaches von 8 haben

von Abakus (Gast)


Lesenswert?

Ich würde den Compiler gar nicht erst "auf dumme Gedanken bringen", eine 
Division und einen Multiplikation zu verwenden. ;-)

Dem kürzestmöglichen Maschinencode dürfte folgendes C-Konstrukt 
nahekommen:

int  In, Out;

Out = ((In+7)<<3)>>3;

von raketenfred (Gast)


Lesenswert?

Simon Budig schrieb:
> ((x + 7) / 8) * 8;

float oder int?

float: return x+7;

int: x+7 und dann die letzten 3 bits auf 000 setzten

von Simon B. (nomis)


Lesenswert?

Abakus schrieb:
> Ich würde den Compiler gar nicht erst "auf dumme Gedanken bringen", eine
> Division und einen Multiplikation zu verwenden. ;-)
>
> Dem kürzestmöglichen Maschinencode dürfte folgendes C-Konstrukt
> nahekommen:
>
> int  In, Out;
>
> Out = ((In+7)<<3)>>3;

Und wuppdich haben wir den Beweis, warum es manchmal doch besser ist, 
die Division/Multiplikation einfach hinzuschreiben...   :-)

Viele Grüße,
        Simon

von Anja (Gast)


Lesenswert?

Abakus schrieb:
> Dem kürzestmöglichen Maschinencode dürfte folgendes C-Konstrukt
> nahekommen:
>
> int  In, Out;
>
> Out = ((In+7)<<3)>>3;

enthält leider gleich mehrere mögliche Problemfälle:
1. Falls In > 8185 (0x1FF9) oder < -8192 (0xE000) ist ergibt sich ein 
Überlauf und damit eine ungewollte Änderung der Bits.

2. in Ansi-C ist rechts-schieben von negativen Zahlen (Datentyp int) 
undefiniert.
Wenn ich also (-1) >> 1 schreibe erhalte ich je nach Compiler als 
Ergebnis entweder -1 (rechts shift mit Vorzeichenerweiterung) oder 32767 
(rechts shift ohne Vorzeichenerweiterung).


ich würde schreiben:
Y = (X+7) & 0xFFF8;

Die Und-Maske ist natürlich an den Datentyp anzupassen. Ich gehe mal von 
uint16_t aus. Der TE muß dann nur noch überlegen was mit Überläufen für 
X >= 65529  (>= 0xFFF9) passieren soll.

Gruß Anja

von Reinhold (Gast)


Lesenswert?

Hallo zusammen,

vielen Dank für die Inspirationen!
Ich habe nun diese Variante benutzt:

y = (x + 7) & 0xF8;

Ich benutze als Datentyp uint8_t (hatte ich vergessen zu erwähnen). Der 
Spezialfall für Werte > 248 ist unkritisch, so groß wird der Wert nie.

Liebe Grüße
Reinhold

von Anja (Gast)


Lesenswert?

Reinhold schrieb:
> Wie würdet ihr das am effektivsten in C implementieren?

Reinhold schrieb:
> y = (x + 7) & 0xF8;

Beim GCC-Compiler und uint8_t kann es sinnvoll sein für den Zwischenwert
(x + 7) eine Registervariable vom Typ uint8_t zu spendieren um den 
compiler zu überreden alles als uint8_t zu rechnen (und nicht als 
uint16_t).
also so:

register uint8_t z;

z = x + 7;
y = z & 0xF8;

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.