Float vs Double Performance

91

Ich habe einige Timing-Tests durchgeführt und auch einige Artikel wie diesen gelesen (letzter Kommentar). In Release-Builds benötigen Float- und Double-Werte dieselbe Verarbeitungszeit.

Wie ist das möglich? Wenn float im Vergleich zu doppelten Werten weniger genau und kleiner ist, wie kann die CLR in derselben Verarbeitungszeit verdoppelt werden?

Joan Venge
quelle
10
Ich denke nicht, dass es ein genaues Duplikat ist, da dieses den Grund dafür fragt, wo der andere Benutzer fragt, ob es tatsächlich schneller ist, aber nicht unbedingt warum
Joan Venge
Angeblich ein genaues Duplikat von Sind Doppelte schneller als Floats in C #? (behauptet im Jahr 2009 von einem anderen Benutzer).
Peter Mortensen

Antworten:

153

Zumindest auf x86-Prozessoren floatund doublewird von der FPU zur Verarbeitung jeweils in ein 10-Byte-Real konvertiert. Die FPU verfügt nicht über separate Verarbeitungseinheiten für die verschiedenen unterstützten Gleitkommatypen.

Der uralte Ratschlag, der floatschneller ist als vor double100 Jahren, als die meisten CPUs keine eingebauten FPUs hatten (und nur wenige Leute separate FPU-Chips hatten), so dass die meisten Gleitkomma-Manipulationen in Software durchgeführt wurden. Auf diesen Maschinen (die durch Dampf erzeugt durch die Lavagruben angetrieben wurden), es war schneller zu bedienen floats. Der einzige wirkliche Vorteil von floats ist, dass sie weniger Platz beanspruchen (was nur wichtig ist, wenn Sie Millionen von ihnen haben).

P Papa
quelle
9
Vielleicht noch nicht vor 100 Jahren ... Einige FPUs unterstützen das native Handling auf Float-, Double- und 80-Bit-Ebene und werden bei kürzeren Längen schneller ausgeführt. Einige werden tatsächlich einige Dinge auch bei kürzeren Längen langsamer ausführen ... :-)
Brian Knoblauch
4
Mögliche Ausnahme: Ich denke, die Zeit für Divisionen hängt von der Anzahl der Bits ab (1 Taktzyklus / 2 Bits). Timings, die ich von Float gegen Double Division gemacht habe, scheinen damit übereinzustimmen.
Neil Coffey
21
Vorsichtsmaßnahme für SIMD-Code - Da Sie 2x Floats als Double in ein SIMD-Register (z. B. SSE) packen können, kann der Betrieb mit Floats möglicherweise schneller sein. Aber da es C # ist, wird das wahrscheinlich nicht passieren.
Calyth
13
@P Daddy: Ich würde sagen, der Platzvorteil ist auf jeder Ebene der Cache-Hierarchie von Bedeutung. Wenn Ihr Datencache der ersten Ebene 16 KB groß ist und Sie ein Array von 4000 Zahlen knacken, kann Float leicht schneller sein.
Peter G.
4
@artificialidiot Sag niemals nie;). SIMD wird in .NET seit 4.6
Ghord
13

Ich hatte ein kleines Projekt, in dem ich CUDA verwendet habe, und ich kann mich daran erinnern, dass Float auch dort schneller als doppelt so hoch war. Ausnahmsweise ist der Verkehr zwischen Host und Gerät geringer (Host ist die CPU und der "normale" RAM und Gerät ist die GPU und der entsprechende RAM dort). Aber selbst wenn sich die Daten ständig auf dem Gerät befinden, sind sie langsamer. Ich glaube, ich habe irgendwo gelesen, dass sich dies in letzter Zeit geändert hat oder mit der nächsten Generation ändern soll, aber ich bin mir nicht sicher.

Es scheint also, dass die GPU in diesen Fällen einfach nicht mit doppelter Genauigkeit nativ umgehen kann, was auch erklären würde, warum GLFloat normalerweise anstelle von GLDouble verwendet wird.

(Wie gesagt, es ist nur so weit ich mich erinnern kann, bin nur darauf gestoßen, als ich auf einer CPU nach float vs. double gesucht habe.)

Mene
quelle
5
GPUs sind völlig andere Tiere als FPUs. Wie bereits erwähnt, ist das native Format der FPU die doppelte Genauigkeit von 80 Bit. Und das schon lange. GPUs nähern sich diesem Bereich jedoch mit einfacher Genauigkeit. Es ist bekannt, dass ihre DP FP-Leistung (Double Precision Floating Point) oft genau die Hälfte der SP FP-Leistung beträgt. Es scheint, dass sie häufig SP-Gleitkommaeinheiten haben und die Einheit wiederverwenden müssen, um die doppelte Genauigkeit abzudecken. Das ergibt genau zwei Zyklen im Vergleich zu einem. Das ist ein großer Leistungsunterschied , der mich verblüfft hat, als ich damit konfrontiert wurde.
Csaba Toth
1
Einige wissenschaftliche Berechnungen erfordern DP FP, und die führenden GPU-Hersteller haben die damit verbundene Leistungsbeeinträchtigung nicht angekündigt. Jetzt scheinen sie (AMD, nVidia) das Thema DP gegen SP etwas zu verbessern. Der viele Kern von Intel Xeon Phi enthält die FPUs von Pentium. Intel hat die doppelte Genauigkeit hervorgehoben . Dort kann es vielleicht wirklich mit GPGPU-Monstern konkurrieren.
Csaba Toth
12

Es gibt jedoch immer noch Fälle, in denen Floats bevorzugt werden. Bei der OpenGL-Codierung wird beispielsweise der GLFloat-Datentyp (im Allgemeinen direkt dem 16-Bit-Float zugeordnet) weitaus häufiger verwendet, da er auf den meisten GPUs effizienter ist als GLDouble.

Cruachan
quelle
3
Möglicherweise aufgrund eines höheren Datendurchsatzes? Wenn Sie eine Zahlenmatrix (Z-Puffer usw.) haben, wird die Datengröße wichtiger und die Vermeidung von Konvertierungen zwischen Float und Double beschleunigt die Verarbeitung. Meine Vermutung.
Lucero
2
Zweifellos Durchsatz. Angesichts des speziellen Kontexts ist es unwahrscheinlich, dass durch die Verwendung von Double-over-Floats etwas sichtbar wird. Warum also den Speicher verschwenden - insbesondere, da er auf GPUs kürzer als auf CPUs ist
Cruachan
1
Durchsatz und auch die Tatsache, dass SP FP (Gleitkomma mit einfacher Genauigkeit) eher das native Format der GPU-internen FPUs ist als DP FP (doppelte Genauigkeit). Siehe meinen Kommentar zu @ Menes Antwort. GPUs und CPU-FPUs sind sehr unterschiedliche Tiere, die FPU der CPU denkt in DP-FP.
Csaba Toth
12

Dies hängt vom 32-Bit- oder 64-Bit- System ab. Wenn Sie auf 64-Bit kompilieren, ist double schneller. Kompiliert auf 32-Bit auf 64-Bit (Maschine und Betriebssystem), schwebte um 30% schneller:

    public static void doubleTest(int loop)
    {
        Console.Write("double: ");
        for (int i = 0; i < loop; i++)
        {
            double a = 1000, b = 45, c = 12000, d = 2, e = 7, f = 1024;
            a = Math.Sin(a);
            b = Math.Asin(b);
            c = Math.Sqrt(c);
            d = d + d - d + d;
            e = e * e + e * e;
            f = f / f / f / f / f;
        }
    }

    public static void floatTest(int loop)
    {
        Console.Write("float: ");
        for (int i = 0; i < loop; i++)
        {
            float a = 1000, b = 45, c = 12000, d = 2, e = 7, f = 1024;
            a = (float) Math.Sin(a);
            b = (float) Math.Asin(b);
            c = (float) Math.Sqrt(c);
            d = d + d - d + d;
            e = e * e + e * e;
            f = f / f / f / f / f;
        }
    }

    static void Main(string[] args)
    {
        DateTime time = DateTime.Now;
        doubleTest(5 * 1000000);
        Console.WriteLine("milliseconds: " + (DateTime.Now - time).TotalMilliseconds);

        time = DateTime.Now;
        floatTest(5 * 1000000);
        Console.WriteLine("milliseconds: " + (DateTime.Now - time).TotalMilliseconds);

        Thread.Sleep(5000);
    }
Bitter blau
quelle
2
Haben Sie gedacht, dass diese 30% auf die zusätzlichen Besetzungen zurückzuführen sind, die Sie verwenden?
Rasmus Damgaard Nielsen
@RasmusDamgaardNielsen Die Casts sind Teil des Problems, da sie Mathmit Double funktionieren. Aber Sie haben meinen Beitrag falsch verstanden: Meine Tests haben gezeigt, dass ich in der Leistung besser schwebe.
Bitterblue
2
Die oben veröffentlichten Ergebnisse sind falsch. Meine Tests zeigen, dass auf einem älteren 32-Bit-Computer mit .NET 4.0 im Release-Modus Leistung floatund doubleLeistung praktisch identisch sind. Unterschied von weniger als 0,3% im Durchschnitt über viele unabhängige Versuche, bei denen jeder Versuch Multiplikations-, Divisions- und Additionsoperationen für nacheinander verkettete Variablen durchführte (um zu vermeiden, dass Compiler-Optimierungen im Weg stehen). Ich habe eine zweite Reihe von Tests mit Math.Sin()und versucht Math.Sqrt()und auch identische Ergebnisse erhalten.
Spezielle Sauce