C 4stellige Zahl aufsplitten

Gast #368087
Lesenswert?

Hallo alle zusammen.

Sitze gerade vor folgendem Problem:
Bin dabei eine 4Stellige sieben Segment Anzeige aufzubauen und möchte
dort die Zahlen anzeigen lassen, die von einem Atmega8 kommen sollen.
Mein Problem ist jetzt, wie splitte ich eine Zahl z.B. 9876 ( in C ) so
auf, dass die „9“ in einer Variablen steckt, die „8“ in einer anderen
usw?

PS: Ja, geggoogelt hab ich auch, hab nur nichts Sinnvolles gefunden.
Gast #368088
Lesenswert?

Durch sukzessive Modulo / Division.
z.B.:

unsigned char stelle[4];
unsigned int wert;

for(i = 0; i < 4; i++)
{
    stelle[i] = wert % 10;
    wert /= 10;
}

Dann stehen in stelle[0...3] die einzelnen Dezimalstellen, und zwar die
Einser in stelle[0], die Zehner in stelle[1] usw...
Gast #368092
Lesenswert?

Naja, ein sprintf ist aber in dem Zusammenhang echt mit Kanonen auf
Spatzen geschossen. Da kann man noch eher itoa nehmen. Das bläht das
Programm nicht so auf und das Ergebnis ist das selbe...
Gast #368093
Lesenswert?

@Walter:
Nur als kleines Beispiel: Aus dem hier

unsigned char string[6];
unsigned int wert = 12345;
sprintf(string, "%i", wert);

macht der AVR-GCC-C-Compiler satte 1922 Bytes Code (Optimierung -Os).

Das hier

unsigned char string[6];
unsigned int wert = 12345;
itoa(wert, string, 10);

gibt kompakte 312 Bytes. Ich glaub, da fiele die Wahl nicht schwer,
gell?

Aber die ganz oben genannten Methoden sind sicher noch kleiner...
Gast #368094
Lesenswert?

290 Bytes Code.
Zahl ist in 4 ASCII Zeichen umgewandelt.
Wenn du kein ASCII haben willst, ziehe 30hex von jeder ab.

unsigned char lookup [17] = "0123456789ABCDEF";
unsigned char buffer[5];

int main(void)
{
 unsigned int zahl;

 buffer[0] = lookup[(zahl)      & 0x000F];
 buffer[1] = lookup[(zahl >>4 ) & 0x000F];
 buffer[2] = lookup[(zahl >>8 ) & 0x000F];
 buffer[3] = lookup[(zahl >>12) & 0x000F];

return 0;
}
Gast #368095
Lesenswert?

Oops, der Zahl fehlt noch dein Beispielwert.

unsigned char lookup [17] = "0123456789ABCDEF";
unsigned char buffer[5];

int main(void)
{
 unsigned int zahl = 9847;

 buffer[3] = lookup[(zahl)      & 0x000F];
 buffer[2] = lookup[(zahl >>4 ) & 0x000F];
 buffer[1] = lookup[(zahl >>8 ) & 0x000F];
 buffer[0] = lookup[(zahl >>12) & 0x000F];

 return 0;
}
Gast #368097
Lesenswert?

Genau, in dem Beispiel würde nicht 9847 ausgegeben, sondern das
Hexadezimal-Äquivalent 2677. Und das ist ein klitzekleiner Unterschied.
Genau das ist ja das Problem, wenn man von einem Prozessor
Dezimalstellen bekommen will: Die Division durch 10 ist eben nicht so
schön einfach durch Bitschubsereien machbar und macht deshalb mehr Code
erforderlich.
#368099
Lesenswert?

Hmm.

> void outint( u16 val, u8 * result )
> {
>   u8 d, i;
>   u16 tval;
>
>   for( i = 4; i; i-- ){
>     tval = pgm_read_word(TEST+i-1);    // get test value
>     for( d = 0; val >= tval; val -= tval )
>       d++;          // count subtractions
>     *result = d;        // store digit

      *result = d + '0';

>     result++;
>   }
>   *result = val;        // store ones
> }

macht noch ein paar Bytes zusätzlich :-)
Gast #368106
Lesenswert?

> daß die Divisionen nicht alle doppelt gemacht werden müssen.

Was glaubst Du denn, was die Funktion div() macht? Du musst die
Division und das Modulo vielleicht nicht explizit hinschreiben, aber
div() macht intern mit Sicherheit auch nix anderes... Vom
Programmieraufwand ist das glaub ich kein wirklicher Unterschied.
Moderator Persönliche Seite #368107
Lesenswert?

> Vom Programmieraufwand ist das glaub ich kein
> wirklicher Unterschied.

Dann solltest du dir mal den Divisionsalgorithmus angucken.
Der Rest fällt bei der ganzzahligen Division immer zugleich
mit dem Quotienten mit an.  Erinnere dich einfach an deine
Division natürlicher Zahlen in der Grundschule: dort war das
auch schon so.

Daher hat es Sinn, div() zu benutzen, wenn man sowohl den
Quotienten als auch den Rest ohnehin benötigt.  (Sonst gäbe
es diese Funktion sicher gar nicht erst.)  Da die Division die
teuerste Grundrechenoperation ist, spart man knapp die Hälfte
an Zeit (und vermutlich einiges mehr gegenüber Peter's "poor
man division" mittels fortlaufender Subtraktion).
#368109
Lesenswert?

@Jörg,

"Da die Division die teuerste Grundrechenoperation ist, spart man
knapp die Hälfte an Zeit (und vermutlich einiges mehr gegenüber
Peter's "poor man division" mittels fortlaufender Subtraktion)."


Nö.

Die 16Bit-Divisonsschleife wird 16* durchlaufen je Digit, die
Subtraktion aber nur max 9* (worst case).

Die optimierte Assemblersubtraktion über Null hinweg ist nochmal
wesentlich schneller (siehe Anhang).

Spielt aber für menschliche Ausgaben keinerlei Rolle.


Peter
Angehängte Dateien:

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren