web-dev-qa-db-fra.com

Compter le nombre de chiffres - quelle méthode est la plus efficace?

Il existe plusieurs solutions pour trouver le nombre de chiffres dans un nombre donné.

Par exemple:

Méthode 1:

int findn(int num)
{
    char snum[100];
    sprintf(snum, "%d", num);
    return strlen(snum);
}

Méthode 2:

int findn(int num)
{
    if (num == 0) return 1;
    int n = 0;
    while(num) {
        num /= 10;
        n++;
    }
    return n;
}

Méthode 3:

int findn(int num)
{
    /* math.h included */
    return (int) log10(num) + 1;
}

La question est la suivante: quelle est la méthode la plus efficace? Je sais que method-2 est O(n) mais qu'en est-il des méthodes-1 et 3? Comment trouver la complexité d'exécution des fonctions de la bibliothèque?

19

Ce qui suit est encore plus efficace:

int findn(int num)
{
   if ( num < 10 )
      return 1;
   if ( num < 100 )
      return 2;
   //continue until max int
}

Vous pouvez optimiser cela encore plus en effectuant une recherche binaire, mais ce serait excessif. 

21
Luchian Grigore

Les fonctions GCC/Clang __builtin_clz() ou Microsoft Visual C _BitScanReverse() //sont compilées en une seule instruction d'ordinateur sur plusieurs ordinateurs. Vous pouvez l'utiliser comme base pour une solution O(1). Voici une implémentation 32 bits:

#include <limits.h>
#include <stdint.h>

/* Return the number of digits in the decimal representation of n. */
unsigned digits(uint32_t n) {
    static uint32_t powers[10] = {
        0, 10, 100, 1000, 10000, 100000, 1000000,
        10000000, 100000000, 1000000000,
    };
    static unsigned maxdigits[33] = {
        1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5,
        5, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 
    };
    unsigned bits = sizeof(n) * CHAR_BIT - __builtin_clz(n);
    unsigned digits = maxdigits[bits];
    if (n < powers[digits - 1]) {
        -- digits;
    }
    return digits;
}
10
AShelly

Je pense que vous pouvez peut-être écrire la première méthode

int findn(int num)
{
    char snum[100];    
    return  sprintf(snum, "%d", num);
}

car sprintf renverra le nombre de caractères écrits et vous pourrez sauvegarder l'appel dans strlen.

En ce qui concerne l'efficacité, je pense que cela dépend de la mise en œuvre de sprintf, vous devrez peut-être trouver la source de sprintf et voir si l'efficacité est de faire cela. 

7
Tao Feng

Une doublure: for(digits = 0; num > 0; digits++) num /= 10;

3
SatoriAmagi

Essayez la recherche binaire. Par souci de clarté, supposons des entiers 32 bits signés. Tout d’abord, vérifiez si x < 10000. Suivant, en fonction de la réponse, si x < 100 ou x < 1000000, etc.

C'est O(log n), où n est le nombre de chiffres.

3
Bolo

Ces fonctions donnent des résultats radicalement différents pour les nombres non positifs (la plus mauvaise est la méthode 3), de sorte que la comparaison de leur complexité temporelle est douteuse. J'utiliserais celui qui donne la réponse requise dans tous les cas; sans contexte, nous ne pouvons pas savoir ce que c'est (ce n'est probablement pas la méthode 3).

Pour la méthode 1, findn(0) == 1 et findn(-n) == digits in n + 1 (en raison du signe négatif).

Pour la méthode 2, findn(0) == 0 et findn(-n) == digits in n.

Pour la méthode 3, findn(0) == INT_MIN et findn(-n) == INT_MIN également.

3
Aaron Dufour

Je pense que sprintf() utilisera votre méthode 2 pour imprimer le nombre (pour déterminer la longueur de la chaîne à imprimer, puis pour imprimer chaque caractère de la chaîne), ce qui le rendra par nature plus lent.

Le numéro 3 impliquerait probablement une approximation polynomiale de ln() qui impliquera plus d'une division, donc je suppose qu'il sera aussi plus lent ( voici a fast ln () implémentant toujours la division float .. donc beaucoup moins vite).

Je pense donc que la méthode 2 est la voie à suivre. 

Veuillez noter qu'il s'agit d'une manière assez libérale d'aborder ce problème. J'imagine que tester un bon vieux million d'itérations avec chaque fonction vous indiquera le résultat. Mais cela ferait trop bruteforce, n'est-ce pas?

Notez que seule la méthode 2 vous donnera les résultats réels, les autres ont des défauts qui doivent être ajustés pour être corrects (voir la réponse d'Aaron). Alors, choisissez simplement la méthode 2.

2
Gui13

la fonction printf renverra le nombre de chiffres imprimés avec succès.

int digits,n=898392;

digits=printf("%d",n);
printf("Number of digits:%d",digits);

Sortie:

898392

Nombre de chiffres: 6

1
Asha

C’est ma solution ........ jusqu’à 100 chiffres ou jusqu’à ce que vous sachiez ce que vous voulez.

max_digits = 100

int numdigits(int x) {
  for (int i = 1; i < max_digits; i++) {
    if (x < pow(10, i)) {
      return i;
    }
  }
  return 0;
}
1
d4nk1337sauce

Utiliser le journal peut être une bonne option ...

  1. Si la machine cible prend en charge le matériel
  2. Si vous êtes certain que int peut être converti en double et inversement sans perte de précision.

Exemple de mise en oeuvre ...

int num_digits(int arg) {
    if (arg == 0) {
        return 1;
    }

    arg = abs(arg);

    return (int)log10(arg)+1;
}
0
Autodidact