Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

CW_Kovok

Alter Hase

  • »CW_Kovok« ist der Autor dieses Themas

Beiträge: 836

Wohnort: nähe Bonn

Beruf: Schüler

  • Private Nachricht senden

1

20.02.2006, 16:30

[FAQ]Sinusprobleme

also hab folgendes testprog:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <iostream>
#include <ctime>
#include <cmath>

using namespace std;

float FastSin0(const float& fAngle)
{
    float fASqr = fAngle*fAngle;
    float fResult = 7.61e-03f;
    fResult *= fASqr;
    fResult -= 1.6605e-01f;
    fResult *= fASqr;
    fResult += 1.0f;
    fResult *= fAngle;
    return fResult;
}

int main(void)
{
    long start, ende;
    float a1, a2, a3, a4;

    start = clock();
    
    for(float i=0.0f; i<360.0f; i=i+0.0001f)
        FastSin0(i);

    ende = clock();

    a2 = float(ende-start);
    cout<<"FastSin0 fertig"<<endl;

    start = clock();
    
    for(float i=0.0f; i<360.0f; i=i+0.0001f)
        sinf(i);

    ende = clock();

    a3 = float(ende-start);
    cout<<"sinf fertig"<<endl;

    start = clock();
    
    for(float i=0.0f; i<360.0f; i=i+0.0001f)
        sin(i);

    ende = clock();

    a4 = float(ende-start);
    cout<<"sin fertig"<<endl;

    cout<<"sinf: "<<a3/CLOCKS_PER_SEC<<" entspricht: "<<a3/a3*100<<"%"<<endl;
    cout<<"sin: "<<a4/CLOCKS_PER_SEC<<" entspricht: "<<a3/a4*100<<"%"<<endl;
    cout<<"FastSin0: "<<a2/CLOCKS_PER_SEC<<" entspricht: "<<a3/a2*100<<"%"<<endl;

    return 0;
}

also ausgabe erhalte ich immer sowas:

Zitat


FastSin0 fertig
sinf fertig
sin fertig
sinf: 0.39 entspricht: 100%
sin: 0.5 entspricht: 78%
FastSin0: 0.313 entspricht: 124.601%
Drücken Sie eine beliebige Taste . . .


lohnt sich dafür ne optimierung von FastSin0? Oder ist der speed gewinn zu gering?
Was es alles gibt, das ich nich brauche - Aristoteles

rewb0rn

Supermoderator

Beiträge: 2 773

Wohnort: Berlin

Beruf: Indie Game Dev

  • Private Nachricht senden

2

20.02.2006, 16:41

Sieht doch ganz gut aus.. Aber ich versteh nicht genau wie du FastSin berechnest, also wie da der Sinus draus werden soll. Kannste das mal erklären? Vor allem der Fehler würde mich interessieren
Normalerweise werden solche Funktionen übrigens mit einem Taylorpolynom approximiert, bei dem die Genauigkeit festlegbar ist, du könntest dir also selber eine Sinusfunktion schreiben, die eine parametrisierte Genauigkeit hat. Wenn dich das interessiert kann ichs dir erklären, aber nicht, dass ich mir die Arbeit umsonst mache^^

Black-Panther

Alter Hase

Beiträge: 1 443

Wohnort: Innsbruck

  • Private Nachricht senden

3

20.02.2006, 16:43

Ich denk mal, dass es drauf ankommt wie oft du diese Funktionen benutzt. Etwas wird es sicherlich bringen!

Edit:
@Spike
Mich würde das interessieren!!
stillalive studios
Drone Swarm (32.000 Dronen gleichzeitig steuern!)
facebook, twitter

DarkFitzi

Alter Hase

Beiträge: 608

Wohnort: Eisenberg, Thüringen

Beruf: Schüler, 10te Klasse

  • Private Nachricht senden

4

20.02.2006, 16:53

@Spike
mich auch ^^
jez zeig mal was de gelernt hast :-D
Ich würde die Welt gern verbessern, doch Gott gibt mir den Sourcecode nicht! :-(

CW_Kovok

Alter Hase

  • »CW_Kovok« ist der Autor dieses Themas

Beiträge: 836

Wohnort: nähe Bonn

Beruf: Schüler

  • Private Nachricht senden

5

20.02.2006, 16:55

der fehler liegt bei <1.7*10e-4 funktioniert jedoch nur im bereich zwischen 0 und neunzig grad, habe ich aus dem buch von David h. Eberly, sie soll schneller sein als taylorentwicklung, werde das aber mal testen, denn mit assembler und son bischen kram müsste das gehen, hier übrigens eine genauere Aproximation:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
float FastSin1(float fAngle)
{
    float fASqr = fAngle*fAngle;
    floaz fResult = -2.39e-08f;
    fResult *= fASqr;
    fResult += 2.7526e-06f;
    fResult *= fASqr;
    fResult -= 1.98409e-04f;
    fResult *= fASqr;
    fResult += 8.3333315e-03f;
    fResult *= fASqr;
    fResult -= 1.666666664e-01f;
    fResult *= fASqr;
    fResult += 1.0f;
    fResult *= fAngle;
    return fResult;
}

mit nem fehler <5*10e-9, hab aber noch nich getestet wie schnell er ist. Dann noch taylor, fällt jemand noch ne schnellere Variante ein?
Was es alles gibt, das ich nich brauche - Aristoteles

Anonymous

unregistriert

6

20.02.2006, 17:04

Hi!

Wieso speicherst du nicht jedes Grad den korrekten Sinus in einem Array
und approximierst dann linear zwischen zwei benachbarten Werten?

Ich weiß zwar nicht wie groß der Fehler da maximal ist, aber der Wert
ließe sich dann so ermitteln:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
const float sintab[90] = { ... 90 korrekte Sinus-Werte (vorberechnet) ... };

float mysin(float w)
{
  int wi = (int)floor(w);
  
  float s1 = sintab[wi];
  float s2 = sintab[wi+1];

  return (s2-s1)/(w-wi)+s1;
}


Evtl. ist das noch schneller...hab aber keine Messungen jetzt gemacht ;)

Grüße
Stefan

rewb0rn

Supermoderator

Beiträge: 2 773

Wohnort: Berlin

Beruf: Indie Game Dev

  • Private Nachricht senden

7

20.02.2006, 17:12

ok *geradehinsetz* *kippeanmach*

die Taylorreihe: Summe(k=0 bis unendlich) aus (k-te Ableitung der Funktion an Stelle x0 durch k Fakultät multipliziert mit (x - x0) hoch k), wobei x der Funktionswert ist.

Das Taylorpolynom ist nun nicht die Summe von 0 bis unendlich sondern von 0 bis n, also eine teilsumme. je größer n desto genauer das ergebnis.

Für die Sinusfunktion sieht das implementiert dann so aus:


C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
float TnSin(float x, unsigned short n)
{
    float Tn = 0;
    for (unsigned short k = 0; k<n; k++)
        Tn += (DerivativeSinX0(k) / fac(k)) * pow(x, k);
    return Tn;
}

float DerivativeSinX0(unsigned short k)
{
    while (k>3) k -= 4;
    switch(k)
    {
    case 0: return 0; //sin 0

    case 1: return 1; //cos 0

    case 2: return 0; //-sin 0

    case 3: return -1; //-cos 0

    }
}


So. fac soll die Fakultätsfunktion sein, bin mir nich sicher. Ob das mit der case Struktur so klappt weiß ich auch nicht, habs nich getestet. DerivativeSinX0 gibt den Funktionswert der kten Ableitung von Sin an der Stelle 0 zurück. An der Stelle pow(x, k) müsste egtl x-0, k stehen. Die Ableitungswerte sind ausm Kopf, evtl ma nachgucken, also sin, cos, -sin, -cos jeweils an der Stelle 0. Danach gehts wieder von vorne los.

Der Fehler hängt von x0 und n ab. am Besten mal experimentieren. Die Taylorreihe ist übrigens auch nicht zwingend fehlerlos. der Fehler ist
(R = DerivativeSin(n+1, Xi) / fac(n+1)) * pow(x, n+1))
wobei Xi zwischen x und x0 liegt und so gewählt wird, das der schlimmste Fall eintritt, dementsprechend ist die Taylorreihe nur dann fehlerfrei, wenn der lim n gegen unendlich von R = 0 ist. Kann man ausrechnen, muss man aber nicht.

Werte für n = 10 sind schon ziemlich genau. kommt bei euch was falsches raus, hab ich mich irgendwo vertan.

CW_Kovok

Alter Hase

  • »CW_Kovok« ist der Autor dieses Themas

Beiträge: 836

Wohnort: nähe Bonn

Beruf: Schüler

  • Private Nachricht senden

8

20.02.2006, 17:14

2 Probleme: erstens ungenau, zweitens speicheranfällig, für hohe genauigkeit muss die lookuptabelle sehr genau sein, aber ich habe hier noch was interessantes:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#include <iostream>
#include <ctime>
#include <cmath>

using namespace std;

float FastSin0(const float& fAngle)
{
    float fASqr = fAngle*fAngle;
    float fResult = 7.61e-03f;
    fResult *= fASqr;
    fResult -= 1.6605e-01f;
    fResult *= fASqr;
    fResult += 1.0f;
    fResult *= fAngle;
    return fResult;
}

float FastSin1(const float& fAngle)
{
    float fASqr = fAngle*fAngle;
    float fResult = -2.39e-08;

    fResult *= fASqr;
    fResult += 2.7526e-06f;
    fResult *= fASqr;
    fResult -= 1.98409e-04f;
    fResult *= fASqr;
    fResult += 8.3333315e-03f;
    fResult *= fASqr;
    fResult -= 1.666666664e-01f;
    fResult *= fASqr;
    fResult += 1.0f;
    fResult *= fAngle;

    return fResult;
}

int main(void)
{
    long start, ende;
    float a1, a2, a3, a4;

    float pi = atan(1.0f)*2.0f; //da nur halbes pi korrekt


    start = clock();
    
    for(float i=0.0f; i<pi; i=i+0.000001f)
        FastSin0(i);

    ende = clock();

    a1 = float(ende-start);
    cout<<"FastSin0 fertig"<<endl;

    start = clock();
    
    for(float i=0.0f; i<pi; i=i+0.000001f)
        FastSin1(i);

    ende = clock();

    a2 = float(ende-start);
    cout<<"FastSin1 fertig"<<endl;

    start = clock();
    
    for(float i=0.0f; i<pi; i=i+0.000001f)
        sinf(i);

    ende = clock();

    a3 = float(ende-start);
    cout<<"sinf fertig"<<endl;

    start = clock();
    
    for(float i=0.0f; i<pi; i=i+0.000001f)
        sin(i);

    ende = clock();

    a4 = float(ende-start);
    cout<<"sin fertig"<<endl;

    cout<<"sinf: "<<a3/CLOCKS_PER_SEC<<" entspricht: "<<a3/a3*100<<"%"<<endl;
    cout<<"sin: "<<a4/CLOCKS_PER_SEC<<" entspricht: "<<a3/a4*100<<"%"<<endl;
    cout<<"FastSin0: "<<a2/CLOCKS_PER_SEC<<" entspricht: "<<a3/a1*100<<"%"<<endl;
    cout<<"FastSin1: "<<a2/CLOCKS_PER_SEC<<" entspricht: "<<a3/a2*100<<"%"<<endl;

    return 0;
}
Das Problem ist nun die Ausgabe:

Zitat

FastSin0 fertig
FastSin1 fertig
sinf fertig
sin fertig
sinf: 0.172 entspricht: 100%
sin: 0.219 entspricht: 78.5388%
FastSin0: 0.219 entspricht: 122.857%
FastSin1: 0.219 entspricht: 78.5388%
Drücken Sie eine beliebige Taste . . .
Interessanterweise sind sin und fastSin1 immer gleichschnell, nur zur taylorentwicklung, wie viele glieder sollten es denn mindestens sein?
Was es alles gibt, das ich nich brauche - Aristoteles

rewb0rn

Supermoderator

Beiträge: 2 773

Wohnort: Berlin

Beruf: Indie Game Dev

  • Private Nachricht senden

9

20.02.2006, 17:15

hab ich oben reineditiert ;)

rewb0rn

Supermoderator

Beiträge: 2 773

Wohnort: Berlin

Beruf: Indie Game Dev

  • Private Nachricht senden

10

20.02.2006, 17:21

Zitat von »"CW_Kovok"«

2 Probleme: erstens ungenau, zweitens speicheranfällig, für hohe genauigkeit muss die lookuptabelle sehr genau sein

Stichwort Template-Metaprogrammierung. Dritter Artikel in Game Programming Gems 1, ansonsten mal googlen.

Werbeanzeige