Ich habe einmal eine verwandte Frage gestellt: Wie kann man die erste Ziffer in einem int bekommen? Viele der gleichen Methoden wie unten wurden in den Antworten der Menschen verwendet. Hier ist der Link für den Fall, dass er für Ihre Aufgabe relevant ist [ stackoverflow.com/questions/701322/]
Dinah
Qualifiziert sich die Inline-Montage?
György Andrasek
1
Während sich alle diese Antworten auf Basis 10 beziehen, ist es ziemlich einfach zu ändern, um das Ergebnis für jede gewünschte Basis zu berechnen.
Ira Baxter
Antworten:
106
Nun, der effizienteste Weg, vorausgesetzt Sie kennen die Größe der Ganzzahl, wäre eine Suche. Sollte schneller sein als der viel kürzere logarithmusbasierte Ansatz. Wenn Sie das '-' nicht zählen möchten, entfernen Sie die + 1.
// generic solutiontemplate<class T>int numDigits(T number){int digits =0;if(number <0) digits =1;// remove this line if '-' counts as a digitwhile(number){
number /=10;
digits++;}return digits;}// partial specialization optimization for 32-bit numberstemplate<>int numDigits(int32_t x){if(x == MIN_INT)return10+1;if(x <0)return numDigits(-x)+1;if(x >=10000){if(x >=10000000){if(x >=100000000){if(x >=1000000000)return10;return9;}return8;}if(x >=100000){if(x >=1000000)return7;return6;}return5;}if(x >=100){if(x >=1000)return4;return3;}if(x >=10)return2;return1;}// partial-specialization optimization for 8-bit numberstemplate<>int numDigits(char n){// if you have the time, replace this with a static initialization to avoid// the initial overhead & unnecessary branchstaticchar x[256]={0};if(x[0]==0){for(char c =1; c !=0; c++)
x[c]= numDigits((int32_t)c);
x[0]=1;}return x[n];}
Wahrscheinlich schneller als meine Antwort, gut gemacht. Wenn Sie für zusätzliche Effizienz wissen, dass Ihre Eingangszahlen meistens klein sind (ich schätze weniger als 100.000), kehren Sie die Tests um: if (x <10) return 1; wenn (x <100) 2 zurückgibt; usw., so dass die Funktion weniger Tests durchführt und schneller beendet wird.
Squelart
29
Oder ordnen Sie die if-Anweisungen neu an und verschachteln Sie sie, um eine binäre Suche anstelle einer linearen Suche durchzuführen.
Dave4420
1
Das ist keine gute Idee. Was passiert, wenn die Architektur auf 256-Bit-Ganzzahlen erweitert wird? Sie müssen daran denken, diesen Code erneut zu ändern. Im wirklichen Leben wird dies nicht passieren, und dies wird wahrscheinlich verwendet, um einen Puffer mit der richtigen Größe zu erstellen, den Sie jetzt für alle Arten von Puffer-Over-Run-Problemen bei größeren Architekten öffnen.
Martin York
3
Unter der Annahme einer gleichmäßigen Verteilung der Zahlen kann die umgekehrte lineare Suche (von maximal bis 1) im Durchschnitt schneller sein als die binäre Suche, da es mit N Ziffern viel mehr Zahlen gibt als mit N-1 Ziffern graphics.stanford.edu/~ Seander /…
fa.
6
Ich würde mir keine Sorgen um 256- oder 128-Bit-Ganzzahlen machen. Wenn Sie nicht die Anzahl der Elektronen im Universum zählen müssen (10 ^ 78, als ich es das letzte Mal getan habe), sind 64 Bit ziemlich gut. 32-Bit-Maschinen haben ~ ~ 15 Jahre gedauert. Ich würde vermuten, dass 64-Bit-Maschinen viel länger halten. Für größere Zahlen ist die Multipräzisionsarithmetik in Ordnung, und ich bezweifle, dass die Effizienz der Berechnung der Ziffernzahl von Bedeutung ist.
Ira Baxter
74
Der einfachste Weg ist:
unsignedGetNumberOfDigits(unsigned i){return i >0?(int) log10 ((double) i)+1:1;}
log10 ist in <cmath>oder definiert <math.h>. Sie müssen dies profilieren, um zu sehen, ob es schneller ist als alle anderen hier veröffentlichten. Ich bin mir nicht sicher, wie robust dies in Bezug auf die Gleitkommapräzision ist. Außerdem ist das Argument nicht vorzeichenbehaftet, da negative Werte und Protokoll nicht wirklich gemischt werden.
Für 32-Bit-Ints und 56-Bit-Floats funktioniert dies wahrscheinlich. Wenn die Eingabe lang ist (64 Bit), können die 56 Bit des Protokolls mit doppelter Genauigkeit dazu führen, dass dies bei Werten nahe großen Werten von 10 ^ n zu einer falschen Antwort führt. Erwarten Sie Probleme über 2 ^ 50.
Ira Baxter
1
Es stellt sich auch die Frage, wie genau die Protokollfunktionen sind. Ich habe nicht überprüft, wie genau sie in modernen Bibliotheken sind, und würde nicht gerne blind darauf vertrauen, dass sie zu einem Teil einer Milliarde gut sind.
David Thornley
@DavidThornley: Protokoll- oder andere mathematische Funktionen sind absolut präzise, sofern sie nicht in der Compiler-Befehlszeile angegeben sind. Einige werden zur Kompilierungszeit in x86-Intrinsics konvertiert. Einige existieren nicht und werden sich zu Formeln bestehender Intrinsics erweitern. Wenn -fpfastSie beispielsweise verwenden, können Sie die Verwendung von SSE-Instrumenten anstelle von x87 sehen, was weniger Garantie für die Präzision IIRC bietet. aber standardmäßig kein problem.
v.oddou
@ DavidThornley: Es ist mehr als Präzision. Die Frage ist, ob garantiert ist, dass log10 (10 ^ k) ≥ k für alle relevanten k ist oder nicht. Das heißt, es ist garantiert, dass jeder unvermeidliche Rundungsfehler in die richtige Richtung geht. k + eps funktioniert daher, k - eps nicht. Und "Perfekt präzise" ist naiv.
gnasher729
1
Der Test i> 0 konnte auf i> 9
Pat
60
Vielleicht habe ich die Frage falsch verstanden, aber tut das nicht?
Dies kann schneller sein oder auch nicht als der von mir gewählte Ansatz der ungerollten Schleife - Sie müssten den Unterschied profilieren (sollte auf lange Sicht vernachlässigbar sein).
Vitali
Einverstanden, Profiling ist der einzige Weg, um wirklich sicher zu wissen! Ich habe meine Antwort mit diesem Kommentar aktualisiert, da die Antwort von Ben S für Ceil (log10 ()) verschwunden ist.
Squelart
11
Praktischer Witz: Dies ist der effizienteste Weg (die Anzahl der Ziffern wird zur Kompilierungszeit berechnet):
template<unsignedlonglong N,size_t base=10>struct numberlength
{enum{ value =1+ numberlength<N/base, base>::value };};template<size_t base>struct numberlength<0, base>{enum{ value =0};};
Kann nützlich sein, um die Breite zu bestimmen, die für das Zahlenfeld bei Formatierungen, Eingabeelementen usw. erforderlich ist.
Erstens funktioniert Ihre Lösung für 0 nicht. Zweitens ist Ihre Lösung nicht auf den allgemeinen Fall einer Variablen anwendbar. Drittens, wenn Sie ein konstantes Literal verwenden, wissen Sie bereits, wie viele Ziffern es hat.
Vitali
Es funktioniert auch für 0. Es funktioniert auch für jede Basis. Der Rest sind gültige Punkte, die ich bereits skizziert habe.
blinnov.com
3
Ich glaube nicht, dass es tatsächlich so ist. Es schlägt auf 0und auch auf Basis fehl 1:) und gibt Division durch Null Fehler, wenn die Basis als gegeben ist 0. Es kann jedoch behoben werden. Wie auch immer, ich suche nicht nach einem sehr alten Beitrag, also tut mir leid, ich denke nur, dass dies kein Witz sein muss und tatsächlich nützlich sein könnte.
tjm
9
Unter Bit Twiddling Hacks finden Sie eine viel kürzere Version der Antwort, die Sie akzeptiert haben. Es hat auch den Vorteil, dass Sie die Antwort früher finden, wenn Ihre Eingabe normal verteilt ist, indem Sie zuerst die großen Konstanten überprüfen. (v >= 1000000000)fängt 76% der Werte ab, sodass die Überprüfung im Durchschnitt schneller ist.
Es ist unklar, ob das Bit-Twiddling tatsächlich schneller ist. Selbst im schlimmsten Fall erfordert mein modifizierter Ansatz 4 Vergleiche (möglicherweise kann ich ihn auf 3 reduzieren, wenn ich die Partitionierung weiter untersuche, obwohl dies unwahrscheinlich erscheint). Ich bezweifle ernsthaft, dass dies durch arithmetische Operationen + Speicherlasten übertroffen wird (obwohl diese bei ausreichendem Zugriff im CPU-Cache verschwinden). Denken Sie daran, dass sie in dem Beispiel, das sie geben, auch die Protokollbasis 2 als abstrakte IntegerLogBase2-Funktion ausblenden (was selbst eigentlich nicht billig ist).
Vitali
Ja, wenn die Nummern normal verteilt sind, ist die Überprüfung der Reihenfolge schneller. Es hat jedoch den entarteten Fall, im schlimmsten Fall doppelt so langsam zu sein. Der nach Anzahl der Ziffern anstelle des Eingabebereichs partitionierte Ansatz bedeutet, dass das Verhalten keinen entarteten Fall aufweist und immer eine optimale Leistung erbringt. Denken Sie außerdem daran, dass Sie davon ausgehen, dass die Zahlen gleichmäßig verteilt sind. Tatsächlich folgen sie eher einer Verteilung im Zusammenhang mit <a href=" en.wikipedia.org/wiki/…> , wie ich vermute.
Vitali
Die Bit-Twiddling-Hacks sind nicht schneller als die oben beschriebene Partitionsmethode, aber sie sind möglicherweise interessant, wenn Sie hier einen allgemeineren Fall wie einen Float hatten.
Corwin Joy
1
Das Bit Twiddling Hacks schlägt einen Weg vor, um das int log10 zu erhalten, wenn das int log2 gegeben ist. Es werden verschiedene Möglichkeiten vorgeschlagen, um int log2 zu erhalten, wobei meist nur wenige Vergleiche / Verzweigungen erforderlich sind. (Ich denke, Sie unterschätzen die Kosten für unvorhersehbare Filialen, Vitali). Wenn Sie Inline x86 asm verwenden können, gibt Ihnen der BSR-Befehl das int log2 eines Werts (dh den Bitindex eines höchstwertigen gesetzten Bits). Bei K8 (Latenz von 10 Zyklen) ist es etwas langsam, bei Core 2 (Latenz von 2 oder 3 Zyklen) jedoch schnell. Auch auf K8 kann durchaus schneller sein als die Vergleiche.
Peter Cordes
Auf K10 zählt lzcnt führende Nullen, daher ist es fast dasselbe wie bsr, aber eine Eingabe von 0 ist kein Sonderfall mehr mit undefinierten Ergebnissen. Latenzen: BSR: 4, LZCNT: 2.
Peter Cordes
8
In String konvertieren und dann integrierte Funktionen verwenden
Dies ist zwar in Bezug auf LOCs effizient, wie in der akzeptierten Antwort angegeben, aber die Verwendung von Protokoll wird wahrscheinlich nicht die beste Leistung bringen.
Ian
@ Ian Warum nicht? Es sind nur ein paar FPU-Anweisungen. Meilen besser als alle Zweige und Schleifen in anderen Antworten.
Marquis von Lorne
5
Ein vorheriges Poster schlug eine Schleife vor, die durch 10 geteilt wird. Da Multiplikationen auf modernen Maschinen viel schneller sind, würde ich stattdessen den folgenden Code empfehlen:
int digits =1, pten=10;while( pten <= number ){ digits++; pten*=10;}
Der Teufel steckt im Detail - was passiert mit sagen std :: numeric_limits <int> :: max == number - es könnte ein Problem beim Beenden geben
pgast
2
Wenn Sie sich über diesen Fall Sorgen machen, können Sie eine zusätzliche IF hinzufügen, um sehr große Werte zu verarbeiten.
Ira Baxter
2
Ich sollte beachten, dass auf x86-Maschinen eine Multiplikation mit einer Konstanten 10, wie sie in diesem Fall verwendet wird, vom Compiler tatsächlich als LEA R2, [8 * R1 + R1], ADD R1, R2 implementiert werden kann, sodass maximal 2 Takte benötigt werden. Multiplikationen mit Variablen dauern zehn Uhren, und Divisionen sind viel schlimmer.
Ira Baxter
Der Vorteil des Divide-Ansatzes besteht darin, dass Sie sich keine Gedanken über negative Zahlen machen müssen.
Johannes Schaub - litb
1
Ich habe den Multiplikationsansatz (mit einer Fabs, um das Vorzeichenproblem zu beseitigen) mit dem Divisionsansatz verglichen. Auf meiner Maschine ist der Divisionsansatz um Faktor 2 langsamer als der Multiplikationsansatz. Ob dies eine vorzeitige Optimierung ist oder nicht, hängt wirklich davon ab, wo und wie dies aufgerufen wird.
Spacemoose
5
Die ppc-Architektur hat eine Bitzählanweisung. Damit können Sie die Protokollbasis 2 einer positiven Ganzzahl in einem einzigen Befehl bestimmen. Zum Beispiel wäre 32 Bit:
#define log_2_32_ppc(x)(31-__cntlzw(x))
Wenn Sie mit einer kleinen Fehlerquote bei großen Werten umgehen können, können Sie diese mit ein paar weiteren Anweisungen in die Protokollbasis 10 konvertieren:
Dies ist plattformspezifisch und leicht ungenau, beinhaltet jedoch auch keine Verzweigungen, Unterteilungen oder Konvertierungen in Gleitkommazahlen. Alles hängt davon ab, was Sie brauchen.
Ich kenne die ppc-Anweisungen nur aus der Hand, aber andere Architekturen sollten ähnliche Anweisungen haben.
Diese Lösung berechnet log2 (15) = 4 Bit und log2 (9) = 4 Bit. Für 15 und 9 ist jedoch eine unterschiedliche Anzahl von Dezimalstellen zum Drucken erforderlich. Es funktioniert also nicht, es sei denn, es macht Ihnen nichts aus, wenn Ihre Zahlen manchmal mit zu vielen Ziffern gedruckt werden. In diesem Fall können Sie jedoch immer "10" als Antwort für int auswählen.
Ira Baxter
Wow, eine ungefähre Funktion. Nett.
Doug65536
4
#include<iostream>#include<math.h>usingnamespace std;int main(){double num;int result;
cout<<"Enter a number to find the number of digits, not including decimal places: ";
cin>>num;
result =((num<=1)?1: log10(num)+1);
cout<<"Number of digits "<<result<<endl;return0;}
Dies ist wahrscheinlich der einfachste Weg, um Ihr Problem zu lösen, vorausgesetzt, Sie kümmern sich nur um Ziffern vor der Dezimalstelle und weniger als 10 ist nur eine Ziffer.
Ich mag Ira Baxters Antwort. Hier ist eine Vorlagenvariante, die die verschiedenen Größen behandelt und sich mit den maximalen Ganzzahlwerten befasst (aktualisiert, um den Check für die Obergrenze aus der Schleife zu heben):
#include<boost/integer_traits.hpp>template<typename T> T max_decimal(){
T t =1;for(unsigned i = boost::integer_traits<T>::digits10; i;--i)
t *=10;return t;}template<typename T>unsigned digits(T v){if(v <0) v =-v;if(max_decimal<T>()<= v)return boost::integer_traits<T>::digits10 +1;unsigned digits =1;
T boundary =10;while(boundary <= v){
boundary *=10;++digits;}return digits;}
Um die verbesserte Leistung zu erzielen, indem der zusätzliche Test aus der Schleife gehoben wird, müssen Sie max_decimal () spezialisieren, um Konstanten für jeden Typ auf Ihrer Plattform zurückzugeben. Ein ausreichend magischer Compiler könnte den Aufruf von max_decimal () auf eine Konstante optimieren, aber die Spezialisierung ist heute bei den meisten Compilern besser. Derzeit ist diese Version wahrscheinlich langsamer, da max_decimal mehr kostet als die aus der Schleife entfernten Tests.
Ich werde das alles als Übung für den Leser hinterlassen.
Sie möchten, dass die Prüfung der Obergrenze zuerst als separate Bedingung getestet wird, damit Sie sie nicht bei jeder Schleifeniteration überprüfen.
Ira Baxter
Sie möchten nicht 10 in diese Temperatur t setzen. Der Compiler könnte das Multiplizieren mit t als Multiplikation mit einer reellen Variablen betrachten und einen Allzweck-Multiplikationsbefehl verwenden. Wenn Sie stattdessen "result * = 10;" Der Compiler wird sicherlich die Multiplikation mit der Konstanten 10 bemerken und diese mit ein paar Verschiebungen und Additionen implementieren, was extrem schnell ist.
Ira Baxter
Wenn die Multiplikation mit t immer eine Multiplikation mit 10 wäre, könnte der Compiler die Stärke reduzieren. In diesem Fall ist t jedoch nicht schleifeninvariant (es ist nur eine Modifikation einer ganzzahligen Potenzfunktion, die ich herumliegen hatte). Die richtige Optimierung ist die Spezialisierung auf den Typ, der eine Konstante zurückgibt. Sie haben jedoch Recht, dass in diesem Fall die Funktion immer 10 auf eine Potenz erhöht, nicht eine beliebige Ganzzahl auf eine Potenz, und eine Verringerung der Stärke einen guten Gewinn ergibt. Also habe ich eine Änderung vorgenommen ... Dieses Mal bleiben weitere Änderungen wirklich als Übung übrig! (Stapelüberlauf ist eine große
Zeitsenke
1
#include<stdint.h>// uint32_t [available since C99]/// Determine the number of digits for a 32 bit integer./// - Uses at most 4 comparisons./// - (cX) 2014 [email protected]/// - \see http://stackoverflow.com/questions/1489830/#27669966/** #d == Number length vs Number of comparisons == #c
\code
#d | #c #d | #c
---+--- ---+---
10 | 4 5 | 4
9 | 4 4 | 4
8 | 3 3 | 3
7 | 3 2 | 3
6 | 3 1 | 3
\endcode
*/unsignedNumDigits32bs(uint32_t x){return// Num-># Digits->[0-9] 32->bits bs->Binary Search( x >=100000u// [6-10] [1-5]?// [6-10]( x >=10000000u// [8-10] [6-7]?// [8-10]( x >=100000000u// [9-10] [8]?// [9-10]( x >=1000000000u// [10] [9]?10:9):8):// [6-7]( x >=1000000u// [7] [6]?7:6)):// [1-5]( x >=100u// [3-5] [1-2]?// [3-5]( x >=1000u// [4-5] [3]?// [4-5]( x >=10000u// [5] [4]?5:4):3):// [1-2]( x >=10u// [2] [1]?2:1)));}
Noch ein Code-Snippet, das im Grunde das Gleiche wie Vitali macht, aber die binäre Suche verwendet. Das Powers-Array wird nur einmal pro Instanz vom Typ ohne Vorzeichen verzögert initialisiert. Die signierte Überladung sorgt für das Minuszeichen.
#include<limits>#include<type_traits>#include<array>template<class T>size_tNumberOfDecPositions( T v,typename std::enable_if<std::is_unsigned<T>::value>::type*=0){typedef std::array<T,std::numeric_limits<T>::digits10+1> array_type;static array_type powers_of_10;if( powers_of_10.front()==0){
T n =1;for( T& i: powers_of_10 ){
i = n;
n *=10;}}size_t l =0, r = powers_of_10.size(), p;while( l+1< r ){
p =(l+r)/2;if( powers_of_10[p]<= v )
l = p;else
r = p;}return l +1;};template<class T>size_tNumberOfDecPositions( T v,typename std::enable_if<std::is_signed<T>::value>::type*=0){typedeftypename std::make_unsigned<T>::type unsigned_type;if( v <0)returnNumberOfDecPositions(static_cast<unsigned_type>(-v))+1;elsereturnNumberOfDecPositions(static_cast<unsigned_type>(v));}
Wenn sich jemand für eine weitere Optimierung interessiert, beachten Sie bitte, dass das erste Element des Potenzarrays niemals verwendet wird und das zweimal langezeigt +1wird.
Falls die Anzahl der Ziffern UND der Wert jeder Ziffernposition benötigt wird, verwenden Sie Folgendes:
int64_t= number, digitValue, digits =0;// or "int" for 32bitwhile(number !=0){
digitValue = number %10;
digits ++;
number /=10;}
digitgibt Ihnen den Wert an der Nummernposition an, die derzeit in der Schleife verarbeitet wird. Für die Nummer 1776 lautet der Ziffernwert beispielsweise:
6 in der 1. Schleife
7 in der 2. Schleife
7 in der 3. Schleife
1 in der 4. Schleife
Für die Ganzzahl 'X' möchten Sie die Anzahl der Stellen wissen. In Ordnung, ohne eine Schleife zu verwenden. Diese Lösung wird nur in einer Formel in einer Zeile angezeigt. Dies ist also die optimalste Lösung, die ich je für dieses Problem gesehen habe.
int x =1000;
cout<<numberOfDigits =1+floor(log10(x))<<endl ;
Schlägt für INT_MAX und auch für negative Zahlen fehl.
Ranu
@ranu schlägt für INT_MAX fehl wie? Wann wird das Argument in konvertiert double? Oder beziehen Sie sich auf eine unmögliche Ganzzahleingabe mit INT_MAX-Dezimalstellen? Was würde hier auch bei jeder anderen Antwort scheitern?
Marquis von Lorne
0
int numberOfDigits(int n){if(n<=9){return1;}return1+ numberOfDigits(n/10);}
Dies ist, was ich tun würde, wenn Sie es für Basis 10 wollen. Es ist ziemlich schnell und Sie werden wahrscheinlich keinen Stapel-Überlauf bekommen, wenn Sie ganze Zahlen zählen
int num,dig_quant =0;
cout<<"\n\n\t\t--Count the digits in Number--\n\n";
cout<<"Enter Number: ";
cin>>num;for(int i =1; i<=num; i*=10){if(num / i >0){
dig_quant +=1;}}
cout<<"\n"<<number<<" include "<<dig_quant<<" digit"
cout<<"\n\nGoodbye...\n\n";
Wenn schneller effizienter ist, ist dies eine Verbesserung gegenüber der Verbesserung von andrei alexandrescu . Seine Version war bereits schneller als der naive Weg (dividiert durch 10 bei jeder Ziffer). Die folgende Version ist zeitlich konstant und zumindest auf x86-64 und ARM für alle Größen schneller, belegt jedoch doppelt so viel Binärcode, sodass sie nicht so cachefreundlich ist.
Ich arbeitete an einem Programm, bei dem ich überprüfen musste, ob der Benutzer richtig geantwortet hatte, wie viele Ziffern in einer Zahl enthalten waren. Daher musste ich eine Methode entwickeln, um die Anzahl der Ziffern in einer Ganzzahl zu überprüfen. Es war relativ einfach zu lösen.
Natürlich könnte jede andere Implementierung eines geordneten Satzes verwendet werden, powers_and_maxund wenn bekannt wäre, dass es Clustering geben würde, aber keine Kenntnis darüber, wo sich der Cluster möglicherweise befindet, ist möglicherweise eine selbstanpassende Baumimplementierung am besten
int numberOfDigits(double number){if(number <0){
number*=-1;}int i=0;while(number > pow(10, i))
i++;
cout <<"This number has "<< i <<" digits"<< endl;return i;}
-1 Dies ist der gleiche Ansatz, den die erste Antwort sechs Jahre zuvor gegeben hat, und er fügt nichts hinzu (tatsächlich ist er bedeutend schlechter).
-4
Hier ist ein anderer Ansatz:
digits = sprintf(numArr,"%d", num);// where numArr is a char arrayif(num <0)
digits--;
Dies ist möglicherweise nicht effizient, nur etwas anderes als das, was andere vorgeschlagen haben.
Antworten:
Nun, der effizienteste Weg, vorausgesetzt Sie kennen die Größe der Ganzzahl, wäre eine Suche. Sollte schneller sein als der viel kürzere logarithmusbasierte Ansatz. Wenn Sie das '-' nicht zählen möchten, entfernen Sie die + 1.
quelle
Der einfachste Weg ist:
log10 ist in
<cmath>
oder definiert<math.h>
. Sie müssen dies profilieren, um zu sehen, ob es schneller ist als alle anderen hier veröffentlichten. Ich bin mir nicht sicher, wie robust dies in Bezug auf die Gleitkommapräzision ist. Außerdem ist das Argument nicht vorzeichenbehaftet, da negative Werte und Protokoll nicht wirklich gemischt werden.quelle
-fpfast
Sie beispielsweise verwenden, können Sie die Verwendung von SSE-Instrumenten anstelle von x87 sehen, was weniger Garantie für die Präzision IIRC bietet. aber standardmäßig kein problem.Vielleicht habe ich die Frage falsch verstanden, aber tut das nicht?
quelle
Hinweis: "0" hat 0 Ziffern! Wenn Sie 0 benötigen, um eine Ziffer zu haben, verwenden Sie:
(Danke Kevin Fegan)
Verwenden Sie am Ende einen Profiler, um zu wissen, welche der hier aufgeführten Antworten auf Ihrem Computer schneller ist ...
quelle
Praktischer Witz: Dies ist der effizienteste Weg (die Anzahl der Ziffern wird zur Kompilierungszeit berechnet):
Kann nützlich sein, um die Breite zu bestimmen, die für das Zahlenfeld bei Formatierungen, Eingabeelementen usw. erforderlich ist.
quelle
0
und auch auf Basis fehl1
:) und gibt Division durch Null Fehler, wenn die Basis als gegeben ist0
. Es kann jedoch behoben werden. Wie auch immer, ich suche nicht nach einem sehr alten Beitrag, also tut mir leid, ich denke nur, dass dies kein Witz sein muss und tatsächlich nützlich sein könnte.Unter Bit Twiddling Hacks finden Sie eine viel kürzere Version der Antwort, die Sie akzeptiert haben. Es hat auch den Vorteil, dass Sie die Antwort früher finden, wenn Ihre Eingabe normal verteilt ist, indem Sie zuerst die großen Konstanten überprüfen.
(v >= 1000000000)
fängt 76% der Werte ab, sodass die Überprüfung im Durchschnitt schneller ist.quelle
In String konvertieren und dann integrierte Funktionen verwenden
quelle
quelle
Ein vorheriges Poster schlug eine Schleife vor, die durch 10 geteilt wird. Da Multiplikationen auf modernen Maschinen viel schneller sind, würde ich stattdessen den folgenden Code empfehlen:
quelle
Die ppc-Architektur hat eine Bitzählanweisung. Damit können Sie die Protokollbasis 2 einer positiven Ganzzahl in einem einzigen Befehl bestimmen. Zum Beispiel wäre 32 Bit:
Wenn Sie mit einer kleinen Fehlerquote bei großen Werten umgehen können, können Sie diese mit ein paar weiteren Anweisungen in die Protokollbasis 10 konvertieren:
Dies ist plattformspezifisch und leicht ungenau, beinhaltet jedoch auch keine Verzweigungen, Unterteilungen oder Konvertierungen in Gleitkommazahlen. Alles hängt davon ab, was Sie brauchen.
Ich kenne die ppc-Anweisungen nur aus der Hand, aber andere Architekturen sollten ähnliche Anweisungen haben.
quelle
Dies ist wahrscheinlich der einfachste Weg, um Ihr Problem zu lösen, vorausgesetzt, Sie kümmern sich nur um Ziffern vor der Dezimalstelle und weniger als 10 ist nur eine Ziffer.
quelle
Ich mag Ira Baxters Antwort. Hier ist eine Vorlagenvariante, die die verschiedenen Größen behandelt und sich mit den maximalen Ganzzahlwerten befasst (aktualisiert, um den Check für die Obergrenze aus der Schleife zu heben):
Um die verbesserte Leistung zu erzielen, indem der zusätzliche Test aus der Schleife gehoben wird, müssen Sie max_decimal () spezialisieren, um Konstanten für jeden Typ auf Ihrer Plattform zurückzugeben. Ein ausreichend magischer Compiler könnte den Aufruf von max_decimal () auf eine Konstante optimieren, aber die Spezialisierung ist heute bei den meisten Compilern besser. Derzeit ist diese Version wahrscheinlich langsamer, da max_decimal mehr kostet als die aus der Schleife entfernten Tests.
Ich werde das alles als Übung für den Leser hinterlassen.
quelle
quelle
Noch ein Code-Snippet, das im Grunde das Gleiche wie Vitali macht, aber die binäre Suche verwendet. Das Powers-Array wird nur einmal pro Instanz vom Typ ohne Vorzeichen verzögert initialisiert. Die signierte Überladung sorgt für das Minuszeichen.
Wenn sich jemand für eine weitere Optimierung interessiert, beachten Sie bitte, dass das erste Element des Potenzarrays niemals verwendet wird und das zweimal
l
angezeigt+1
wird.quelle
Falls die Anzahl der Ziffern UND der Wert jeder Ziffernposition benötigt wird, verwenden Sie Folgendes:
digit
gibt Ihnen den Wert an der Nummernposition an, die derzeit in der Schleife verarbeitet wird. Für die Nummer 1776 lautet der Ziffernwert beispielsweise:6 in der 1. Schleife
7 in der 2. Schleife
7 in der 3. Schleife
1 in der 4. Schleife
quelle
quelle
quelle
Für die Ganzzahl 'X' möchten Sie die Anzahl der Stellen wissen. In Ordnung, ohne eine Schleife zu verwenden. Diese Lösung wird nur in einer Formel in einer Zeile angezeigt. Dies ist also die optimalste Lösung, die ich je für dieses Problem gesehen habe.
quelle
double
? Oder beziehen Sie sich auf eine unmögliche Ganzzahleingabe mit INT_MAX-Dezimalstellen? Was würde hier auch bei jeder anderen Antwort scheitern?Dies ist, was ich tun würde, wenn Sie es für Basis 10 wollen. Es ist ziemlich schnell und Sie werden wahrscheinlich keinen Stapel-Überlauf bekommen, wenn Sie ganze Zahlen zählen
quelle
quelle
Wenn schneller effizienter ist, ist dies eine Verbesserung gegenüber der Verbesserung von andrei alexandrescu . Seine Version war bereits schneller als der naive Weg (dividiert durch 10 bei jeder Ziffer). Die folgende Version ist zeitlich konstant und zumindest auf x86-64 und ARM für alle Größen schneller, belegt jedoch doppelt so viel Binärcode, sodass sie nicht so cachefreundlich ist.
Benchmarks für diese Version vs alexandrescus Version auf meiner PR auf Facebook Torheit .
Funktioniert
unsigned
nichtsigned
.quelle
Ich arbeitete an einem Programm, bei dem ich überprüfen musste, ob der Benutzer richtig geantwortet hatte, wie viele Ziffern in einer Zahl enthalten waren. Daher musste ich eine Methode entwickeln, um die Anzahl der Ziffern in einer Ganzzahl zu überprüfen. Es war relativ einfach zu lösen.
Dies war meine Antwort, die derzeit mit Zahlen mit weniger als 10 ^ 1000 Stellen funktioniert (kann durch Ändern des Exponentenwerts geändert werden).
PS Ich weiß, dass diese Antwort zehn Jahre zu spät ist, aber ich bin 2020 hierher gekommen, damit andere Leute sie verwenden können.
quelle
wo in haben
powers_and_max
wir(10^n)-1
für allen
solche(10^n) <
std::numeric_limits<type>::max()
und
std::numeric_limits<type>::max()
in einem Array:Hier ist ein einfacher Test:
Natürlich könnte jede andere Implementierung eines geordneten Satzes verwendet werden,
powers_and_max
und wenn bekannt wäre, dass es Clustering geben würde, aber keine Kenntnis darüber, wo sich der Cluster möglicherweise befindet, ist möglicherweise eine selbstanpassende Baumimplementierung am bestenquelle
effektiver Weg
quelle
C ++ 11 Update der bevorzugten Lösung:
verhindert die Instanziierung von Vorlagen mit double et al. al.
quelle
quelle
Dies ist mein Weg, um das zu tun:
quelle
Hier ist ein anderer Ansatz:
Dies ist möglicherweise nicht effizient, nur etwas anderes als das, was andere vorgeschlagen haben.
quelle