¿No se puede usar el módulo en dobles?

185

Tengo un programa en C ++ (compilado usando g ++). Estoy tratando de aplicar dos dobles como operandos a la función de módulo, pero aparece el siguiente error:

error: operandos no válidos de los tipos 'double' y 'double' a binario 'operator%'

Aquí está el código:

int main() {
    double x = 6.3;
    double y = 2;
    double z = x % y;
}
Bhaxy
fuente
12
Como se ha observado, fmod () proporciona la función necesaria. Como aún no se ha observado, es importante darse cuenta de que los errores de redondeo en el segundo operando de fmodpueden causar comportamientos inesperados. Por ejemplo, fmod(1, 0.1);matemáticamente debería ser cero, pero de hecho será casi 0.1. La extensión del error aumenta con la magnitud del cociente. Por ejemplo, se fmod(9E14, 0.1);evalúa a aproximadamente 0.05, que es desde un punto de vista matemático simplemente erróneo.
supercat
1
@supercat más detalles sería increíble. Creo que tengo una idea de lo que está sucediendo detrás de escena para hacer que lo que dices sea cierto, pero sería bueno ver las razones de por qué lo que dices es cierto; Sería interesante ver cómo funciona detrás de escena (creo que lo entiendo, pero podría estar equivocado muy fácilmente).
RastaJedi
3
Los valores de punto flotante representan múltiplos enteros exactos o fracciones de potencias de dos. Por ejemplo, el entero literal 0.1 es exactamente 3602879701896397/36028797018963968 (el último valor es una potencia de dos). fmod(x,0.1)dividirá x entre esa fracción precisa y tomará el resto, en lugar de dividirlo por el valor numérico "una décima".
supercat

Respuestas:

272

El %operador es para enteros. Estás buscando la fmod()función .

#include <cmath>

int main()
{
    double x = 6.3;
    double y = 2.0;
    double z = std::fmod(x,y);

}
Místico
fuente
Estoy programando en C ++ para Qt y fmod tiene un error allí. El resultado de fmod (ángulo, 360) puede ser 360 (¡¿QUÉ ?!)
Paul
77
@Paul: Eso probablemente no sea un error. Si anglees, digamos, 359.9999999entonces ambos angley fmod(angle, 360)es probable que se muestren como 360. (Agregue más 9 seg. Según sea necesario). Intente imprimir los valores con, digamos, 50 dígitos de precisión.
Keith Thompson el
El formato QString :: de @Paul Qt se redondeará. Si es tan crítico, tendrá que redondearse o verificar el resultado de "360" y reemplazarlo con su propio valor.
jfh
38

fmod(x, y) es la función que usas.

MSN
fuente
5

Utilice fmod()partir <cmath>. Si no desea incluir el archivo de encabezado C:

template<typename T, typename U>
constexpr double dmod (T x, U mod)
{
    return !mod ? x : x - mod * static_cast<long long>(x / mod);
}

//Usage:
double z = dmod<double, unsigned int>(14.3, 4);
double z = dmod<long, float>(14, 4.6);
//This also works:
double z = dmod(14.7, 0.3);
double z = dmod(14.7, 0);
double z = dmod(0, 0.3f);
double z = dmod(myFirstVariable, someOtherVariable);
Jule escéptico
fuente
3
¿Por qué no querrías incluir el archivo de encabezado C? Para eso está ahí.
Keith Thompson el
2

Puede implementar su propia función de módulo para hacer eso por usted:

double dmod(double x, double y) {
    return x - (int)(x/y) * y;
}

A continuación, puede utilizar dmod(6.3, 2)para obtener el resto, 0.3.

Místico
fuente
Aún no es una solución perfecta. x = 10.499999999999998, y = 0.69999999999999996 devuelve 0.69999999999999929 en lugar de 0.0
tarpista