web-dev-qa-db-fra.com

Vérifier la double variable si elle contient un entier et non une virgule flottante

Ce que je veux dire est le suivant:

  double d1 =555;
  double d2=55.343

Je veux pouvoir dire que d1 est un entier, alors que d2 ne l’est pas. Existe-t-il un moyen simple de le faire dans c/c ++?

34
vehomzzz

Utilisez std::modf :

double intpart;
modf(value, &intpart) == 0.0

Ne convertissez pas en int! Le nombre 1.0e+300 est un entier aussi que vous connaissez.

Edit: Comme le souligne Pete Kirkham, passer le second argument n’est pas garanti par la norme, ce qui nécessite l’utilisation d’une variable factice et, malheureusement, rend le code beaucoup moins élégant.

69
avakar

En supposant que vous ayez la bibliothèque cmath <math.h>, vous pouvez comparer le nombre par rapport à floor . Si le nombre peut être négatif, assurez-vous que vous obtenez le absolu premier.

bool double_is_int(double trouble) {
   double absolute = abs( trouble );
   return absolute == floor(absolute);
}
9
tj111

En supposant un environnement conforme aux normes c99 et IEEE-754,

(trunc(x) == x)

est une autre solution et aura (sur la plupart des plates-formes) des performances légèrement supérieures à celles de modf car il suffit de produire la partie entière. Les deux sont complètement acceptables.

Notez que trunc génère un résultat en double précision. Vous n'avez donc pas à vous soucier des conversions de type hors plage comme vous le feriez avec (int)x.


Comme le souligne @pavon dans un commentaire, vous devrez peut-être ajouter une autre vérification, selon que vous vous souciez ou non de l'infini et du résultat que vous souhaitez obtenir si x est infini.

5
Stephen Canon

avakar avait presque raison - utilisez modf, mais le détail était désactivé.

modf renvoie la partie décimale, le test doit donc indiquer que le résultat de modf est 0.0.

modf prend deux arguments, le deuxième devant être un pointeur du même type que le premier argument. Passer NULL ou 0 provoque une erreur de segmentation dans le runtime g ++. La norme ne spécifie pas que le dépassement de 0 est sûr; il se peut que cela fonctionne sur la machine d’avakar mais ne le faites pas. 

Vous pouvez également utiliser fmod(a,b) qui calcule la a modulo b en passant 1.0. Cela devrait également donner la partie décimale. 

#include<cmath>
#include<iostream>

int main ()
{
    double d1 = 555;
    double d2 = 55.343;

    double int_part1;
    double int_part2;

    using namespace std;

    cout << boolalpha;
    cout << d1 << " " << modf ( d1, &int_part1 ) << endl;
    cout << d1 << " " << ( modf ( d1, &int_part1 ) == 0.0 ) << endl;
    cout << d2 << " " << modf ( d2, &int_part2 ) << endl;
    cout << d1 << " " << ( modf ( d2, &int_part2 ) == 0.0 ) << endl;
    cout << d2 << " " << modf ( d2, &int_part2 ) << endl;
    cout << d1 << " " << ( modf ( d2, &int_part2 ) == 0.0 ) << endl;

    cout << d1 << " " << fmod ( d1, 1.0 ) << endl;
    cout << d1 << " " << ( fmod ( d1, 1.0 ) == 0 ) << endl;
    cout << d2 << " " << fmod ( d2, 1.0 ) << endl;
    cout << d2 << " " << ( fmod ( d2, 1.0 ) == 0 ) << endl;


    cout.flush();

    modf ( d1, 0 ); // segfault

}
4
Pete Kirkham

Que diriez-vous 

if (abs(d1 - (round(d1))) < 0.000000001) {
   printf "Integer\n"; /* Can not use "==" since we are concerned about precision */
}

Corrigé pour travailler en utilisant l'arrondi pour refléter le bug trouvé par Anna

Solutions alternatives:

if ((d1 - floor(d1) < 0.000000001) || (d1 - floor(d1) > 0.9999999999)) {
   /* Better store floor value in a temp variable to speed up */
   printf "Integer\n"; /* Can not use "==" since we are concerned about precision */
}

Theres également un autre avec prenant le plancher, soustrayant 0,5 et prenant abs () de cela et comparant à 0.499999999 mais je suppose que ce ne sera pas une amélioration majeure de performance.

3
DVK
int iHaveNoFraction(double d){
    return d == trunc(d);
}

Maintenant, ce ne serait pas C s'il n'avait pas eu environ 40 ans de révisions linguistiques ...

En C, == renvoie int mais en C++, il retourne bool. Au moins sur ma distribution Linux (Ubuntu), vous devez déclarer double trunc(double); ou vous pouvez compiler avec -std=c99, ou déclarer la macro de niveau, le tout afin d’obtenir <math.h> pour la déclarer.

3
DigitalRoss

Que dis-tu de ça?

if ((d1 - (int)d1) == 0)
    // integer
2
Ashwin

essayer:

bool isInteger(double d, double delta)
{
   double absd = abs(d);

   if( absd - floor(absd) > 0.5 )
      return (ceil(absd) - absd) < delta;

   return (d - floor(absd)) < delta;
}
0

Dans de nombreux calculs, vous savez que vos résultats en virgule flottante comporteront une petite erreur numérique pouvant résulter de plusieurs multiplications.

Donc, ce que vous voulez vraiment trouver, c’est la question qui se pose est ce nombre compris dans les nombres 1e-5 d’une valeur entière. Dans ce cas, je pense que cela fonctionne mieux:

bool isInteger( double value )
{
    double flr = floor( value + 1e-5 );
    double diff = value - flr;
    return diff < 1e-5;
}
0
Jeroen Dirks
#include <math.h>
#include <limits>

int main()
{
  double x, y, n;
  x = SOME_VAL;
  y = modf( x, &n ); // splits a floating-point value into fractional and integer parts
  if ( abs(y) < std::numeric_limits<double>::epsilon() )
  {
    // no floating part
  }
}
0

J'ai fait face à des questions similaires. Comme je devais quand même arrondir le double, c’est ce que je trouve efficace:

double d = 2.000000001;
int i = std::round(d);
std::fabs(d-i) < 10 * std::numeric_limits<double>::epsilon()
0
Denis

Vous trouverez ci-dessous le code pour tester d1 et d2 en le maintenant très simple. La seule chose que vous devez vérifier est de savoir si la valeur de la variable est égale à la même valeur convertie en un type int. Si ce n'est pas le cas, alors ce n'est pas un entier.

#include<iostream>
using namespace std;

int main()
{
    void checkType(double x);
    double d1 = 555;
    double d2 = 55.343;        
    checkType(d1);
    checkType(d2);
    system("Pause");
    return 0; 
}
void checkType(double x)
{
     if(x != (int)x)
     {
          cout<< x << " is not an integer "<< endl;
     }
     else 
     {
         cout << x << " is an integer " << endl;
     }
};
0
KJP