Compter le nombre de chiffres après le". " dans les nombres à virgule flottante?
C'est une question d'entrevue.
Comment voulez-vous calculer le nombre de chiffres après .
en nombre à virgule flottante.
par exemple, si 3.554 de sortie=3
pour 43.000 sortie=0.
Mon bout de code est ici
double no =3.44;
int count =0;
while(no!=((int)no))
{
count++;
no=no*10;
}
printf("%d",count);
Il y a quelques chiffres qui ne peuvent pas être indiqué par float
type. par exemple, il n'y a pas de 73.487
dans float
type, le nombre indiqué par float
en c est 73.486999999999995
rapprochant d'elle.
Maintenant comment le résoudre comme il va, dans certains boucle infinie.
Remarque : les Spécifications de la norme IEEE 754, 32 bits en virgule flottante est divisé comme 24+7+1 bits. Les 7 bits indiquent la mantisse.
- Alors, que faut-il faire lorsque vous passez une non-fin nombre décimal à elle? Le programme devrait en quelque sorte savoir que
73.486999999999995
est "réellement"73.487
? Êtes-vous sûr que le nombre décimal doit être un float, pas une chaîne de la représentation? - En supposant binaire à virgule flottante, tous les représentable nombres sont des multiples d'une partie de la puissance de deux; pas infiniment de répéter les nombres rationnels sont représentable.
- Je donne 73.487 il va dans une boucle infinie. Je ne suis pas sûr si je la déclare en tant que double et d'une certaine manière c'est la conversion de chaîne de caractères. Mais pourquoi il devrait être une représentation de chaîne?
- La meilleure façon de savoir, c'est que la virgule flottante représentation de deux nombres sont les mêmes. Donc, vous voulez le plus court fraction que les résultats de la même virgule flottante.
- Comment géreriez-vous
2.00000
? Et1.99999999999999999999999999
, comme compilateur autour d'elle? - Le résultat pour
2.00000
(ce qui est exactement représentable) est tout simplement 0. Et une question n'est pas stupide juste parce que la réponse est "vous ne pouvez pas le faire". C'est une bonne question si les OP et les autres lecteurs en apprendre quelque chose. - Cette question indique qu'un 32 bits
float
est divisée en 24 bits, 7 bits, 1 bit, et que les 7 bits de spécifier la mantisse. Ceci est incorrect. Le 32 bits IEEE-754 binaire à virgule flottante format a un bit de signe, huit bits pour l'exposant de codage, et 23 bits pour une significande encodage.
Vous devez vous connecter pour publier un commentaire.
Le problème n'est pas vraiment possible comme l'a dit, depuis virgule flottante est généralement représenté en binaire, pas en décimal. Comme vous le dites, beaucoup (en fait la plupart) des nombres décimaux ne sont pas exactement représentable en virgule flottante.
D'autre part, tous numéros qui sont exactement représentable en binaire à virgule flottante sont les décimales d'un nombre fini de chiffres, mais c'est pas particulièrement utile si vous voulez un résultat de 2 pour
3.44
.Quand je lance votre extrait de code, il est dit que
3.44
a 2 chiffres après la virgule -- parce que3.44 * 10.0 * 10.0
arrive juste à rendement exactement344.0
. Qui pourrait ne pas se produire pour un autre nombre, comme, par exemple,3.43
(je n'ai pas essayé).Quand je l'ai essayer avec
1.0/3.0
, il entre dans une boucle infinie. L'ajout de certainsprintf
s montre queno
devient exactement33333333333333324.0
après 17 itérations, mais ce nombre est trop grand pour être représenté comme uneint
(au moins sur mon système), et de le convertir enint
a un comportement indéfini.Et pour un grand nombre, à plusieurs reprises en multipliant par 10 va inévitablement vous donner un floating-point de débordement. Il existe des moyens pour éviter que les, mais ils ne permettent pas de résoudre les autres problèmes.
Si vous stockez la valeur
3.44
dans undouble
objet, la valeur réelle stockée (au moins sur mon système) est exactement3.439999999999999946709294817992486059665679931640625
, qui a 51 chiffres décimaux dans sa partie fractionnaire. Supposons que vous avez vraiment voulez pour calculer le nombre de décimales après le point dans3.439999999999999946709294817992486059665679931640625
. Depuis3.44
et3.439999999999999946709294817992486059665679931640625
sont effectivement le même nombre, il n'y a aucun moyen pour toute fonction C pour distinguer entre eux et de savoir s'il doit retourner 2 ou 51 (ou 50 si vous signifiait3.43999999999999994670929481799248605966567993164062
, ou ...).Vous pourriez probablement détecter que la valeur stockée est "assez proche" de
3.44
, mais qui le rend beaucoup plus complexe problème-et il perd la capacité de déterminer le nombre de chiffres dans la partie décimale de3.439999999999999946709294817992486059665679931640625
.La question n'a de sens que si le numéro que vous avez reçu est stocké dans un format qui peut réellement représenter les fractions décimales (comme une chaîne de caractères), ou si vous ajoutez une certaine exigence complexe pour déterminer quelle fraction décimale d'une donnée binaire rapprochement est censé représenter.
Il y a probablement un moyen raisonnable de faire la dernière, par la recherche de l'unique fraction décimale dont la plus proche approximation donnée à virgule flottante de type est la donnée binaire nombre à virgule flottante.
Je doute que cela soit ce que vous voulez, puisque la question est de demander quelque chose qui n'est généralement pas significative avec des nombres à virgule flottante, mais voici la réponse:
x
à chaque itération. Ne serait-ce pas vous donner le nombre de binaire chiffres plutôt que des décimales?digits_after_decimal_point(3.554)
est susceptible de renvoyer à 51 au lieu de 3.La question pourrait être interprété comme tel:
Donné un nombre à virgule flottante, trouver le plus court représentation décimale qui serait interprété comme la même valeur à virgule flottante avec arrondi correct.
Une fois posée comme cela, la réponse est Oui, nous pouvons voir cet algorithme:
Impression des nombres à virgule flottante rapidement et avec précision. Robert G. Burger et R. Kent Dybvig. ACM SIGPLAN Conférence de 1996 sur le Langage de Programmation, de Conception et de mise en Œuvre, juin 1996
http://www.cs.indiana.edu/~dyb/pubs/FP-Impression-PLDI96.pdf
Voir aussi les références de Calculer le double de la valeur la plus proche préféré décimal résultat pour une Causerie de mise en œuvre.
float
ne sera pas le rendement le plus prochefloat
car elle va d'abord être converti àdouble
(arrondi vers le bas pour le prochain nombre entier pair), et qui sera arrondi à la baisse à nouveau. Je me demande s'il y a desfloat
valeurs dont le plus court représentation décimale serait correct si converties directement enfloat
, mais donnerait des résultats incorrects si analysée pardouble
?double
rendements autre chose que le plus prochefloat
. Je ne sais pas du tout particulière minime-longueurfloat
valeurs où la double-arrondissement serait la cause de la détresse; je me demandais si vous connaissiez tous les ou savait avec certitude qu'il n'en existe aucun.Sonne comme vous devez soit utiliser
sprintf
pour obtenir une réelle arrondie version, ou d'avoir en entrée une chaîne de caractères (et pas analysé à unfloat
).De toute façon, une fois que vous avez une version de chaîne, le nombre, le comptage de caractères après la virgule doivent être trivial.
Il n'existe pas de solutions exactes. Mais vous pouvez convertir la valeur à la chaîne et ne compte pas la partie qui dépasse le type de précision et exclure la fuite 0s ou 9s. Ce sera le travail pour le plus de cas, mais il ne veut toujours pas de retour de la bonne réponse pour tous.
Par exemple en double précision est environ 15 chiffres si l'entrée est une chaîne décimale de l'utilisateur (17 chiffres pour le binaire-décimal-binaire aller-retour), donc pour 73.486999999999995 il y a 15 - 2 = 13 chiffres après la radix point (moins de 2 chiffres dans l'int de la partie). Après qu'il y a encore beaucoup de 9s dans la partie fractionnaire, de soustraire de l'compter aussi. Ici il y a dix 9s qui signifie qu'il ya 13 - 10 = 3 chiffres après la virgule. Si vous utilisez 17 chiffres puis le dernier chiffre qui peuvent être de simples déchets, de l'exclure avant de compter les 9 ou 0.
Sinon il suffit de démarrer à partir du 15 ou du 16ème chiffres et itérer jusqu'à ce que vous voyez le premier non-0 et non à 9 chiffres. Compter les autres chiffres et vous obtiendrez 3 dans ce cas. Bien sûr, lors de l'itération, vous devez également vous assurer que la fuite est 0 ou tous les 9s
Ce que vous pouvez faire est de multiplier le nombre par les diverses puissances de 10, rond qu'à l'entier le plus proche, et ensuite, divisez la réponse par le même nombre de puissances de 10. Lorsque le résultat final compare différent de l'original, vous avez passé un chiffre trop loin.
Je n'ai pas lu cela dans un temps long, alors je ne sais pas comment il se rapporte à cette idée, mais Comment faire pour Imprimer les Nombres à virgule Flottante avec Précision à partir de PLDI 1990 et 2003 Rétrospective sont probablement très pertinentes pour le problème de base.
double
plus proche de 1/3, cet algorithme renvoie 16. Pourquoi? Ledouble
plus proche de 1/3 a 54 chiffres après le point décimal; il est 0.333333333333333314829616256247390992939472198486328125. Il n'est même pas près de 16 chiffres décimaux chiffre (qui est, de sa déviation de la plus proche à 16 chiffres décimaux chiffre est beaucoup plus grande que la valeur d'un chiffre à cette position).Demande: par exemple, si 3.554 de sortie = 3, pour 43.000 sortie = 0
Problème: qui est déjà un chiffre après la virgule comme 0.33345. Lorsque cela est converti en
double
, il pourrait être quelque chose comme 0.333459999...125. Le but est simplement de déterminer que 0.33345 est un court décimale qui produira le même double. La solution est de convertir une chaîne de caractères avec le bon nombre de chiffres que les résultats de la même valeur d'origine.