Ich würde gerne wissen, wie ich die Länge einer ganzen Zahl in C finden kann.
Zum Beispiel:
- 1 => 1
- 25 => 2
- 12512 => 5
- 0 => 1
usw.
Wie kann ich das in C machen?
marabunta2048
Ich würde gerne wissen, wie ich die Länge einer ganzen Zahl in C finden kann.
Zum Beispiel:
usw.
Wie kann ich das in C machen?
Jordan Lewis
Warum nehmen Sie nicht einfach den Basis-10-Log des Absolutwerts der Zahl, runden ihn ab und addieren eins? Dies funktioniert für positive und negative Zahlen, die nicht 0 sind, und vermeidet die Verwendung von String-Konvertierungsfunktionen.
Das log10
, abs
und floor
Funktionen werden bereitgestellt von math.h
. Zum Beispiel:
int nDigits = floor(log10(abs(the_integer))) + 1;
Sie sollten dies in eine Klausel packen, die dies sicherstellt the_integer != 0
seit log10(0)
kehrt zurück -HUGE_VAL
entsprechend man 3 log
.
Außerdem möchten Sie möglicherweise eins zum Endergebnis hinzufügen, wenn die Eingabe negativ ist, wenn Sie an der Länge der Zahl einschließlich ihres negativen Vorzeichens interessiert sind.
int nDigits = Math.floor(Math.log10(Math.abs(the_integer))) + 1;
NB Die Fließkomma-Natur der Berechnungen, die bei dieser Methode verwendet werden, kann dazu führen, dass sie langsamer ist als ein direkterer Ansatz. In den Kommentaren zu Kangkans Antwort finden Sie einige Diskussionen zur Effizienz.
Eigentlich sollten Sie floor verwenden und stattdessen 1 hinzufügen. Math.Ceil(Math.Log(99)) = 2 aber Math.Ceil(Math.Log(10)) = 1. Math.Floor(Math.Log(99)) + 1 = 2 und Math.Floor(Math. Protokoll (10)) = 2
– Sani Singh Huttunen
18. Juni 2010 um 9:20 Uhr
Die Frage zur Definition der Länge ist nicht ganz klar (Sie hätten also möglicherweise an “Anzahl der Ziffern ohne führende Nullen” denken können), aber ich würde erwarten, dass 0 und -1 eher 1 und 2 als Länge ihrer Zeichendarstellung zurückgeben als -2147483648 und 1.
– Peter Kirkham
18. Juni 2010 um 9:40 Uhr
@Pete Vielen Dank, dass Sie mich an die Domänenbeschränkung des Protokolls und den negativen Zahlenfall erinnert haben – ich habe meine Antwort bearbeitet.
– Jordan Lewis
18. Juni 2010 um 9:51 Uhr
+1 schön und kurz – das ist meine bevorzugte Antwort, auch wenn es die langsamste ist – schließlich ist der Geschwindigkeitsunterschied nicht groß und diese Art von Code ist sehr unwahrscheinlich, dass es sich um eine Leistung handelt. Engpass sowieso.
– Eamon Nerbonne
18. Juni 2010 um 13:20 Uhr
Dies funktioniert nicht für 999999999999999999, eine C-Ganzzahl, die in einen größeren Double-Wert konvertiert wird und somit eine fehlerhafte Anzahl von Ziffern erzeugt. Das OP hat es nicht spezifiziert int
nur eine ganze Zahl.
– chqrlie
23. November 2015 um 23:08 Uhr
Eamon Nerbonne
Bei Interesse an einer schnell und sehr einfach Lösung, die folgende könnte am schnellsten sein (dies hängt von der Wahrscheinlichkeitsverteilung der fraglichen Zahlen ab):
int lenHelper(unsigned x) {
if (x >= 1000000000) return 10;
if (x >= 100000000) return 9;
if (x >= 10000000) return 8;
if (x >= 1000000) return 7;
if (x >= 100000) return 6;
if (x >= 10000) return 5;
if (x >= 1000) return 4;
if (x >= 100) return 3;
if (x >= 10) return 2;
return 1;
}
int printLen(int x) {
return x < 0 ? lenHelper(-x) + 1 : lenHelper(x);
}
Während es vielleicht keine Preise für die genialste Lösung gewinnt, ist es trivial zu verstehen und auch trivial auszuführen – also ist es schnell.
Auf einem Q6600 mit MSC habe ich dies mit der folgenden Schleife bewertet:
int res = 0;
for(int i = -2000000000; i < 2000000000; i += 200) res += printLen(i);
Diese Lösung dauert 0,062 s, die zweitschnellste Lösung von Pete Kirkham mit einem Smart-Logarithmus-Ansatz dauert 0,115 s – fast doppelt so lange. Bei Zahlen um 10000 und darunter ist das Smart-Log jedoch schneller.
Auf Kosten der Klarheit können Sie Smart-Log zuverlässiger schlagen (zumindest auf einem Q6600):
int lenHelper(unsigned x) {
// this is either a fun exercise in optimization
// or it's extremely premature optimization.
if(x >= 100000) {
if(x >= 10000000) {
if(x >= 1000000000) return 10;
if(x >= 100000000) return 9;
return 8;
}
if(x >= 1000000) return 7;
return 6;
} else {
if(x >= 1000) {
if(x >= 10000) return 5;
return 4;
} else {
if(x >= 100) return 3;
if(x >= 10) return 2;
return 1;
}
}
}
Diese Lösung dauert bei großen Zahlen immer noch 0,062 s und verschlechtert sich bei kleineren Zahlen auf etwa 0,09 s – in beiden Fällen schneller als der Smart-Log-Ansatz. (gcc macht schnelleren Code; 0,052 für diese Lösung und 0,09 s für den Smart-Log-Ansatz).
Ich schaudere, wenn ich daran denke, wie die zweite Version aussehen würde, die vollständig mit dem ternären Operator geschrieben wurde …
– Eamon Nerbonne
18. Juni 2010 um 13:22 Uhr
Wenn dies verwendet würde, um lange Listen von Zahlen zu kauen, würde die Menge an Verzweigungscode Chaos mit der CPU verursachens branch prediction and not produce the fastest execution I
Ich habe Angst.
– Lloyd Crawley
23. Oktober 2013 um 8:52 Uhr
In meinem Benchmark ist es immer noch die schnellste Lösung – beachten Sie, dass alle anderen integralen Lösungen auch mehrere Zweige benötigen, und die einzige wirkliche Alternative eine Int-to-Double-Konvertierung mit einem Gleitkommaprotokoll ist (was, wie sich herausstellt, auch nicht billig ist). .
– Eamon Nerbonne
23. Oktober 2013 um 16:15 Uhr
@earthdan: Diese Lösung ist in Ordnung, aber aufgrund der Teilungen ziemlich langsam. Es verwendet auch immer mehr Zweige als die zweite Version dieses Codes und im Durchschnitt mehr als die erste hier gepostete Lösung. Außerdem ist diese Lösung ziemlich schlau (auf eine schlechte Art und Weise), da der Grund, warum sie funktioniert, nicht ganz offensichtlich ist. Wenn Sie eine kurze und offensichtliche Lösung wünschen, verwenden Sie stackoverflow.com/a/3068412/42921; Wenn Sie eine schnelle und offensichtliche Lösung wünschen, verwenden Sie diese. Kann mir den Anwendungsfall für stackoverflow.com/a/6655759/2382629 nicht vorstellen (obwohl es natürlich eine lustige intellektuelle Übung ist!)
– Eamon Nerbonne
17. März 2014 um 12:55 Uhr
zed_0xff
int get_int_len (int value){
int l=1;
while(value>9){ l++; value/=10; }
return l;
}
und der zweite funktioniert auch für negative Zahlen:
int get_int_len_with_negative_too (int value){
int l=!value;
while(value){ l++; value/=10; }
return l;
}
Ich mag das. Keine temporären Zeichenpuffer mit Annahmen über die Größe.
– Noufal Ibrahim
18. Juni 2010 um 9:13 Uhr
Schnell und elegant funktioniert dies jedoch nicht für negative Zahlen. Ich weiß nicht, ob das ein Problem für das Frageposter ist
– Jamie Wong
18. Juni 2010 um 9:16 Uhr
es wird. Versuche es. es wird 1 zurückgegeben
– zed_0xff
19. Juni 2010 um 10:10 Uhr
Du hast Recht – es wird in der Tat :-). Es wäre für mich klarer (und nicht langsamer), diesen Fall eher über eine if-Rückgabe als über eine Negation zu unterscheiden.
– Eamon Nerbonne
21. Juni 2010 um 7:54 Uhr
Sie können eine Funktion wie folgt schreiben:
unsigned numDigits(const unsigned n) {
if (n < 10) return 1;
return 1 + numDigits(n / 10);
}
Fritz G. Mehner
Länge von n:
length = ( i==0 ) ? 1 : (int)log10(n)+1;
Sie sollten wahrscheinlich das Runden über Casting vermeiden und stattdessen einen expliziteren (auch als portierbaren und konsistenten) Rundungsansatz wählen.
– Chris Lutz
18. Juni 2010 um 9:18 Uhr
wie ist casting
umgesetzt? wie kann eine funktion wie boden realisiert werden? (Wir gehen von einem Prozessor mit IEEE in Hardware oder durch einen mathematischen Coprozessor oder die Verfügbarkeit von Softwarefunktionen aus, um dieselbe Funktion auszuführen, die normalerweise auf fp-fähigen Prozessoren vorhanden ist) … am Ende (int) ist portabel und konsistent in die meisten Fälle (ich wage zu sagen, alle Fälle, um die wir uns normalerweise kümmern)
– Shin Takezou
18. Juni 2010 um 9:48 Uhr
Wie in anderen Beiträgen erwähnt, schlägt dies fehl, wenn n = 0 ist
– Jamie Wong
18. Juni 2010 um 9:59 Uhr
@Lutz: Welche Art von Portabilität kaufen Sie, wenn Sie davon ausgehen, dass das Casting von Double nach Int nicht definiert ist? Gibt es eigentlich eine entsprechende Plattform wo das der Fall ist?
– Eamon Nerbonne
18. Juni 2010 um 13:34 Uhr
@Chris Lutz Wenn es sich um eine standardkonforme C-Implementierung handelt, gehorcht sie Wenn ein endlicher Wert vom Typ Real Floating in einen anderen Integer-Typ als _Bool konvertiert wird, wird der Bruchteil verworfen (dh der Wert wird in Richtung Null gekürzt).
– Peter Kirkham
18. Juni 2010 um 17:44 Uhr
sam hocevar
Ein richtiges snprintf
Implementierung:
int count = snprintf(NULL, 0, "%i", x);
Sie sollten wahrscheinlich das Runden über Casting vermeiden und stattdessen einen expliziteren (auch als portierbaren und konsistenten) Rundungsansatz wählen.
– Chris Lutz
18. Juni 2010 um 9:18 Uhr
wie ist casting
umgesetzt? wie kann eine funktion wie boden realisiert werden? (Wir gehen von einem Prozessor mit IEEE in Hardware oder durch einen mathematischen Coprozessor oder die Verfügbarkeit von Softwarefunktionen aus, um dieselbe Funktion auszuführen, die normalerweise auf fp-fähigen Prozessoren vorhanden ist) … am Ende (int) ist portabel und konsistent in die meisten Fälle (ich wage zu sagen, alle Fälle, um die wir uns normalerweise kümmern)
– Shin Takezou
18. Juni 2010 um 9:48 Uhr
Wie in anderen Beiträgen erwähnt, schlägt dies fehl, wenn n = 0 ist
– Jamie Wong
18. Juni 2010 um 9:59 Uhr
@Lutz: Welche Art von Portabilität kaufen Sie, wenn Sie davon ausgehen, dass das Casting von Double nach Int nicht definiert ist? Gibt es eigentlich eine entsprechende Plattform wo das der Fall ist?
– Eamon Nerbonne
18. Juni 2010 um 13:34 Uhr
@Chris Lutz Wenn es sich um eine standardkonforme C-Implementierung handelt, gehorcht sie Wenn ein endlicher Wert vom Typ Real Floating in einen anderen Integer-Typ als _Bool konvertiert wird, wird der Bruchteil verworfen (dh der Wert wird in Richtung Null gekürzt).
– Peter Kirkham
18. Juni 2010 um 17:44 Uhr
IVlad
Die Anzahl der Ziffern einer ganzen Zahl x
ist gleich 1 + log10(x)
. Sie können also Folgendes tun:
#include <math.h>
#include <stdio.h>
int main()
{
int x;
scanf("%d", &x);
printf("x has %d digits\n", 1 + (int)log10(x));
}
Oder Sie können eine Schleife ausführen, um die Ziffern selbst zu zählen: Führen Sie eine ganzzahlige Division durch 10 durch, bis die Zahl 0 ist:
int numDigits = 0;
do
{
++numDigits;
x = x / 10;
} while ( x );
Bei der Rückkehr muss man etwas aufpassen 1
wenn die ganze Zahl ist 0
in der ersten Lösung und Sie möchten vielleicht auch negative ganze Zahlen behandeln (arbeiten Sie mit -x
wenn x < 0
).
Ja, schön einfach do
Schleife.
– chux – Wiedereinsetzung von Monica
23. November 2015 um 23:07 Uhr
Was ist die Definition von “Länge”, wenn die Ganzzahl 0 ist? Negativ?
– kennytm
18. Juni 2010 um 9:11 Uhr
Siehe stackoverflow.com/questions/679602/…. Es ist fast ein Duplikat, aber nicht genau, da es sich um eine .NET-Frage handelt.
– ChrisF
♦
18. Juni 2010 um 9:36 Uhr
Die richtige Frage ist nicht die Länge der Ganzzahl, sondern die minimale Anzahl von Dezimalstellen, die benötigt wird, um diese Zahl darzustellen (in einem C int enthalten). log10 ist dein Freund: log10(10000) = 4, +1 die Anzahl der Stellen (log10 muss abgeschnitten werden)… wenn die Zahl negativ ist, brauchst du eins mehr für das – Symbol, wenn du es zählen willst, und log10(-num) (da Log einer negativen Zahl “problematisch” ist).
– Shin Takezou
18. Juni 2010 um 9:41 Uhr
Wie sicher bist du dir das?
log10(10000)
wird 4 und nicht 3,999999 zurückgeben …?– Keith Thompson
29. August 2011 um 5:58 Uhr
Hmm. Experiment zeigt das
log10(10**n)
liefert den genauen Wert für Zehnerpotenzen von 1 bis 2**19, zumindest mit gcc und glibc. Aber ich würde mich nicht bei allen Implementierungen darauf verlassen. (**
bedeutet Potenzierung; Es gibt keinen solchen Operator in C.)– Keith Thompson
29. August 2011 um 6:02 Uhr