mikrocontroller.net

Forum: Compiler & IDEs Anzahl Stellen einer Zahl


Autor: Dennis (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
ich möchte die Anzahl der Stellen einer Zahl bestimmen.
Bei 123456 soll zum Beispiel 6 herauskommen.
Gab es nicht Funktionen wie length() oder so ähnlich?
Gruß,
Dennis

Autor: UBoot-Stocki (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

wie wärs mit einer Funktion,

- die solange durch 10 teilt, bis die "Restzahl" 0 ist?

- die die Zahl in einen String wandelt und dann mittels "strlen" die 
Länge bestimmt ?

Gruß

Andreas

Autor: Christian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
...oder den Logarithmus zur Basis 10 ausrechnen und dann das Ergebnis 
aufrunden. Wird allerdings auf einem µC nicht sehr effizient.

Grüße,
 Christian

Autor: Florian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das Effizienteste ist mit Sicherheit eine Verschachtelung von 
Bedingungen (also if etc.), da - bei ganzzahligen Datentypen - die 
maximale Anzahl der Ziffern wohl bekannt ist.

8-bit 0 - 255, also maximal 3 Ziffern
16-bit 0 - 65535, also max. 5 Ziffern
24-bit 0 - 16777215, also max. 8 Ziffern
32-bit 0 - 4294967295, also max. 10 Ziffern

usw.

Die Divisionen sind langsamer.

Also etwas in der Art, wie

if ( x < 10 )
  return 1;
else if ( x < 100 )
  return 2;
else if ( x < 1000 )
  return 3;

usw.

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das könnte man auch noch in eine For-Schleife packen ;)

Autor: yalu (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Das könnte man auch noch in eine For-Schleife packen ;)

Genau! Und dann mit -O3 kompilieren, um den Schleifen-Overhead und die
Multiplikationen wieder wegzuoptimieren ;) ;)

Autor: Dirk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
char s[6];
int z=12345
int len;

sprintf(s,"%d",z);
len = strlen(s);

Autor: Guenther Boelter (Firma: gbs-Consulting) (gboelter)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
#include <stdio.h>
#include <string.h>

int main (void) {

    int i;
    int n;

    printf("Bitte geben Sie eine Zahl ein : ");
    scanf("%d",&i);

    n = anzahl(i);
    printf ( "Die Zahl %i besteht aus %i Ziffern!\n", i, n );
}


anzahl (arg1)
{

    int zeichen;
    char buffer[100];
    sprintf(buffer, "%d", arg1);

    zeichen = strlen(buffer);

    return zeichen;

}

Autor: yalu (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn man schon mit Kanonen auf Spatzen schießt (sprintf :-)), kann man
auf strlen verzichten, da die Länge als Abfallprodukt geliefert wird:
int anzahl(unsigned int n) {
  char buffer[11];
  return sprintf(buffer, "%d", n);
}

Autor: yalu (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stopp, Fehler entdeckt:

s/%d/%u/

:-)

Autor: Guenther Boelter (Firma: gbs-Consulting) (gboelter)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
yalu wrote:
> Wenn man schon mit Kanonen auf Spatzen schießt (sprintf :-)), kann man
> auf strlen verzichten, da die Länge als Abfallprodukt geliefert wird:

Stimmt, keine Frage. Aber ich wollte auch nur den vorangegangnen Code 
ein wenig erlaeutern. Aus der Ursprungsfrage von Dennis schliesse ich 
naemlich, das er in C/C++ nicht so bewandert ist.

Meinen Beispielcode hatte ich zudem gerade rein zufaellig im Editor ...

Guenther
Davao City, Philippines, Planet Earth

Autor: And the winner is (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
if ( x < 10 )
  return 1;
else if ( x < 100 )
  return 2;
else if ( x < 1000 )
  return 3;
else if ( x < 10000 )
  return 4;
return 5;


  CMP.W  #0xa, R15
  JC  ??main_0
  MOV.W  #0x1, R12
  RET
??main_0:
  CMP.W  #0x64, R15
  JC  ??main_1
  MOV.W  #0x2, R12
  RET
??main_1:
  CMP.W  #0x3e8, R15
  JC  ??main_2
  MOV.W  #0x3, R12
  RET
??main_2:
  CMP.W  #0x2710, R15
  JC  ??main_3
  MOV.W  #0x4, R12
  RET
??main_3:
  MOV.W  #0x5, R12
  RET

Nicht alles was schick aussieht, ist auch effizient.

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hast du denn eine effizientere Lösung?

Autor: yalu (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielleicht sollte man an dieser Stelle einmal zwischen Speicher- und
Laufzeiteffizenz unterscheiden:

- Am speichereffizientesten sind sicher die Logarithmus- und die
  sprintf-Lösung, wenn man die Mathebibliothek bzw. die
  sprintf-Funktion (und den benötigten Puffer) sowieso schon an
  anderer Stelle im Programm benutzt.

- Sind diese Voraussetzungen nicht gegeben, ist wahrscheinlich Simons
  Schleife eine gute Wahl. Die ist auch laufzeitmäßig nicht schlecht,
  vor allem dann, wenn das Zielsystem einen schnellen Multiplizierer
  hat.

- Am schnellsten ist aber sicher die Lösung mit einzelnen
  if-Anweisungen wie von Florian, oder (noch schneller) so:
  if(n < 100000) {
    if(n < 1000) {
      if(n < 100) {
        if(n < 10)
          return 1;
        return 2;
      }
      return 3;
    }
    if(n < 10000)
      return 4;
    else
      return 5;
  }
  if(n < 100000000) {
    if(n < 10000000) {
      if(n < 1000000)
        return 6;
      return 7;
    }
    return 8;
  }
  if(n < 1000000000)
    return 9;
  else
    return 10;
  
  Dies ist für 32-Bit-Zahlen. Für größere oder kleiner Wertebereiche
  muss der Code natürlich angepasst werden.

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
yalu wrote:
>> Das könnte man auch noch in eine For-Schleife packen ;)
>
> Genau! Und dann mit -O3 kompilieren, um den Schleifen-Overhead und die
> Multiplikationen wieder wegzuoptimieren ;) ;)

Achwas, die Hauptsache ist doch, dass es im Quelltext schön aussieht ;) 
;)

@ And the winner is (Gast):
Verstehe deinen Einwand nicht so ganz, was gibt's denn an dem Code zu 
meckern? Entspricht doch genau dem (zumindest von mir) erwarteten Code: 
Vergleiche und bedingte Jumps...

PS: Die Sache mit dem strlen ist ja wohl Mega-Quatsch... Erst alles 
durch Dividieren/Modulo mit 10 in einen String umwandeln und 
anschließend nochmal von vorne zählen, wieviele Stellen > 0 entstanden 
sind.

Da "erzeugt" man doch in einem Zwischenschritt Informationen, die man 
nachher eh "wegschmeißt"...

PPS: @Yalu vor mir: Die Version sieht richtig gut aus. Wenn ich das 
richtig sehe, werden sogar unnötige Vergleiche direkt vermieden, wenn 
sie gar nicht mehr wahr werden können.

Autor: yalu (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja. Man unterteilt den Wertebereich wiederholt in zwei Teile, so dass
in jedem möglichst gleichviele Stellenzahlen liegen. Der erste
Vergleich trennt die Zahlen nach solchen mit der Stellenzahl 1..5 und
solchen mit der Stellenzahl 5..10. Für jede dieser Hälften wird das
Verfahren entsprechend fortgesetzt, so dass man schließlich mit
maximal 4 Vergleichen zum Ziel kommt.

Übungsaufgabe für den geneigten Leser: Man formuliere das ganze kürzer
und eleganter als
a) Schleife
b) Rekursion
:-)

Autor: Guenther Boelter (Firma: gbs-Consulting) (gboelter)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das ist ja alles schoen und nett, aber die Frage von Dennis war doch 
wohl

> ich möchte die Anzahl der Stellen einer Zahl bestimmen.
> Bei 123456 soll zum Beispiel 6 herauskommen.
> Gab es nicht Funktionen wie length() oder so ähnlich?

der hat doch von Geschwindigkeit und dergleichen ueberhaupt nichts 
geschrieben, der wollte - meiner bescheidenen Meinung nach - nur eine 
simple Alternative zu length() haben, und das ist nun mal der 'Trick' 
mit sprintf.

Klar sind Eure Ansaetze super, aber das war doch ueberhaupt nicht das 
Thema,

Autor: Sven (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja, solange nur die Datentypen char und int verwendet werden. Wenn ein 
Long verwendet werden soll, muss man die Funktion noch weiter ausbauen, 
da man hier den formatstring %ld verwenden muss.

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Guenther Boelter wrote:
> Klar sind Eure Ansaetze super, aber das war doch ueberhaupt nicht das
> Thema,

Und? Man kann doch ruhig weiterspinnen, wenn die Frage des Threadopeners 
eigentlich völlig geklärt ist.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Mir stellt sich die Frage nach der Sinnhaftigkeit, die Länge einer Zahl 
zu bestimmen, ohne sie ausgeben zu wollen.

Wenn man sie zur Ausgabe umwandelt fällt die Länge ja automatisch ab 
(Mitzählen) bzw. kann per strlen einfachst ermittelt werden.

Deshalb werde ich mich hüten, für derart Sinnloses hier Code 
reinzustellen (wäre schade um die Mühe).


Peter

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Mir stellt sich die Frage nach der Sinnhaftigkeit, die Länge einer Zahl
> zu bestimmen, ohne sie ausgeben zu wollen.
>
> Wenn man sie zur Ausgabe umwandelt fällt die Länge ja automatisch ab
> (Mitzählen) bzw. kann per strlen einfachst ermittelt werden.

Vielleicht will er ja die Länge bereits vor der Ausgabe wissen statt 
nachher, z.B. weil er es rechtsbündig ausgeben will und dazu wissen 
will, wo er links anfangen muß.

> Deshalb werde ich mich hüten, für derart Sinnloses hier Code
> reinzustellen (wäre schade um die Mühe).

Du hast doch überhaupt keine Ahnung, wozu der Ursprungsposter das will. 
Wie kannst du da wissen, ob es sinnlos ist?

Autor: Peter Dannegger (peda)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Rolf Magnus wrote:

> Vielleicht will er ja die Länge bereits vor der Ausgabe wissen statt
> nachher, z.B. weil er es rechtsbündig ausgeben will und dazu wissen
> will, wo er links anfangen muß.

1.
Man macht Wandlung und rechtsbündige Ausgabe gleichzeitig:
printf("%6d", i);

2.
Man macht alles nacheinander(itoa, strlen, lcd_locate, lcd_puts).


Beides benötigt leider nicht, die Länge vor der Wandlung zu kennen.


Peter

Autor: yalu (Gast)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Peter Dannegger schrieb:

> Deshalb werde ich mich hüten, für derart Sinnloses hier Code
> reinzustellen (wäre schade um die Mühe).

Dass du dir keinen Sinn in Dennis Frage vorstellen kannst, hat geneu
einen der folgenden beiden Gründe:

- Diesen Sinn gibt es tatsächlich nicht.

- Der Sinn liegt außerhalb deines Gedankenhorizonts.


Mir ist vollkommen klar, was Dennis damit machen will: Nämlich
folgendes zahlentheoretische Problem lösen:

  Gegegeben seien zwei Funktionen f und g von N in N (N ist die Menge
  der natürlichen Zahlen).

  s(n) sei die Stellenanzahl von n in Dezimalschreibweise.

  Gesucht ist die kleinste Zahl n aus N, für die gilt:

    f(n) = s(g(n))

Da f und g ziemlich komplizierte Funktionen sind, will Dennis das
Problem per Computer durch Ausprobieren lösen. Dazu braucht er sehr
schnelle Implementationen von f, g und s. Für f und g hat er die schon
gefunden, sonst hätte er danach gefragt. Aber s fehlte ihm noch,
deswegen seine Anfrage.

Zum Glück hat er unter den vielen Lösungsvorschlägen einen geeigneten
gefunden (sonst hätte er den Grund gepostet, warum die Vorschläge
nichts taugen) und lässt nun gerade seinen Rechner nudeln.

Jeder, der eine Lösung wusste, sie aber nicht gepostet hat, hat mit
seinem Verhalten den wissenschaftlichen Fortschritt gebremst.

                                                                ;-)

Autor: Guenther Boelter (Firma: gbs-Consulting) (gboelter)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Nun kommt mal wieder mit den Fuessen auf die Erde, das ist hier doch 
kein Kindergarten. Da hat jemand eine durchaus interessante Frage 
gestellt, die es jedem frei steht sie zu beantworten.

Und was macht ihr draus: Meiner ist groesser, laenger, dicker ....

Habt ihr sonst nix zu tun?

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Guenther Boelter wrote:
> Da hat jemand eine durchaus interessante Frage
> gestellt, die es jedem frei steht sie zu beantworten.
Ja, EBEN.

> Und was macht ihr draus: Meiner ist groesser, laenger, dicker ....
Programmierer überbieten sich halt gern in Sachen "Wer hat den besseren 
Code". Immerhin kann man so voneinander lernen und unter Umständen 
völlig andere Algorithmen kennen lernen um ein bestimmtes Problem zu 
lösen...

> Habt ihr sonst nix zu tun?
Das frage ich mich im Bezug auf dich.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.