Forum: Mikrocontroller und Digitale Elektronik itoa durch Shiftoperatoren - möglich?


von Sven (Gast)


Lesenswert?

Hi Leute!

Ist es möglich eine Art von itoa mittels Shiftoperationen zu machen?

Ich merke schon deutlich einen Speicherplatzunterschied wenn ich z.B. 
anstatt durch 32 teilen einen Rechtsshift um 5 mache. Das macht bei mir 
hier gerade einen Unterschied von 268 Byte aus (mein Controller hat 2k).

Ich habe hier meine eigene Funktion
1
void integer_to_single_numbers( int16_t source_number, uint8_t *dest_buffer )
2
{ 
3
  if( source_number < 0 )
4
  {
5
    shift_reg_control.display__sign = SIGN_NEGATIVE;
6
    source_number *= -1;
7
  }
8
  else
9
  {
10
    shift_reg_control.display__sign = NO_SIGN;
11
  }
12
  
13
  dest_buffer[0] = (source_number / 1000);
14
  source_number %= 1000;
15
  dest_buffer[1] = (source_number / 100);
16
  source_number %= 100;
17
  dest_buffer[2] = (source_number / 10);
18
  dest_buffer[3] = (source_number % 10);
19
}
die mir Zahlen in ihre Einzelteile zerlegt. Gibt es denn irgendeine 
Möglichkeit auch zu einer Zehnerpotenz ähnliches anzuwenden?

von Sven (Gast)


Lesenswert?

Nachtrag: Nimmt eine Multiplikation mit -1 auch verhältnismäßig mehr 
Speicher weg als eine Addition? Geht das auch anders?

von Harglbar (Gast)


Lesenswert?

Optimierung ausgeschaltet? Der Compiler benutzt automatisch Shifts, wenn 
Zweierpotenzen im Spiel sind.

Wenn du Platz sparen willst, lass es lieber für solch triviale Sachen 
Structs zu benutzen.

Und nein, Shifts im Binärsystem bringen dir nichts im Dezimalsystem.

von (prx) A. K. (prx)


Lesenswert?

Sven schrieb:

> Ist es möglich eine Art von itoa mittels Shiftoperationen zu machen?

Nur wenn die Basis eine Zweierpotenz ist.

von Heinz L. (ducttape)


Lesenswert?

Divisionen sind teuer. Aber das wirst Du auch schon festgestellt haben. 
In Assembler ließe sich sowas noch mehr optimieren, aber hast du mal 
etwas im Stil von dem da probiert:


1
void itoa (unsigned int input, char* digits)
2
//digits muss ein Array sein das hinreichend groß ist.
3
{
4
unsigned char ucplace=0;
5
unsigned int uidiv;
6
7
while (ucplace<MAXDIGITS)
8
{
9
  switch (ucplace)
10
  {
11
    case 0:
12
    {
13
      uidiv=10000;
14
      break;
15
    }
16
    case 1:
17
    {
18
      uidiv=1000;
19
      break;
20
    }
21
    ...//Die restlichen Zuweisungen, bis runter zu case 4: uidiv=1;
22
  }
23
  
24
  while (input >= uidiv)
25
  {
26
    input -= uidiv;
27
    digits[ucplace]++;
28
  }
29
}
30
return;
31
}

Hab ich jetzt nur mal runtergeschrieben und nicht ausprobiert, aber die 
Idee ist, so lang die höchste 10er Potenz abzuziehen (und die Anzahl zu 
zählen) bis der Rest kleiner ist, dann die nächstniedrigere 10er Potenz 
zählen usw.

Sollt klappen, schneller sein und weniger Platz fressen. In ASM könnte 
man hier noch einiges mehr optimieren... ich guck mal ob ich Zeit finde, 
brauchen kann man sowas bekanntlich immer mal.

von Peter D. (peda)


Lesenswert?

Zahlenausgabe schnell und codesparend, da ist die Subtraktionsmethode 
optimal:
1
void outint( int val )
2
{
3
  uint code TEST[] = { 10, 100, 1000, 10000 };
4
  uchar d, i;
5
  bit zero;
6
  uint uval = val;
7
8
  if( val < 0 ){
9
    uval = -val;
10
    putchar( '-' );
11
  }
12
13
  zero = 1;
14
  i = 4;
15
  do{
16
    i--;
17
    for( d = '0'; uval >= TEST[i]; uval -= TEST[i] ){
18
      d++;
19
      zero = 0;
20
    }
21
    if( zero == 0 )
22
      putchar( d );
23
  }while( i );
24
25
  putchar( (uchar)uval + '0' );
26
}


Peter

von Oliver (Gast)


Lesenswert?

Harglbar schrieb:
> Optimierung ausgeschaltet? Der Compiler benutzt automatisch Shifts, wenn
> Zweierpotenzen im Spiel sind.

Hm. Von welcher Firma ist denn das Produkt "Der Compiler"?
Das sollten man schon wissen, bevor man solche Aussagen trifft.

Eine Optimierung, soweit vorhanden, sollte man aber schon einschalten.

Oliver

von bitshift (Gast)


Lesenswert?

Sven schrieb:
> Nachtrag: Nimmt eine Multiplikation mit -1 auch verhältnismäßig mehr
> Speicher weg als eine Addition? Geht das auch anders?

ZAHL = ~(ZAHL)+1

bzw

ZAHL = ~(ZAHL-1)

von (prx) A. K. (prx)


Lesenswert?

Sven schrieb:
>     source_number *= -1;

Sven schrieb:
> Nachtrag: Nimmt eine Multiplikation mit -1 auch verhältnismäßig mehr
> Speicher weg als eine Addition? Geht das auch anders?

bitshift schrieb:
> ZAHL = ~(ZAHL-1)

Soll ich jetzt lachen oder weinen?

von Sven (Gast)


Lesenswert?

Hi und danke!

Ich habe es jetzt mit der Subtraktion implementiert und wieder 132Byte 
gespart. Super!
1
void integer_to_numbers( int16_t source_number, uint8_t *dest_buffer )
2
{
3
  uint16_t test_val[4] = { 1000, 100, 10, 1 };
4
  uint16_t temp_val;
5
  uint8_t count, number;
6
  
7
  temp_val = source_number;
8
  shift_reg_control.display__sign = NO_SIGN;
9
  
10
  if( source_number < 0 )
11
  {
12
    shift_reg_control.display__sign = SIGN_NEGATIVE;
13
    temp_val = -source_number;
14
  }
15
  
16
  count = 0;
17
  
18
  do
19
  {    
20
    for( number = 0; temp_val >= test_val[count]; temp_val -= test_val[count] )
21
    {
22
      number++;
23
    }
24
    
25
    dest_buffer[count] = number;  
26
    count++;
27
    
28
  } while( count < 4 );
29
}

von Sven (Gast)


Lesenswert?

Ach ja: Ich benutze den IAR Compiler. Optimierungen habe ich persönlich 
jetzt nicht eingestellt. Zumindest habe nichts verändert.

von Sven (Gast)


Lesenswert?

Wie geht denn das mit den Optimierungen? Ich find nichts im Netz.

von Sven (Gast)


Lesenswert?

Harglbar schrieb:
> Wenn du Platz sparen willst, lass es lieber für solch triviale Sachen
> Structs zu benutzen.

Verbrauchen structs mehr Platz als einzelne Variablen?

von MaWin (Gast)


Lesenswert?

> wieder 132Byte gespart.
1
void integer_to_numbers(int16_t source_number, uint8_t *dest_buffer)
2
{
3
    char *buf[6];
4
5
    if(source_number<0) 
6
    { 
7
        *dest_buffer++='-'; 
8
        source_number=-source_number; 
9
    }
10
    buf[i=5]='\0'; // terminiert nachher den dest_buffer
11
    do // immer mindestens eine 0
12
    {
13
       buf[--i]=source_number%10;
14
       source_number/=10;
15
    }
16
    while(source_number); // kann auch 5 Stellen, führende 0 unterdrückt
17
    while(i<=5)
18
    {
19
        *dest_buffer++=buf[i++];
20
    }
21
}
braucht sicher weniger Speicher.

von Sven (Gast)


Lesenswert?

MaWin schrieb:
> braucht sicher weniger Speicher.

So hatte ich es doch vorher ungefähr - da ist doch wieder die Division 
drin.

von Stefan (Gast)


Lesenswert?

Welchen Controller nutzt du?

von W.S. (Gast)


Lesenswert?

Sven schrieb:
> (mein Controller hat 2k)

So, 2k WAS? Dein Controller hat nur 2 K Byte Befehlsspeicher oder 2 K 
Befehle? Ist also vermutlich ein kleiner 8 Bitter.

Und da willst du solche Hilfsroutinen wie das Ausgabekonvertieren von 
Integers in C schreiben, ohne dich intensiv um die in den mitgelieferten 
Bibliotheken vorhandenen Funktionen zu kümmern. Ah ja.

Such einfach mal nach der Funktion ldiv. Die müßte es bei IAR auch für 
die kleineren uC geben - und wenn du sie gefunden hast, dann schreib 
deine Ziffernroutine neu.

Ich geb dir hier mal einen Ausschnitt aus ner Konvertierung (die 
Formatierungen hab ich weggelassen):

long LtoStr (long aValue, int digits, char* Buffer, int BufLen)
  ...
  i = BufLen - 1;
  Buffer[i--] = 0;    /* Endemarker setzen */
  if (aValue<0)
       { L = -aValue;
         v = 1;
       }
  else { L = aValue;
         v = 0;
       }

  if (!L)  Buffer[i--] = '0';
  while (i)
  { if (!L) goto _lready;
    T = ldiv(L,10);
    L = T.quot;
    Buffer[i--] = '0'+T.rem;
  }

                     /* i = 0 heisst: der Buffer ist voll! */
  i = 0; j = BufLen - 2;
  Buffer[i++] = '>';
  while (i<j) Buffer[i++] = '9';
  return aValue;

_lready:
  ...


Aber bei einem uC mit nur 2 K Programmspeicher würde ich zumindest 
solche Routinen in Assembler schreiben und nicht ldiv, sondern die von 
Peter Dannegger skizzierte Subtraktionsmethode benutzen. Die braucht 
lediglich Subtraktionen und ein paar Zehnerpotenzen als Konstanten.

W.S.

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.