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
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
...oder den Logarithmus zur Basis 10 ausrechnen und dann das Ergebnis aufrunden. Wird allerdings auf einem µC nicht sehr effizient. Grüße, Christian
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.
> 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 ;) ;)
#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; }
Wenn man schon mit Kanonen auf Spatzen schießt (sprintf :-)), kann man auf strlen verzichten, da die Länge als Abfallprodukt geliefert wird:
1 | int anzahl(unsigned int n) { |
2 | char buffer[11]; |
3 | return sprintf(buffer, "%d", n); |
4 | }
|
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
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.
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:
1 | if(n < 100000) { |
2 | if(n < 1000) { |
3 | if(n < 100) { |
4 | if(n < 10) |
5 | return 1; |
6 | return 2; |
7 | }
|
8 | return 3; |
9 | }
|
10 | if(n < 10000) |
11 | return 4; |
12 | else
|
13 | return 5; |
14 | }
|
15 | if(n < 100000000) { |
16 | if(n < 10000000) { |
17 | if(n < 1000000) |
18 | return 6; |
19 | return 7; |
20 | }
|
21 | return 8; |
22 | }
|
23 | if(n < 1000000000) |
24 | return 9; |
25 | else
|
26 | return 10; |
Dies ist für 32-Bit-Zahlen. Für größere oder kleiner Wertebereiche muss der Code natürlich angepasst werden.
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.
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 :-)
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,
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.
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.
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
> 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?
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
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. ;-)
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?
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.
Beitrag #5088904 wurde von einem Moderator gelöscht.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.