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

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

}

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.


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

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.


Aún no es una solución perfecta. x = 10.499999999999998, y = 0.69999999999999996 devuelve 0.69999999999999929 en lugar de 0.0
tarpista
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.