c++ - simple - Verifique la variable doble si contiene un número entero, y no un punto flotante
punto flotante simple precision (13)
¿Qué tal esto?
if ((d1 - (int)d1) == 0)
// integer
Lo que quiero decir es lo siguiente:
double d1 =555;
double d2=55.343
Quiero poder decir que d1 es un número entero mientras que d2 no. ¿Hay una manera fácil de hacerlo en c / c ++?
A continuación tienes el código para probar d1 y d2, manteniéndolo muy simple. Lo único que tiene que probar es si el valor de la variable es igual al mismo valor convertido a un tipo int. Si este no es el caso, entonces no es un número entero.
#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;
}
};
En muchos cálculos, usted sabe que sus resultados de punto flotante tendrán un pequeño error numérico que puede resultar de varias multiplicaciones.
Entonces, lo que realmente querrás encontrar es que la pregunta es este número dentro del 1e-5 de un valor entero. En ese caso, creo que esto funciona mejor:
bool isInteger( double value )
{
double flr = floor( value + 1e-5 );
double diff = value - flr;
return diff < 1e-5;
}
Enfrenté una pregunta similar. Como necesitaba redondear el doble de todos modos, eso es lo que encuentro que funciona:
double d = 2.000000001;
int i = std::round(d);
std::fabs(d-i) < 10 * std::numeric_limits<double>::epsilon()
Qué tal si
if (abs(d1 - (round(d1))) < 0.000000001) {
printf "Integer/n"; /* Can not use "==" since we are concerned about precision */
}
Se arregló para trabajar usando el redondeo para reflejar el error que Anna encontró
Soluciones alternativas:
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 */
}
También hay otro que toma la palabra, restando 0.5 y tomando abs () y comparando con 0.499999999, pero supongo que no será una gran mejora en el rendimiento.
Suponiendo un entorno compatible con c99 e IEEE-754,
(trunc(x) == x)
es otra solución, y tendrá (en la mayoría de las plataformas) un rendimiento ligeramente mejor que modf
porque solo necesita producir la parte entera. Ambos son completamente aceptables.
Tenga en cuenta que trunc
produce un resultado de doble precisión, por lo que no tiene que preocuparse por las conversiones fuera del rango como lo haría con (int)x
.
Editar: como señala @pavon en un comentario, puede que necesite agregar otra verificación, dependiendo de si le importa el infinito o no, y qué resultado desea obtener si x
es infinito.
Un código de ejemplo recortado que lo hace:
if ( ABS( ((int) d1) - (d1)) )< 0.000000001)
cout <<"Integer" << endl;
else
cout <<"Flaot" << endl;
EDITAR: Se modificó para reflejar el código correcto.
Use std::modf
:
double intpart;
modf(value, &intpart) == 0.0
No convertir a int
! El número 1.0e+300
es un número entero, ¿sabes?
Editar: Como señala Pete Kirkham, pasa el 0 ya que el segundo argumento no está garantizado por el estándar para funcionar, lo que requiere el uso de una variable ficticia y, por desgracia, hace que el código sea mucho menos elegante.
avakar estaba casi en lo cierto, usa modf, pero el detalle estaba apagado.
modf devuelve la parte fraccional, por lo que la prueba debería ser que el resultado de modf es 0.0.
modf toma dos argumentos, el segundo de los cuales debe ser un puntero del mismo tipo que el primer argumento. Pasar NULL o 0 causa un error de segmentación en el tiempo de ejecución de g ++. La norma no especifica que pasar 0 es seguro; podría ser que funcione en la máquina de Avakar pero no lo haga.
También puede usar fmod(a,b)
que calcula el módulo b
pasando 1.0. Esto también debería dar la parte fraccionaria.
#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
}
tratar:
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;
}
#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
}
}
int iHaveNoFraction(double d){
return d == trunc(d);
}
Ahora, no sería C si no tuviera aproximadamente 40 años de revisiones de lenguaje ...
En C, ==
devuelve int
pero en C ++ devuelve bool
. Al menos en mi distribución Linux (Ubuntu) necesitas declarar double trunc(double);
o puede compilar con -std=c99
, o declarar el macro de nivel, todo con el fin de obtener <math.h>
para declararlo.