Vous ne pouvez pas utiliser le module sur les doubles?

185

J'ai un programme en C ++ (compilé avec g ++). J'essaie d'appliquer deux doubles comme opérandes à la fonction de module, mais j'obtiens l'erreur suivante:

erreur: opérandes non valides des types 'double' et 'double' en binaire 'opérateur%'

Voici le code:

int main() {
    double x = 6.3;
    double y = 2;
    double z = x % y;
}
Bhaxy
la source
12
Comme cela a été noté, fmod () fournit la fonction nécessaire. Comme cela n'a pas encore été noté, il est important de comprendre que les erreurs d'arrondi dans le deuxième opérande de fmodpeuvent provoquer des comportements inattendus. Par exemple, fmod(1, 0.1);devrait mathématiquement être nul, mais sera en fait presque 0,1. L'ampleur de l'erreur augmente avec la magnitude du quotient. Par exemple, fmod(9E14, 0.1);évalue à environ 0,05, ce qui est tout simplement faux d'un point de vue mathématique.
supercat
1
@supercat plus de détails serait génial. Je pense avoir une idée de ce qui se passe dans les coulisses pour que ce que vous dites soit vrai, mais ce serait bien de voir les raisons pour lesquelles ce que vous dites est vrai; serait intéressant de voir comment cela fonctionne dans les coulisses (je pense que je comprends mais pourrait très facilement se tromper).
RastaJedi
3
Les valeurs à virgule flottante représentent des multiples entiers exacts ou des fractions de puissances de deux. Par exemple, le littéral entier 0,1 est exactement 3602879701896397/36028797018963968 (cette dernière valeur est une puissance de deux). fmod(x,0.1)divisera x par cette fraction précise et prendra le reste, plutôt que de diviser par la valeur numérique "un dixième".
supercat

Réponses:

272

L' %opérateur est pour les entiers. Vous recherchez la fmod()fonction .

#include <cmath>

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

}
Mysticial
la source
Je programme en C ++ pour Qt et fmod a un bogue. Le résultat de fmod (angle, 360) peut être 360 ​​(WAT?!)
Paul
7
@Paul: Ce n'est probablement pas un bug. Si anglec'est, par exemple, 359.9999999alors les deux angleet fmod(angle, 360)sont susceptibles d'être affichés sous la forme 360. (Ajoutez plus de 9 si nécessaire.) Essayez d'imprimer les valeurs avec, par exemple, 50 chiffres de précision.
Keith Thompson
Le format QString :: de @Paul Qt s'arrondira. Si c'est aussi critique, vous devrez soit vous arrondir ou vérifier la sortie pour "360" et le remplacer par votre propre valeur.
jfh
38

fmod(x, y) est la fonction que vous utilisez.

MSN
la source
5

Utiliser à fmod()partir de <cmath>. Si vous ne souhaitez pas inclure le fichier d'en-tête 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 sceptique
la source
3
Pourquoi ne voudriez-vous pas inclure le fichier d'en-tête C? C'est pour ça qu'il est là.
Keith Thompson
2

Vous pouvez implémenter votre propre fonction de module pour le faire pour vous:

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

Ensuite , vous pouvez simplement utiliser dmod(6.3, 2)pour obtenir le reste, 0.3.

Mystique
la source
Ce n'est toujours pas une solution parfaite. x = 10.499999999999998, y = 0.69999999999999996 renvoie 0.69999999999999929 au lieu de 0.0
tarpista