par exemple,
n = 3432, result 4
n = 45, result 2
n = 33215, result 5
n = -357, result 3
Je suppose que je pourrais simplement le transformer en chaîne puis obtenir la longueur de la chaîne mais cela semble compliqué et bidouillé.
floor (log10 (abs (x))) + 1
L'approche récursive :-)
int numPlaces (int n) {
if (n < 0) return numPlaces ((n == INT_MIN) ? MAX_INT: -n);
if (n < 10) return 1;
return 1 + numPlaces (n / 10);
}
Ou itératif:
int numPlaces (int n) {
int r = 1;
if (n < 0) n = (n == INT_MIN) ? INT_MAX: -n;
while (n > 9) {
n /= 10;
r++;
}
return r;
}
Ou vitesse brute:
int numPlaces (int n) {
if (n < 0) n = (n == INT_MIN) ? INT_MAX : -n;
if (n < 10) return 1;
if (n < 100) return 2;
if (n < 1000) return 3;
if (n < 10000) return 4;
if (n < 100000) return 5;
if (n < 1000000) return 6;
if (n < 10000000) return 7;
if (n < 100000000) return 8;
if (n < 1000000000) return 9;
/* 2147483647 is 2^31-1 - add more ifs as needed
and adjust this final return as well. */
return 10;
}
Celles ci-dessus ont été modifiées pour mieux traiter MININT. Sur tous les systèmes étranges qui ne suivent pas raisonnable 2n règles de complément à deux pour les entiers, ils peuvent nécessiter des ajustements supplémentaires.
La version à vitesse brute surpasse en fait la version à virgule flottante, modifiée ci-dessous:
int numPlaces (int n) {
if (n == 0) return 1;
return floor (log10 (abs (n))) + 1;
}
Avec cent millions d'itérations, j'obtiens les résultats suivants:
Raw speed with 0: 0 seconds
Raw speed with 2^31-1: 1 second
Iterative with 2^31-1: 5 seconds
Recursive with 2^31-1: 6 seconds
Floating point with 1: 6 seconds
Floating point with 2^31-1: 7 seconds
En fait, cela m'a un peu surpris - je pensais que les puces Intel disposaient d'un FPU décent, mais je suppose que les opérations générales FP ne peuvent toujours pas rivaliser avec le code entier optimisé à la main.
Mise à jour suivant les suggestions de stormsoul:
Tester la solution multi-itérative avec stormsoul donne un résultat de 4 secondes. Bien que beaucoup plus rapide que la solution divide-itérative, elle ne correspond toujours pas à la solution optimisée if-statement.
Le choix des arguments dans un pool de 1 000 nombres générés aléatoirement a porté le délai d’expiration à la vitesse brute à 2 secondes. Par conséquent, bien qu’il puisse sembler avantageux de disposer du même argument à chaque fois, c’est toujours l’approche la plus rapide.
Compiler avec -O2 améliorait les vitesses mais pas les positions relatives (j'ai multiplié par dix le nombre d'itérations pour vérifier cela).
Toute analyse plus poussée devra s’intéresser sérieusement au fonctionnement interne de l’efficacité du processeur (différents types d’optimisation, utilisation des caches, prédiction de branche, du type de processeur dont vous disposez, de la température ambiante dans la pièce, etc.). gêne mon travail rémunéré :-). Cela a été une diversion intéressante mais, à un moment donné, le retour sur investissement pour l'optimisation devient trop petit pour avoir de l'importance. Je pense que nous avons suffisamment de solutions pour avoir répondu à la question (qui, après tout, ne concernait pas la rapidité).
Mise à jour ultérieure:
Ce sera ma dernière mise à jour de cette réponse, à l'exception des erreurs flagrantes qui ne dépendent pas de l'architecture. Inspiré par les efforts vaillants de stormsoul pour mesurer, je publie mon programme de test (modifié conformément au programme de test de stormsoul) ainsi que des exemples de chiffres pour toutes les méthodes indiquées dans les réponses fournies ici. N'oubliez pas que c'est sur une machine particulière, votre kilométrage peut varier en fonction du lieu où vous l'exécutez (c'est pourquoi je poste le code de test).
Faites avec comme vous voulez:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <limits.h>
#include <time.h>
#define numof(a) (sizeof(a) / sizeof(a[0]))
/* Random numbers and accuracy checks. */
static int rndnum[10000];
static int rt[numof(rndnum)];
/* All digit counting functions here. */
static int count_recur (int n) {
if (n < 0) return count_recur ((n == INT_MIN) ? INT_MAX : -n);
if (n < 10) return 1;
return 1 + count_recur (n / 10);
}
static int count_diviter (int n) {
int r = 1;
if (n < 0) n = (n == INT_MIN) ? INT_MAX : -n;
while (n > 9) {
n /= 10;
r++;
}
return r;
}
static int count_multiter (int n) {
unsigned int num = abs(n);
unsigned int x, i;
for (x=10, i=1; ; x*=10, i++) {
if (num < x)
return i;
if (x > INT_MAX/10)
return i+1;
}
}
static int count_ifs (int n) {
if (n < 0) n = (n == INT_MIN) ? INT_MAX : -n;
if (n < 10) return 1;
if (n < 100) return 2;
if (n < 1000) return 3;
if (n < 10000) return 4;
if (n < 100000) return 5;
if (n < 1000000) return 6;
if (n < 10000000) return 7;
if (n < 100000000) return 8;
if (n < 1000000000) return 9;
/* 2147483647 is 2^31-1 - add more ifs as needed
and adjust this final return as well. */
return 10;
}
static int count_revifs (int n) {
if (n < 0) n = (n == INT_MIN) ? INT_MAX : -n;
if (n > 999999999) return 10;
if (n > 99999999) return 9;
if (n > 9999999) return 8;
if (n > 999999) return 7;
if (n > 99999) return 6;
if (n > 9999) return 5;
if (n > 999) return 4;
if (n > 99) return 3;
if (n > 9) return 2;
return 1;
}
static int count_log10 (int n) {
if (n < 0) n = (n == INT_MIN) ? INT_MAX : -n;
if (n == 0) return 1;
return floor (log10 (n)) + 1;
}
static int count_bchop (int n) {
int r = 1;
if (n < 0) n = (n == INT_MIN) ? INT_MAX : -n;
if (n >= 100000000) {
r += 8;
n /= 100000000;
}
if (n >= 10000) {
r += 4;
n /= 10000;
}
if (n >= 100) {
r += 2;
n /= 100;
}
if (n >= 10)
r++;
return r;
}
/* Structure to control calling of functions. */
typedef struct {
int (*fnptr)(int);
char *desc;
} tFn;
static tFn fn[] = {
NULL, NULL,
count_recur, " recursive",
count_diviter, " divide-iterative",
count_multiter, " multiply-iterative",
count_ifs, " if-statements",
count_revifs, "reverse-if-statements",
count_log10, " log-10",
count_bchop, " binary chop",
};
static clock_t clk[numof (fn)];
int main (int c, char *v[]) {
int i, j, k, r;
int s = 1;
/* Test code:
printf ("%11d %d\n", INT_MIN, count_recur(INT_MIN));
for (i = -1000000000; i != 0; i /= 10)
printf ("%11d %d\n", i, count_recur(i));
printf ("%11d %d\n", 0, count_recur(0));
for (i = 1; i != 1000000000; i *= 10)
printf ("%11d %d\n", i, count_recur(i));
printf ("%11d %d\n", 1000000000, count_recur(1000000000));
printf ("%11d %d\n", INT_MAX, count_recur(INT_MAX));
/* */
/* Randomize and create random pool of numbers. */
srand (time (NULL));
for (j = 0; j < numof (rndnum); j++) {
rndnum[j] = s * Rand();
s = -s;
}
rndnum[0] = INT_MAX;
rndnum[1] = INT_MIN;
/* For testing. */
for (k = 0; k < numof (rndnum); k++) {
rt[k] = (fn[1].fnptr)(rndnum[k]);
}
/* Test each of the functions in turn. */
clk[0] = clock();
for (i = 1; i < numof (fn); i++) {
for (j = 0; j < 10000; j++) {
for (k = 0; k < numof (rndnum); k++) {
r = (fn[i].fnptr)(rndnum[k]);
/* Test code:
if (r != rt[k]) {
printf ("Mismatch error [%s] %d %d %d %d\n",
fn[i].desc, k, rndnum[k], rt[k], r);
return 1;
}
/* */
}
}
clk[i] = clock();
}
/* Print out results. */
for (i = 1; i < numof (fn); i++) {
printf ("Time for %s: %10d\n", fn[i].desc, (int)(clk[i] - clk[i-1]));
}
return 0;
}
N'oubliez pas que vous devez vous assurer d'utiliser la bonne ligne de commande pour la compiler. En particulier, vous pouvez avoir besoin de répertorier explicitement la bibliothèque mathématique pour que
log10()
fonctionne. La ligne de commande que j'ai utilisée sous Debian étaitgcc -o testprog testprog.c -lm
.
Et, en termes de résultats, voici le tableau de bord pour mon environnement:
Niveau d'optimisation 0:
Time for reverse-if-statements: 1704
Time for if-statements: 2296
Time for binary chop: 2515
Time for multiply-iterative: 5141
Time for divide-iterative: 7375
Time for recursive: 10469
Time for log-10: 26953
Niveau d'optimisation 3:
Time for if-statements: 1047
Time for binary chop: 1156
Time for reverse-if-statements: 1500
Time for multiply-iterative: 2937
Time for divide-iterative: 5391
Time for recursive: 8875
Time for log-10: 25438
La réponse la plus courte: snprintf(0,0,"%+d",n)-1
Pseudo-algorithme de recherche binaire pour obtenir aucun des chiffres de r dans v ..
if (v < 0 ) v=-v;
r=1;
if (v >= 100000000)
{
r+=8;
v/=100000000;
}
if (v >= 10000) {
r+=4;
v/=10000;
}
if (v >= 100) {
r+=2;
v/=100;
}
if( v>=10)
{
r+=1;
}
return r;
Divisez par 10 en boucle jusqu'à ce que le résultat atteigne zéro. Le nombre d'itérations correspondra au nombre de chiffres décimaux.
En supposant que vous vous attendiez à obtenir 0 chiffre dans une valeur nulle:
int countDigits( int value )
{
int result = 0;
while( value != 0 ) {
value /= 10;
result++;
}
return result;
}
Version à coût constant qui utilise l'assemblage x86 et une table de recherche:
int count_bsr(int i) {
struct {
int max;
int count;
} static digits[32] = {
{ 9, 1 }, { 9, 1 }, { 9, 1 }, { 9, 1 },
{ 99, 2 }, { 99, 2 }, { 99, 2 },
{ 999, 3 }, { 999, 3 }, { 999, 3 },
{ 9999, 4 }, { 9999, 4 }, { 9999, 4 }, { 9999, 4 },
{ 99999, 5 }, { 99999, 5 }, { 99999, 5 },
{ 999999, 6 }, { 999999, 6 }, { 999999, 6 },
{ 9999999, 7 }, { 9999999, 7 }, { 9999999, 7 }, { 9999999, 7 },
{ 99999999, 8 }, { 99999999, 8 }, { 99999999, 8 },
{ 999999999, 9 }, { 999999999, 9 }, { 999999999, 9 },
{ INT_MAX, 10 }, { INT_MAX, 10 }
};
register const int z = 0;
register unsigned log2;
if (i < 0) i = -i;
__asm__ __volatile__ (
"bsr %1, %0;" \
"cmovz %2, %0;"\
: "=r" (log2) \
: "rm" (i), "r"(z));
return digits[log2].count + ( i > digits[log2].max );
}
Une autre, avec une table de consultation plus petite et une approximation log10 tirée de ici .
int count_bsr2( int i ) {
static const unsigned limits[] =
{0, 10, 100, 1000, 10000, 100000,
1000000, 10000000, 100000000, 1000000000};
register const int z = 0;
register int l, log2;
if (i < 0) i = -i;
__asm__ __volatile__ (
"bsr %1, %0;" \
"cmovz %2, %0;"\
: "=r" (log2) \
: "rm" (i), "r"(z));
l = (log2 + 1) * 1233 >> 12;
return (l + ((unsigned)i >= limits[l]));
}
Ces deux avantages tirent parti du fait que sur x86, -INT_MIN est égal à INT_MIN.
Mettre à jour:
Comme suggéré, voici les timings pour les routines count_bsr et légèrement plus rapides de 64 bits seulement count_bsr_mod par rapport à la recherche binaire et aux algorithmes de découpage binaire à l'aide du programme de test très agréable de paxdiablo modifié pour générer ensembles avec une distribution de signe aléatoire. Les tests ont été construits avec gcc 4.9.2 en utilisant les options "-O3 -falign-functions = 16 -falign-jumps = 16 -march = corei7-avx" et exécutés sur un système Sandy Bridge par ailleurs inactif avec les états turbo et veille désactivés.
Temps pour mod bsr: 270000 Temps pour bsr: 340000 Temps pour hachage binaire: 800000 Temps pour recherche binaire: 770000 Temps pour recherche binaire mod: 470000
Source pour le test,
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <limits.h>
#include <time.h>
#define numof(a) (sizeof(a) / sizeof(a[0]))
/* Random numbers and accuracy checks. */
static int rndnum[10000];
static int rt[numof(rndnum)];
/* All digit counting functions here. */
static int count_bchop (int n) {
int r = 1;
if (n < 0) n = (n == INT_MIN) ? INT_MAX : -n;
if (n >= 100000000) {
r += 8;
n /= 100000000;
}
if (n >= 10000) {
r += 4;
n /= 10000;
}
if (n >= 100) {
r += 2;
n /= 100;
}
if (n >= 10)
r++;
return r;
}
static int count_bsearch(int i)
{
if (i < 0)
{
if (i == INT_MIN)
return 11; // special case for -2^31 because 2^31 can't fit in a two's complement 32-bit integer
i = -i;
}
if (i < 100000) {
if (i < 1000) {
if (i < 10) return 1;
else if (i < 100) return 2;
else return 3;
} else {
if (i < 10000) return 4;
else return 5;
}
} else {
if (i < 10000000) {
if (i < 1000000) return 6;
else return 7;
} else {
if (i < 100000000) return 8;
else if (i < 1000000000) return 9;
else return 10;
}
}
}
// Integer log base 10, modified binary search.
static int count_bsearch_mod(int i) {
unsigned x = (i >= 0) ? i : -i;
if (x > 99)
if (x > 999999)
if (x > 99999999)
return 9 + (x > 999999999);
else
return 7 + (x > 9999999);
else
if (x > 9999)
return 5 + (x > 99999);
else
return 3 + (x > 999);
else
return 1 + (x > 9);
}
static int count_bsr_mod(int i) {
struct {
int m_count;
int m_threshold;
} static digits[32] =
{
{ 1, 9 }, { 1, 9 }, { 1, 9 }, { 1, 9 },
{ 2, 99 }, { 2, 99 }, { 2, 99 },
{ 3, 999 }, { 3, 999 }, { 3, 999 },
{ 4, 9999 }, { 4, 9999 }, { 4, 9999 }, { 4, 9999 },
{ 5, 99999 }, { 5, 99999 }, { 5, 99999 },
{ 6, 999999 }, { 6, 999999 }, { 6, 999999 },
{ 7, 9999999 }, { 7, 9999999 }, { 7, 9999999 }, { 7, 9999999 },
{ 8, 99999999 }, { 8, 99999999 }, { 8, 99999999 },
{ 9, 999999999 }, { 9, 999999999 }, { 9, 999999999 },
{ 10, INT_MAX }, { 10, INT_MAX }
};
__asm__ __volatile__ (
"cdq \n\t"
"xorl %%edx, %0 \n\t"
"subl %%edx, %0 \n\t"
"movl %0, %%edx \n\t"
"bsrl %0, %0 \n\t"
"shlq $32, %%rdx \n\t"
"movq %P1(,%q0,8), %q0 \n\t"
"cmpq %q0, %%rdx \n\t"
"setg %%dl \n\t"
"addl %%edx, %0 \n\t"
: "+a"(i)
: "i"(digits)
: "rdx", "cc"
);
return i;
}
static int count_bsr(int i) {
struct {
int max;
int count;
} static digits[32] = {
{ 9, 1 }, { 9, 1 }, { 9, 1 }, { 9, 1 },
{ 99, 2 }, { 99, 2 }, { 99, 2 },
{ 999, 3 }, { 999, 3 }, { 999, 3 },
{ 9999, 4 }, { 9999, 4 }, { 9999, 4 }, { 9999, 4 },
{ 99999, 5 }, { 99999, 5 }, { 99999, 5 },
{ 999999, 6 }, { 999999, 6 }, { 999999, 6 },
{ 9999999, 7 }, { 9999999, 7 }, { 9999999, 7 }, { 9999999, 7 },
{ 99999999, 8 }, { 99999999, 8 }, { 99999999, 8 },
{ 999999999, 9 }, { 999999999, 9 }, { 999999999, 9 },
{ INT_MAX, 10 }, { INT_MAX, 10 }
};
register const int z = 0;
register unsigned log2;
if (i < 0) i = -i;
__asm__ __volatile__ (
"bsr %1, %0;" \
"cmovz %2, %0;"\
: "=r" (log2) \
: "rm" (i), "r"(z));
return digits[log2].count + ( i > digits[log2].max );
}
/* Structure to control calling of functions. */
typedef struct {
int (*fnptr)(int);
const char *desc;
} tFn;
static tFn fn[] = {
{ NULL, NULL },
{ count_bsr_mod, " bsr mod" },
{ count_bsr, " bsr" },
{ count_bchop, " binary chop" },
{ count_bsearch, " binary search" },
{ count_bsearch_mod," binary search mod"}
};
static clock_t clk[numof (fn)];
int main (int c, char *v[]) {
int i, j, k, r;
int s = 1;
/* Test code:
printf ("%11d %d\n", INT_MIN, count_bsearch(INT_MIN));
//for (i = -1000000000; i != 0; i /= 10)
for (i = -999999999; i != 0; i /= 10)
printf ("%11d %d\n", i, count_bsearch(i));
printf ("%11d %d\n", 0, count_bsearch(0));
for (i = 1; i != 1000000000; i *= 10)
printf ("%11d %d\n", i, count_bsearch(i));
printf ("%11d %d\n", 1000000000, count_bsearch(1000000000));
printf ("%11d %d\n", INT_MAX, count_bsearch(INT_MAX));
return 0;
/* */
/* Randomize and create random pool of numbers. */
int p, n;
p = n = 0;
srand (time (NULL));
for (j = 0; j < numof (rndnum); j++) {
rndnum[j] = ((Rand() & 2) - 1) * Rand();
}
rndnum[0] = INT_MAX;
rndnum[1] = INT_MIN;
/* For testing. */
for (k = 0; k < numof (rndnum); k++) {
rt[k] = (fn[1].fnptr)(rndnum[k]);
}
/* Test each of the functions in turn. */
clk[0] = clock();
for (i = 1; i < numof (fn); i++) {
for (j = 0; j < 10000; j++) {
for (k = 0; k < numof (rndnum); k++) {
r = (fn[i].fnptr)(rndnum[k]);
/* Test code:
if (r != rt[k]) {
printf ("Mismatch error [%s] %d %d %d %d\n",
fn[i].desc, k, rndnum[k], rt[k], r);
return 1;
}
/* */
}
}
clk[i] = clock();
}
/* Print out results. */
for (i = 1; i < numof (fn); i++) {
printf ("Time for %s: %10d\n", fn[i].desc, (int)(clk[i] - clk[i-1]));
}
return 0;
}
Vous pouvez faire: floor (log10 (abs (x))) + 1
Ou si vous voulez économiser sur les cycles, vous pouvez simplement faire des comparaisons.
if(x<10)
return 1;
if(x<100)
return 2;
if(x<1000)
return 3;
etc etc
Cela évite toute fonction coûteuse en calcul, telle que la journalisation, voire la multiplication ou la division. Bien qu’elle ne soit pas élégante, cela peut être masqué en l’encapsulant dans une fonction. Il n’est ni complexe ni difficile à maintenir, je ne rejeterais donc pas cette approche en raison de la mauvaise pratique de codage; Je pense que ce serait jeter le bébé avec l'eau du bain.
De Bit Twiddling Hacks:
Trouver le journal de base entier 10 d'un entier de manière évidente
Notez le classement des comparaisons dans celui-ci.
Voici une recherche binaire déroulée sans division ni multiplication. En fonction de la distribution des nombres qui lui sont attribués, il peut ou non battre les autres avec des instructions if déroulées, mais doit toujours battre celles qui utilisent des boucles et des multiplications/divisions/log10.
Avec une distribution uniforme de nombres aléatoires englobant toute la plage, sur ma machine, elle représentait en moyenne 79% du temps d'exécution de count_bchop () de paxdiablo, 88% du temps de count_ifs () et 97% du temps de count carbifs ().
Avec une distribution exponentielle (la probabilité qu'un nombre ait n chiffres est égale à celle d'un nombre m chiffres, où m n ) count_ifs () et count_revifs () les deux battent ma fonction. Je ne sais pas pourquoi à ce stade.
int count_bsearch(int i)
{
if (i < 0)
{
if (i == INT_MIN)
return 10; // special case for -2^31 because 2^31 can't fit in a two's complement 32-bit integer
i = -i;
}
if (i < 100000) {
if (i < 1000) {
if (i < 10) return 1;
else if (i < 100) return 2;
else return 3;
} else {
if (i < 10000) return 4;
else return 5;
}
} else {
if (i < 10000000) {
if (i < 1000000) return 6;
else return 7;
} else {
if (i < 100000000) return 8;
else if (i < 1000000000) return 9;
else return 10;
}
}
}
Je suis tombé sur cela pendant une recherche sur Google: http://www.hackersdelight.org/hdcodetxt/ilog.c.txt } _
Un repère rapide montrait clairement que les méthodes de recherche binaire étaient gagnantes. Le code de lakshmanaraj est assez bon, d'Alexander Korobka est environ 30% plus rapide, Code mort est un tout petit peu plus rapide (~ 10%), mais j'ai trouvé ce qui suit Les astuces du lien ci-dessus donnent une amélioration supplémentaire de 10%.
// Integer log base 10, modified binary search.
int ilog10c(unsigned x) {
if (x > 99)
if (x < 1000000)
if (x < 10000)
return 3 + ((int)(x - 1000) >> 31);
// return 3 - ((x - 1000) >> 31); // Alternative.
// return 2 + ((999 - x) >> 31); // Alternative.
// return 2 + ((x + 2147482648) >> 31); // Alternative.
else
return 5 + ((int)(x - 100000) >> 31);
else
if (x < 100000000)
return 7 + ((int)(x - 10000000) >> 31);
else
return 9 + ((int)((x-1000000000)&~x) >> 31);
// return 8 + (((x + 1147483648) | x) >> 31); // Alternative.
else
if (x > 9)
return 1;
else
return ((int)(x - 1) >> 31);
// return ((int)(x - 1) >> 31) | ((unsigned)(9 - x) >> 31); // Alt.
// return (x > 9) + (x > 0) - 1; // Alt.
}
Notez qu'il s'agit du journal 10 et non du nombre de chiffres, donc digits = ilog10c(x)+1
.
Ne supporte pas les négatifs, mais c'est facilement corrigé avec un -
.
if (x == MININT) return 10; // abs(MININT) is not defined
x = abs (x);
if (x<10) return 1;
if (x<100) return 2;
if (x<1000) return 3;
if (x<10000) return 4;
if (x<100000) return 5;
if (x<1000000) return 6;
if (x<10000000) return 7;
if (x<100000000) return 8;
if (x<1000000000) return 9;
return 10; //max len for 32-bit integers
Très inélégant. Mais plus rapide que toutes les autres solutions. Les journaux de division et FP entiers sont coûteux. Si les performances ne sont pas un problème, la solution log10 est ma solution préférée.
Juste un petit ajustement pour la langue C:
floor( log10( abs( (number)?number:1 ) ) + 1 );
int n = 437788;
int N = 1;
while (n /= 10) N++;
Je sais que je suis en retard, mais ce code est + x10 plus rapide que toutes les autres réponses.
int digits(long long x)
{
x < 0 ? x = -x : 0;
return x < 10 ? 1 :
x < 100 ? 2 :
x < 1000 ? 3 :
x < 10000 ? 4 :
x < 100000 ? 5 :
x < 1000000 ? 6 :
x < 10000000 ? 7 :
x < 100000000 ? 8 :
x < 1000000000 ? 9 :
x < 10000000000 ? 10 : 0;
}
int x = -937810;
printf("%d : %d digits\n", x, digits(x));
En dehors:
-937810 : 6 digits
Voici un moyen simple de trouver la longueur (c'est-à-dire le nombre de chiffres) d'un entier signé:
while ( abs(n) > 9 )
{
num /= 10;
++len;
}
Où n
est le nombre entier dont vous voulez trouver la longueur et où len
est égal au nombre de chiffres du nombre entier. Cela fonctionne pour les deux valeurs de n
(négatif ou positif).
L'appel sur abs()
est facultatif, si vous travaillez uniquement avec des entiers positifs.
NE PAS utiliser le sol (log10 (...)). Ce sont des fonctions à virgule flottante et des fonctions lentes à ajouter. Je crois que le moyen le plus rapide serait cette fonction:
int ilog10(int num)
{
unsigned int num = abs(num);
unsigned int x, i;
for(x=10, i=1; ; x*=10, i++)
{
if(num < x)
return i;
if(x > INT_MAX/10)
return i+1;
}
}
Certaines personnes suggèrent que la version de recherche binaire pourrait être plus lente en raison de prédictions erronées de la branche.
MODIFIER:
J'ai fait des tests et obtenu des résultats vraiment intéressants. J'ai synchronisé ma fonction avec toutes les fonctions testées par Pax ET la fonction de recherche binaire fournie par lakshmanaraj . Le test est effectué à l'aide de l'extrait de code suivant:
start = clock();
for(int i=0; i<10000; i++)
for(int j=0; j<10000; j++)
tested_func(numbers[j]);
end = clock();
tested_func_times[pass] = end-start;
Où le tableau de nombres [] contient des nombres générés aléatoirement sur toute la plage du type int (sauf MIN_INT). Le test a été répété pour chaque fonction testée sur le tableau THE SAME numbers []. Le test complet a été effectué 10 fois, avec des résultats moyens pour toutes les passes. Le code a été compilé avec GCC 4.3.2 avec le niveau d’optimisation -O3.
Voici les résultats:
floating-point log10: 10340ms
recursive divide: 3391ms
iterative divide: 2289ms
iterative multiplication: 1071ms
unrolled tests: 859ms
binary search: 539ms
Je dois dire que je me suis vraiment étonné. La recherche binaire a été bien meilleure que ce que je pensais. J'ai vérifié comment GCC a compilé ce code pour asm. O_O. Maintenant, c'est impressionnant. Il a été optimisé bien mieux que je ne le pensais, évitant la plupart des branches de manière très intelligente. Pas étonnant que ce soit RAPIDE.
Pour c #, voici une solution très simple et rapide ...
private static int NumberOfPlaces(int n)
{
//fast way to get number of digits
//converts to signed string with +/- intact then accounts for it by subtracting 1
return n.ToString("+#;-#;+0").Length-1;
}
Je suppose que le moyen le plus simple serait:
int digits = 0;
if (number < 0) digits = 1;
while (number) {
number /= 10;
digits++;
}
digits donne la réponse.
vous pouvez trouver le nombre de chiffres dans un nombre en utilisant cette formule ceil (log10 (abs (x))) où ceil retourne un nombre entier juste supérieur au nombre