Gibt es eine schnellere Sinusfunktion?

25

Ich arbeite an Generation 3D Perlin Rauschen. Die C # Math-Bibliothek scheint zu viel für das zu sein, was ich brauche, da die meisten ihrer Funktionen Double Percision verwenden. Ich benutze Math.Sin () an mehreren Stellen, um das Rauschen zu erzeugen. Kennt jemand eine schnellere Sinusfunktion?

user2709
quelle

Antworten:

32

Sie können eine Parabel verwenden, um den Wert der Sinusfunktion zu approximieren. Dies hat den Vorteil, dass die Wurzeln genau bei -pi / 2 und pi / 2 liegen, was bei anderen schnellen Approximationen auf der Basis der TaylorSeries oder MaclaurinSeries normalerweise nicht der Fall ist .

public float Sin(float x)
{
    const float B = 4 / PI;
    const float C = -4 / (PI*PI);

    return -(B * x + C * x * ((x < 0) ? -x : x));
} 

Hier ein Vergleich zur aktuellen Sinusfunktion:

Alt-Text

Zfedoran
quelle
3
Dies ist in der Tat eine großartige Lösung. Hier ist ein ausgezeichneter Artikel von devmaster.net, der beschreibt, warum dies funktioniert, und einige Implementierungsdetails enthält: devmaster.net/forums/showthread.php?t=5784
Hall
Ich kenne C # nicht, aber die abs () - Funktion ist in den meisten C-Umgebungen bei Optimierung wahrscheinlich schneller als eine Verzweigung (der?: -Operator).
3
Ich habe den Aufruf von Math.Abs ​​() entfernt, weil ich angenommen habe, dass dieser Code auf der Xbox 360 oder Windows Phone 7 ausgeführt werden kann. Der JIT-Compiler auf der Xbox 360 integriert nichts. Ein Aufruf von Math.Abs ​​() ist tatsächlich teurer.
Zfedoran
@reverbb Link ist 404. Hier ist eine zwischengespeicherte Kopie.
Daniel Pendergast
1
@zfedoran Warum negieren Sie den Rückgabewert? Es scheint eine negative Sinuswelle zu sein.
Daniel Pendergast
12

Was ist der Bereich der Eingabewerte für Ihre sin () - Funktion? Für was Sie es verwenden, klingt es so, als wären sie begrenzt, was bedeutet, dass Sie die Werte vorberechnen könnten . Wenn Sie beispielsweise die Eingabewerte auf den nächsten Grad aufrunden, haben Sie nur 360 mögliche Werte - berechnen Sie sie einfach vor und speichern Sie sie in einer Tabelle.

Wenn Sie etwas mehr Werte benötigen, z. B. eine Dezimalstelle, können Sie aus der Tabelle interpolieren. Perlin-Rauschen ist mir nicht vertraut , aber das Wort "Rauschen" scheint darauf hinzudeuten, dass keine hohe Genauigkeit erforderlich ist. :) (Sie könnten auch einfach eine größere Tabelle erstellen, 3600 Einträge sind nicht viel Platz).

Zyklop
quelle
3
Wenn Geschwindigkeit Ihr wichtigstes Anliegen ist und es Ihnen nichts ausmacht, ein bisschen Genauigkeit zu opfern, ist dies die beste Antwort.
AttackingHobo
1
Ich weiß nicht wie "am besten" - Wie in einer anderen Antwort gezeigt, können Sie eine weitere sehr gute Annäherung in fünf Operationen + abs erhalten (deren Geschwindigkeit von Ihrem Arch / Compiler abhängt, aber oft verzweigungslos ist). Wenn sich die Nachschlagetabelle nicht im Cache befindet, ist sie viel langsamer.