83 votes

Trouver la longueur d'un entier en C

Je voudrais savoir comment trouver la longueur d'un nombre entier en C.

Par exemple :

  • 1 => 1
  • 25 => 2
  • 12512 => 5
  • 0 => 1

et ainsi de suite.

Comment puis-je faire cela en C ?

1 votes

Quelle est la définition de "longueur" si le nombre entier est 0 ? Négatif ?

1 votes

Voir stackoverflow.com/questions/679602/ . C'est presque un double, mais pas exactement car il s'agit d'une question sur .NET.

7 votes

La bonne question n'est pas la longueur du nombre entier, mais quel est le nombre minimal de chiffres décimaux nécessaires pour représenter ce nombre (maintenu dans un int C). log10 est votre ami : log10(10000) = 4, +1 le nombre de chiffres (log10 doit être tronqué)... si le nombre est négatif, vous avez besoin d'un de plus pour le symbole -, si vous voulez le compter, et log10(-num) (puisque le log d'un nombre négatif est "problématique".

124voto

Jordan Lewis Points 3456

C :

Pourquoi ne pas simplement prendre le logarithme en base 10 de la valeur absolue du nombre, l'arrondir au chiffre inférieur et ajouter un ? Cela fonctionne pour les nombres positifs et négatifs qui ne sont pas égaux à 0, et évite d'avoir à utiliser des fonctions de conversion de chaîne.

El log10 , abs y floor Les fonctions sont fournies par math.h . Par exemple :

int nDigits = floor(log10(abs(the_integer))) + 1;

Vous devez inclure cette clause dans une clause garantissant que the_integer != 0 puisque log10(0) renvoie à -HUGE_VAL en fonction de man 3 log .

De plus, vous pouvez ajouter un au résultat final si l'entrée est négative, si vous êtes intéressé par la longueur du nombre incluant son signe négatif.

Java :

int nDigits = Math.floor(Math.log10(Math.abs(the_integer))) + 1;

N.B. La nature à virgule flottante des calculs impliqués dans cette méthode peut la rendre plus lente qu'une approche plus directe. Voir les commentaires de la réponse de Kangkan pour une discussion sur l'efficacité.

2 votes

En fait, vous devriez utiliser le plancher et ajouter 1 à la place. Math.Ceil(Math.Log(99)) = 2 mais Math.Ceil(Math.Log(10)) = 1. Math.Floor(Math.Log(99)) + 1 = 2 et Math.Floor(Math.Log(10)) = 2

0 votes

La question n'est pas tout à fait claire sur la définition de la longueur (vous auriez donc pu penser à "nombre de chiffres sans les zéros de tête"), mais je m'attendrais à ce que 0 et -1 renvoient 1 et 2 comme longueur de leur représentation de caractères plutôt que -2147483648 et 1.

0 votes

@Pete Merci de me rappeler la limitation du domaine de log et le cas des nombres négatifs - j'ai modifié ma réponse.

54voto

Eamon Nerbonne Points 21663

Si vous êtes intéressé par un rapide y très simple la solution suivante pourrait être la plus rapide (cela dépend de la distribution de probabilité des nombres en question) :

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);
}

Même si elle ne remporte pas de prix pour la solution la plus ingénieuse, elle est triviale à comprendre et triviale à exécuter, donc rapide.

Sur un Q6600 utilisant MSC, je l'ai testé avec la boucle suivante :

int res = 0;
for(int i = -2000000000; i < 2000000000; i += 200) res += printLen(i);

Cette solution prend 0,062s, la deuxième solution la plus rapide de Pete Kirkham utilisant une approche smart-logarithmique prend 0,115s - presque deux fois plus de temps. Cependant, pour les nombres autour de 10000 et en dessous, le smart-log est plus rapide.

Au prix d'une certaine clarté, vous pouvez battre smart-log de manière plus fiable (du moins, sur un 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;
        }
    }
}

Cette solution est toujours de 0,062s pour les grands nombres, et se dégrade à environ 0,09s pour les petits nombres - plus rapide dans les deux cas que l'approche smart-log. (gcc fait un code plus rapide ; 0.052 pour cette solution et 0.09s pour l'approche smart-log).

10 votes

Je frémis à l'idée de ce à quoi ressemblerait la deuxième version écrite entièrement avec l'opérateur ternaire...

0 votes

S'il était utilisé pour traiter de longues listes de chiffres, la quantité de code de branchement causerait des ravages dans le CPU. s branch prediction and not produce the fastest execution I J'ai peur.

0 votes

Dans mon benchmark, c'est toujours la solution la plus rapide - notez que toutes les autres solutions intégrales nécessitent également plusieurs branches, et que la seule véritable alternative est une conversion int-double avec un log en virgule flottante (qui, comme il s'avère, n'est pas bon marché non plus).

38voto

zed_0xff Points 12379
int get_int_len (int value){
  int l=1;
  while(value>9){ l++; value/=10; }
  return l;
}

et la seconde fonctionnera aussi pour les nombres négatifs :

int get_int_len_with_negative_too (int value){
  int l=!value;
  while(value){ l++; value/=10; }
  return l;
}

3 votes

J'aime ça. Pas de tampons de caractères temporaires avec des hypothèses sur la taille.

0 votes

Rapide et élégant, il ne fonctionne cependant pas pour les nombres négatifs. Je ne sais pas si c'est un problème pour l'auteur de la question.

1 votes

Il le fera. essayez. il retournera 1

18voto

Kangkan Points 7119

Vous pouvez écrire une fonction comme celle-ci :

unsigned numDigits(const unsigned n) {
    if (n < 10) return 1;
    return 1 + numDigits(n / 10);
}

4 votes

C'est inutilement inefficace - pourquoi utiliser jusqu'à environ 18 appels de fonctions récursives quand on peut le faire avec un seul appel à log10 ?

0 votes

Mais faire en sorte qu'il ne soit pas récursif pourrait être dans certaines circonstances, en fonction des processeurs et de la disponibilité du coprocesseur de flottaison, plus rapide que d'utiliser une fonction comme log10.

9 votes

@Jordan Lewis appeler ceci 20 millions de fois prend 1.8s sur mon netbook ; appeler votre code prend 6.6 secondes (gcc -O3 pour les deux). Un appel à log10 est beaucoup plus lent que tous les appels récursifs qu'il effectue.

12voto

fgm Points 5930

Longueur de n :

length =  ( i==0 ) ? 1 : (int)log10(n)+1;

0 votes

Vous devriez probablement éviter l'arrondi par casting et opter plutôt pour une approche d'arrondi plus explicite (c'est-à-dire portable et cohérente).

0 votes

Comment est casting comment une fonction comme floor peut-elle être implémentée ? (nous supposons un processeur avec ieee dans le matériel, ou par le biais d'un coprocesseur mathématique, ou la disponibilité d'une fonction logicielle pour effectuer la même fonction normalement présente sur les processeurs compatibles fp) ... à la fin (int) est portable et cohérent dans la plupart des cas (j'ose dire, tous les cas dont nous nous soucions normalement)

0 votes

Comme mentionné dans d'autres messages, cela échouera lorsque n = 0.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X