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 ?
Je voudrais savoir comment trouver la longueur d'un nombre entier en C.
Par exemple :
et ainsi de suite.
Comment puis-je faire cela en 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.
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é.
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
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.
@Pete Merci de me rappeler la limitation du domaine de log et le cas des nombres négatifs - j'ai modifié ma réponse.
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).
Je frémis à l'idée de ce à quoi ressemblerait la deuxième version écrite entièrement avec l'opérateur ternaire...
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.
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).
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.
C'est inutilement inefficace - pourquoi utiliser jusqu'à environ 18 appels de fonctions récursives quand on peut le faire avec un seul appel à log10 ?
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.
@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.
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).
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)
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.
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".
0 votes
A quel point êtes-vous sûr que
log10(10000)
retournera 4 et non 3.999999... ?1 votes
Hmm. L'expérience montre que
log10(10**n)
donne la valeur exacte pour les puissances de 10 de 1 à 2**19, au moins avec gcc et glibc. Mais je ne compterais pas dessus pour toutes les implémentations. (**
désigne l'exponentiation ; il n'existe pas d'opérateur de ce type en C).0 votes
Alors, quelle réponse est acceptée comme réponse ?
0 votes
Duplicata : stackoverflow.com/questions/1068849/
0 votes
@APerson Whoa ! Je viens de signaler cette même question comme étant un doublon. Vous devez être une personne, aussi.
0 votes
Pendant une seconde, j'ai presque cru que j'avais atterri sur Code Golf au lieu de SO.