2
votes

Comment puis-je convertir double ou float (tous les chiffres) en int?

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


13 commentaires

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 un double )


@ 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 un double .


@ChrisMcmonagle: Ensuite, vous pouvez simplement multiplier avec 10 puissance 5 et attribuer à un int


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 exemple long long ), vous devriez vous assurer que le nombre est compris entre std :: 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.


5 Réponses :


2
votes
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;
}

1 commentaires

Je l'ai compilé et le programme fonctionne bien, et la question ne mentionne pas de gérer les valeurs -ve.



0
votes

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 */
}


8 commentaires

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.



0
votes

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


0 commentaires

0
votes

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.


0 commentaires

0
votes

Comment puis-je convertir un double ou un flottant (tous les chiffres) en entier?

0.9332
1.32001

Objectif pas strictement possible en général.
Typiquement , il y en a environ 2 64 différents double . 0.9332 et 1.32001 ne sont pas dans cet ensemble de double .


Regardons les alternatives les plus proches.

Le double le plus proche a des valeurs exactes plus comme ci-dessous. Certaines valeurs doubles , 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.
  }
} 
Maintenant buf [] ne contient que des chiffres (à moins que l'infini / NaN) convenant à la conversion de strto ... () en un type entier - si cela "correspond". buf [] pourrait contenir des centaines de chiffres car DBL_MAX est souvent environ 3.0e308 ou plus. L'objectif d'OP n'est pas exprimé pour les très grands / petits double .

Pour une plage limitée de double , 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 '.' .

XXX

Sortie

0.933200000000000029487523534...
1.32000999999999990563992469...

0 commentaires