Kann das Modul nicht für Doppel verwendet werden?

184

Ich habe ein Programm in C ++ (kompiliert mit g ++). Ich versuche, zwei Doppelte als Operanden auf die Modulfunktion anzuwenden, erhalte jedoch den folgenden Fehler:

Fehler: Ungültige Operanden vom Typ 'double' und 'double' zum binären 'Operator%'

Hier ist der Code:

int main() {
    double x = 6.3;
    double y = 2;
    double z = x % y;
}
Bhaxy
quelle
12
Wie bereits erwähnt, bietet fmod () die erforderliche Funktion. Wie noch nicht bemerkt wurde, ist es wichtig zu wissen, dass Rundungsfehler im zweiten Operanden von fmodzu unerwartetem Verhalten führen können. Zum Beispiel fmod(1, 0.1);sollte mathematisch Null sein, wird aber tatsächlich fast 0,1 sein. Das Ausmaß des Fehlers steigt mit der Größe des Quotienten. Zum Beispiel fmod(9E14, 0.1);ergibt sich ein Wert von ungefähr 0,05, was aus mathematischer Sicht einfach falsch ist.
Supercat
1
@supercat mehr Details wäre super. Ich denke, Sie haben eine Vorstellung davon, was sich hinter den Kulissen abspielt, damit das, was Sie sagen, wahr ist, aber es wäre gut, die Gründe dafür zu sehen, warum das, was Sie sagen, wahr ist. Es wäre interessant zu sehen, wie es hinter den Kulissen funktioniert (ich glaube ich verstehe, könnte aber sehr leicht falsch liegen).
RastaJedi
3
Gleitkommawerte repräsentieren exakte ganzzahlige Vielfache oder Bruchteile von Zweierpotenzen. Beispielsweise ist das ganzzahlige Literal 0.1 genau 3602879701896397/36028797018963968 (der letztere Wert ist eine Zweierpotenz). fmod(x,0.1)dividiert x durch diesen genauen Bruch und nimmt den Rest, anstatt durch den numerischen Wert "ein Zehntel" zu dividieren.
Supercat

Antworten:

272

Der %Operator ist für ganze Zahlen. Sie suchen die fmod()Funktion .

#include <cmath>

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

}
Mystisch
quelle
Ich programmiere in C ++ für Qt und fmod hat dort einen Fehler. Das Ergebnis von fmod (Winkel, 360) kann 360 (WAT?!) Sein
Paul
7
@ Paul: Das ist wahrscheinlich kein Fehler. Wenn dies anglebeispielsweise der Fall ist, werden 359.9999999beide angleund fmod(angle, 360)wahrscheinlich als angezeigt 360. (Fügen Sie nach Bedarf weitere 9s hinzu.) Versuchen Sie, die Werte beispielsweise mit einer Genauigkeit von 50 Stellen zu drucken.
Keith Thompson
Das QString :: -Format von @Paul Qt wird gerundet. Wenn es so kritisch ist, müssen Sie sich entweder selbst runden oder die Ausgabe auf "360" prüfen und durch Ihren eigenen Wert ersetzen.
26.
38

fmod(x, y) ist die Funktion, die Sie verwenden.

MSN
quelle
5

Verwenden Sie fmod()von <cmath>. Wenn Sie die C-Header-Datei nicht einschließen möchten:

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);
Skeptischer Jule
quelle
3
Warum sollten Sie die C-Header-Datei nicht einschließen? Dafür ist es da.
Keith Thompson
2

Sie können Ihre eigene Modulfunktion implementieren, um dies für Sie zu tun:

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

Dann können Sie einfach verwenden dmod(6.3, 2), um den Rest zu erhalten 0.3.

Mystisch
quelle
Immer noch keine perfekte Lösung. x = 10.499999999999998, y = 0.69999999999999996 gibt 0.69999999999999929 statt 0.0
tarpista