Comment puis-je convertir un double ou un flottant (tous les chiffres) en entier?
Par exemple, si j'ai un double 0.9332, la fonction retournera 9332, 1.32001 renverra 132001
5 Réponses :
this will work ! question is similar to this one : https://stackoverflow.com/questions/5314954/how-to-get-the-length-of-a-numbers-fraction-part #include <iostream> #include <math.h> using namespace std; int getFractionDigitsCount(float ); int main() { float a=1.9332; int p = getFractionDigitsCount(a); cout<<"answer is : "<< a * pow(10,p); return 0; } int getFractionDigitsCount(float d) { if (d >= 1) { //we only need the fraction digits d = d - (long) d; } if (d == 0) { //nothing to count return 0; } d *= 10; //shifts 1 digit to left int count = 1; while (d - (long) d != 0) { //keeps shifting until there are no more fractions d *= 10; count++; } return count; }
Je l'ai compilé et le programme fonctionne bien, et la question ne mentionne pas de gérer les valeurs -ve.
Après un peu plus de réflexion, vous ne pouvez pas gérer avec élégance la conversion directe de double
(ou float
) en entier par de simples casts et multiplication en raison de la limitation des nombres à virgule flottante qui ne représentent pas exactement toutes les valeurs conduisant à la répétition de points décimaux, etc., cela provoque l'échec de la multiplication de l'approche de la partie fractionnaire pour des nombres comme 9.999999
.
Cependant, vous pouvez utiliser une chaîne
intermédiaire et analyser les chiffres de la chaîne pour éviter tous les pièges. (soit en convertissant le nombre en un stringstream
si le nombre à virgule flottante est déjà dans votre programme, soit en lisant simplement la valeur en virgule flottante sous forme de string
pour commencer .
Ensuite, il s'agit simplement de gérer les cas pour une valeur négative ou des valeurs commençant par des zéros non significatifs (par exemple -31.3333
) puis de copier ( .push_back ( )
) les chiffres de la valeur à virgule flottante d'origine vers une chaîne intermédiaire avant d'appeler votre conversion en .stoi (), .stol () ou .stoll ()
. Vous pouvez utilisez la gestion des exceptions try {...} catch {...}
pour gérer tout échec de conversion.
Pour votre fonction renvoyant un long long
value, vous pouvez faire quelque chose comme:
$./bin/double_all_digits enter double in range of 64-bit int: 0.9223372036854775808 error: std::stoll out_of_range. 0.9223372036854775808 -> 0
En le rassemblant dans un court exemple, vous pouvez faire:
$ ./bin/double_all_digits enter double in range of 64-bit int: 0.9223372036854775807 0.9223372036854775807 -> 9223372036854775807
Il y a probablement plusieurs façons de le faire, alors ne prenez pas cela comme la seule approche, mais vous pouvez gérer avec précision les conversions et valider afin d'identifier les échecs.
Exemple d'utilisation / de sortie
$ ./bin/double_all_digits enter double in range of 64-bit int: 9.999999 9.999999 -> 9999999 $ ./bin/double_all_digits enter double in range of 64-bit int: -31.3333 -31.3333 -> -313333
Les valeurs négatives sont également gérées correctement: p >
$ ./bin/double_all_digits enter double in range of 64-bit int: -0.9332 -0.9332 -> -9332
En utilisant une chaîne pour l'analyse intermédiaire, vous évitez le problème décimal répétitif en virgule flottante:
$ ./bin/double_all_digits enter double in range of 64-bit int: 0.9332 0.9332 -> 9332 $ ./bin/double_all_digits enter double in range of 64-bit int: 1.32001 1.32001 -> 132001
En utilisant le essayez {...} catch {...}
la gestion des exceptions, vous pouvez intercepter toutes les conversions out_of_range
. La plus grande conversion autorisée en long long
serait:
#include <iostream> #include <string> #include <limits> #include <cctype> #define LONGDIGITS 19 long long sdigits (std::string s) { int start = 0; /* flag skip leading 0 */ size_t n = 0, maxdigits = LONGDIGITS; /* set max digits */ long long l = 0; /* int to hold conversion */ std::string result; /* string to hold digits */ if (s[0] == '-') { /* if leading '-' */ result.push_back ('-'); /* save for sign */ maxdigits++; /* increment max by 1 */ } for (auto c : s) { /* loop over all chars */ if (isdigit (c)) { /* if not digit skip */ if (c != '0') /* if not 0, the set start flag */ start = 1; if (start) { /* if start set */ result.push_back (c); /* add digit to result */ n++; /* increment digit count */ } } if (n == maxdigits) /* if digit count == max */ break; /* break */ } try { /* try conversion to long long */ l = std::stoll (result); } catch ( std::exception& e ) { /* catch/handle exception */ std::cerr << "error: std::" << e.what() << " out_of_range.\n"; } return l; /* return long long value, or 0 on error */ } int main (void) { std::string s; long long l; std::cout << "enter double in range of 64-bit int: "; if (!(std::cin >> s)) { std::cerr << "err: invalid input.\n"; return 1; } l = sdigits (s); std::cout << s << " -> " << l << '\n'; }
Tout en en ajoutant une, il en résulterait une valeur hors plage pour long long :
#define LONGDIGITS 19 long long sdigits (std::string s) { int start = 0; /* flag skip leading 0 */ size_t n = 0, maxdigits = LONGDIGITS; /* set max digits */ long long l = 0; /* int to hold conversion */ std::string result; /* string to hold digits */ if (s[0] == '-') { /* if leading '-' */ result.push_back ('-'); /* save for sign */ maxdigits++; /* increment max by 1 */ } for (auto c : s) { /* loop over all chars */ if (isdigit (c)) { /* if not digit skip */ if (c != '0') /* if not 0, the set start flag */ start = 1; if (start) { /* if start set */ result.push_back (c); /* add digit to result */ n++; /* increment digit count */ } } if (n == maxdigits) /* if digit count == max */ break; /* break */ } try { /* try conversion to long long */ l = std::stoll (result); } catch ( std::exception& e ) { /* catch/handle exception */ std::cerr << "error: std::" << e.what() << " out_of_range.\n"; } return l; /* return long long value, or 0 on error */ }
Votre premier paragraphe est faux. Vous pouvez extraire tous les chiffres décimaux des nombres binaires à virgule flottante. Il se peut qu'il y en ait un peu trop (pour être pratique) pour la valeur exacte.
Bien sûr, vous pouvez tous les extraire, ce qui voulait dire que vous ne pouvez pas directement les convertir sans rencontrer les problèmes de partie fractionnaire. C'est ce que tu veux dire?
Prenez soin de la partie intégrale, supprimez / soustrayez-la. Jusqu'à ce que le reste soit égal à 0, multipliez par 10, prenez soin de la partie intégrale, supprimez / soustrayez-la ... Quels problèmes voyez-vous ici? Il n'y en a pas. Pas d'arrondi ni de troncature.
Le problème se produit avec des nombres tels que 9.9999
où la représentation en virgule flottante n'est pas exactement 99999/10000
. Lorsque vous tentez une distribution - soustrayez la partie réelle, multipliez la partie fractionnaire par 10, répétez - vous finissez par répéter plus de 4 fois. Avec des nombres comme 0.9332
c'est trivial et ça marche, avec 9.999999
vous n'avez pas de chance.
Vous n'avez pas vraiment 9.9999. Le nombre exact est légèrement différent. Vous avez le numéro exact dont vous pouvez tout récupérer (il y en aura plus de cinq).
Oui, exactement, c'était le problème que l'OP essayait d'éviter.
Ne devrait pas utiliser binaire alors pour commencer.
Je comprends ce que vous dites - cela se résume à ce que vous voulez. (et je suis d'accord) Si vous avez une représentation de 9.9999
et que vous voulez 99999
, alors vous rencontrez plus de 5 chiffres. Si vous voulez juste ce que les chiffres à virgule flottante finissent par être - alors cela fonctionne.
Vous pouvez utiliser la fonction de chaîne de bibliothèque standard C ++ pour convertir un chiffre flottant en entier.
#include <iostream> #include <string> #include <cctype> int floatDigitToInt(float num) { std::string str_f = std::to_string(num); // here one can check NaN, inf etc.. std::string str_i; for (int i = 0; i < str_f.length(); ++i) { if (std::isdigit(str_f[i])) { str_i += str_f[i]; } } return std::stoi(str_i); } int main() { float num_f = 1.32001; std::cout << floatDigitToInt(num_f); return 0; }
Vous vous êtes inutilement peint dans un coin. Si vous avez besoin de vos résultats en virgule flottante décimale appropriée, vous devez utiliser une virgule flottante décimale comme dec64 pour vos calculs au lieu d'essayer pour ramener le résultat bâclé à la normale.
Comment puis-je convertir un double ou un flottant (tous les chiffres) en entier?
0.9332 1.32001Objectif pas strictement possible en général.
Typiquement , il y en a environ 2 64 différents double .0.9332
et1.32001
ne sont pas dans cet ensemble dedouble
.
Regardons les alternatives les plus proches.
Le
double
le plus proche a des valeurs exactes plus comme ci-dessous. Certaines valeursdoubles
, car les valeurs à virgule flottante binaire nécessitent des centaines de chiffres décimaux pour représenter exactement.printf("%.16g\n", 0.9332); printf("%.16g\n", 1.32001);Pour imprimer ces valeurs "en entier" de manière raisonnable, nous devons sélectionner la précision souhaitée.
Disons que nous choisissons un nombre fixe de chiffres après la virgule décimale. (Ce n'est pas vraiment une bonne idée pour les petites valeurs
doubles
car elles deviennent toutes "0" `), le code pourrait post-traiter la chaîne comme vous le souhaitez.int len = snprintf(NULL, n, "%.*f", 16, double_value); char buf(len + 1]; snprintf(buf, sizeof buf, "%.*f", 16, double_value); char *dp = strchr(buf, '.'); // Look for the decimal point - might be `,` in some locales if (dp) { size_t len = strlen(dp + 1); memmove(dp, dp + 1, len + 1); // shove over fraction while (len > 0 && dp[len - 1] == '0') { dp[--len] = '\0'; // lop off trailing zeros. } }Maintenantbuf []
ne contient que des chiffres (à moins que l'infini / NaN) convenant à la conversion destrto ... ()
en un type entier - si cela "correspond".buf []
pourrait contenir des centaines de chiffres carDBL_MAX
est souvent environ 3.0e308 ou plus. L'objectif d'OP n'est pas exprimé pour les très grands / petitsdouble
.
Pour une plage limitée de
XXXdouble
, utilisez le code code utilisez"%. * g"
dont "les zéros de fin sont supprimés de la partie fractionnaire du résultat" puis post = traiter la chaîne pour supprimer le'.'
.Sortie
0.933200000000000029487523534... 1.32000999999999990563992469...
Vous ne pouvez pas. La plupart des nombres à virgule flottante sont une série infinie de nombres au format base 10. Cela se présente sous diverses formes presque tous les jours. Recherchez simplement en virgule flottante.
Difficile à faire car il est très difficile de savoir où «se termine» un nombre à virgule flottante. Ils ne sont pas précis, 10, par exemple, pourrait être 9,99999999999999. Ils se décomposent également en absurdités après un certain nombre de chiffres (7 pour un
float
, 15 pour undouble
)@ user4581301. Tous les nombres à virgule flottante n'ont pas de représentations fractionnaires répétitives. Par exemple, 3,2, .5, .25, .125, .375 sont exacts en virgule flottante IEEE. Mais la plupart ne le sont pas. Même des nombres simples comme .1
Ok cela a du sens. Serait-ce possible si le double devait être normalisé d'abord à 5 chiffres?
@doug Vrai, mais je voulais un exemple simple. comme il est 10 est facilement représentable comme un
float
ou undouble
.@ChrisMcmonagle: Ensuite, vous pouvez simplement multiplier avec
10 puissance 5
et attribuer à unint
Je pense que vous devriez le convertir en chaîne et supprimer le point de la chaîne, puis le convertir en int. mais il n'est pas retournable
Si les nombres sont tous 1> x> -1, vous pouvez multiplier par 10 à la puissance 5 et convertir en un entier. Si vous devez arrondir, vérifiez si le sixième chiffre est> = 5.
En supposant que vous vouliez dire
64 bits
int (par exemplelong long
), vous devriez vous assurer que le nombre est compris entrestd :: numeric_limits :: min ( ) <= double <= std :: numeric_limits :: max ()
Ok ça me donne quelque chose avec quoi travailler. J'essaierai de compter les chiffres, d'évaluer le sixième nombre et aussi la théorie des cordes. Merci!
Vous pouvez avoir jusqu'à quoi ... mille et puis quelques chiffres lors de l'extraction fidèle de tous les chiffres décimaux d'un double. Veux-tu vraiment ça?
@doug: Chaque nombre binaire à virgule flottante est exactement représentable avec un nombre fini de chiffres décimaux.
@EricPostpischil Oui, bon point. Mal formulé. C'est la plupart des fractionnaires de base 10 (par exemple) qui nécessitent un nombre infini de bits dans la mantisse. Par conséquent, ne peut pas être représenté en binaire IEEE.