Willkommen ~Gast!
Registrieren || Einloggen || Hilfe/FAQ || Staff
Probleme mit der Registrierung im Forum? Melde dich unter registerEin Bild.
Autor Beitrag
000
02.06.2002, 20:33
Diablo_bth



eigentlich is dass ja eine Frechheit wenn man z.B. so etwas is der math.h zu lesen bekommt:
Quellcode:
inline float sinf(float _X)
        {return ((float)sin((double)_X)); }

da benutzt man extra 32-bit-float anstatt double und dann sowas! Ok in einem Source habe ich dann sowas entdekt:
Quellcode:
__forceinline static
__declspec(naked) float __fastcall
fsin(float a)
{
    __asm {
        fld        DWORD PTR [esp+4]
        fsin
        ret 4
    }
}

__forceinline static
__declspec(naked) float __fastcall
fcos(float a)
{
    __asm {
        fld        DWORD PTR [esp+4]
        fcos
        ret 4
    }
}

Das ist fast genau doppelt so schnell wie das normale sin/cos. Mein Problem ist jetzt dass ich von Assmbler nicht wirklich was verstehe, aber das ganze gerne auch für tan, asin, acos, atan und sqrt ( sqrtf() is auch so eine verarsche! ) hätte.
Nicht dass ich das nicht versucht hätte, doch wenn ich nun anstatt fcos z.B. ftan hinschreibe gibts einen Fehler.
Kann mir da jemand weiterhelfen?

--


Dieser Beitrag wurde am 02.06.2002 um 20:34 von Diablo_bth bearbeitet.
zum Seitenanfang zum Seitenende Profil || Suche
001
02.06.2002, 20:47
Ferdi



du hast sin und cos...
wie wärs mit tan(x) = sin(x) / cos(x) ?

nur ein vorschlag um dass Problem zu umgehen aber es gibt sicher auch ne bessere Variante

--

zum Seitenanfang zum Seitenende Profil || Suche
002
02.06.2002, 20:52
Diablo_bth



ähh ich glaube Du hast mich nicht ganz verstanden?! es gibt natürlich auch ein tan( double ), ich will das aber für float optimiert haben! So wie ich das in den beiden Beispielfunktionen gezeigt habe!

--

zum Seitenanfang zum Seitenende Profil || Suche
003
02.06.2002, 22:25
Ferdi



ich glaube du verstehst mich eher falsch...aber egal...

--

zum Seitenanfang zum Seitenende Profil || Suche
004
02.06.2002, 23:55
Kriz



Nicht meckern, selber programmieren =)

--

K:R-I)Z++
"CSS ist cascading style sheets. Und nicht so'n Ranzspiel." - dp
In memory of Voice († 2005/03/30)

zum Seitenanfang zum Seitenende Profil || Suche
005
03.06.2002, 01:36
Tron



es ist nur halbe verarsche
der rueckgabewert in form von fliesskommazahlen wird ueber st0 (das erste fpu register) gehandhabt, da ist es voellig egal ob das nun float, double oder gar long double ist.
wie es mit der parameteruebergabe aussieht haengt vermutlich von der schlaeue des optimierers ab.
ich empfehle: einfach mal profilen, ob es langsamer langsamer ist.
das normale sin/cos ist vermutlich deshalb langsamer, da ANSI-C(++) sehr genaue vorgaben bzgl. rundung macht und das vor jedem groesere flieskommabtrechnung eingestellt wird, was die ganze sache natuerlich enorm verlangsamt
ich werd nacher mal bissl wuehlen und schauen wie die assemblerbefehle fuer die uebrigen operationen lauten.

btw: im quake sourcecode ist eine sehr gute 1/sqrt(x) funktion drin, das is zwar der uebelst gehackteste kleine bastard, den ich je gesehen habe, aber dafuer sauschnell.
such mal im forum von www.flipcode.com , da gab es mal einen thread ueber sowas

--

'KEINE PANIK' - aus der Triologie in fuenf Baenden von Douglas Adams

'FÜR DEINN FERD' - aus 'Gevatter Tod' von Terry Pratchett

zum Seitenanfang zum Seitenende Profil || Suche
006
03.06.2002, 22:43
[PE]Spinator



@Diablo_bth: Ferdi hat schon recht, wenn du optimierte funktionen für cos und sin hast, dann kannst du dir ne tan aus diesen beiden basteln... allzugross ist der speed verlust sicher nit...

--

This post was written using Opera 7.0 (http://www.opera.com)

zum Seitenanfang zum Seitenende Profil || Suche
007
03.06.2002, 23:03
Diablo_bth



wow krass geil ich hab voll den Exzess darüber gefunden:
http://www.flipcode.com/cgi-bin/msg.cgi?showThread=00002548&forum=3dtheory&id=-1

@Spinator, Ferdi: ihr habt nicht wirklich recht, da ich ein wenig recherchiert habe. Ihr könnt ja mal so eine Funktion basteln und die mit der hier vergleichen: ( ich bin sicher dass ist schneller als alles was ihr je gesehen habt!! )
Quellcode:
__forceinline /* inline */ static
__declspec( naked ) float __fastcall
ftan( float )
{
  __asm {
    fld    dword ptr [esp+4]
    fptan
    fstp  dword ptr [esp+4]
    ret    4
  }
}

@Tron: da waren nun schon ein paar ganz gute Ansätze für sqrtf, tanf, arcsin/cos.
Die haben aber z.B. sowas hier gemacht:
Quellcode:
float asm_arccos( float r ) {
  // return half_pi + arctan( -r / sqr( 1.f - r * r ) );
  const float asm_one = 1.f;
  const float asm_half_pi = half_pi;
  __asm {
    fld r
    fld r
    fmul r
    fsubr asm_one
    fsqrt
    fstp r
    fchs
    fdiv r
    fld1
    fpatan
    fadd asm_half_pi
  }
}

Wenn man dann den asm-code anschaut ist da noch viel unnötiges Zeug drin
wie zB. das pushes un popen von ebx, den Aufruf von __checkesp und anderes Zeug was ich nicht verstanden habe. Da habe mich nun mal selbst mit der Materie beschäftigt und die Performance dieser Funktionen etwas gesteigert. Der code funktioniert, ich bin mir aber seiner Fehlerfreiheit nicht 100%ig sicher. Zumindest wird das esp ( was immer das auch ist ) durch den Funktionaufruf nicht verändert. [ damit hatte ich anfags probleme ]
( ich poste einfach mal alle in meiner fmath.h, vielleicht interessiert das noch jemand )
Quellcode:

__forceinline /* inline */ static
__declspec( naked ) float __fastcall
fsin( float )
{
  __asm {
    fld    dword ptr [esp+4]
    fsin
    ret    4
  }
}

__forceinline /* inline */ static
__declspec( naked ) float __fastcall
fcos( float )
{
  __asm {
    fld    dword ptr [esp+4]
    fcos
    ret    4
  }
}

__forceinline /* inline */ static
__declspec( naked ) float __fastcall
ftan( float )
{
  __asm {
    fld    dword ptr [esp+4]
    fptan
    fstp  dword ptr [esp+4]
    ret    4
  }
}

__forceinline /* inline */ static
__declspec( naked ) float __fastcall
fasin( float )
{
  // return arctan( r / sqr( 1.0f - r * r ) );
  __asm {
    push  ebp
    mov    ebp,esp
    sub    esp,44h

    mov    dword ptr [ebp-4],3F800000h  //  1.0f;

    fld    dword ptr [ebp+8]  // r0 = r
    fld    dword ptr [ebp+8]  // r1 = r0, r0 = r
    fmul  dword ptr [ebp+8]  // r0 = r0 * r
    fsubr  dword ptr [ebp-4]  // r0 = r0 - 1.0f
    fsqrt            // r0 = sqrtf( r0 )
    fdiv            // r0 = r1 / r0
    fld1            // r0 =
    fpatan            // atan( r0 )

    mov    esp,ebp
    pop    ebp
    ret    4
  }
}

__forceinline /* inline */ static
__declspec( naked ) float __fastcall
facos( float )
{
  // return half_pi + arctan( r / -sqr( 1.0f - r * r ) );
  __asm {
    push  ebp
    mov    ebp,esp
    sub    esp,48h

    mov    dword ptr [ebp-4],3F800000h  //  1.0f;
    mov    dword ptr [ebp-8],3FC90FDBh  //  M_HALFPI;

    fld    dword ptr [ebp+8]  // r0 = r
    fld    dword ptr [ebp+8]  // r1 = r0, r0 = r
    fmul  dword ptr [ebp+8]  // r0 = r0 * r
    fsubr  dword ptr [ebp-4]  // r0 = r0 - 1.0f
    fsqrt            // r0 = sqrtf( r0 )
    fchs            // r0 = - r0
    fdiv            // r0 = r1 / r0
    fld1            // r0 =
    fpatan            // atan( r0 )
    fadd  dword ptr [ebp-8]  // r0 = r0 + pi / 2

    mov    esp,ebp
    pop    ebp
    ret    4
  }
}

__forceinline /* inline */ static
__declspec( naked ) float __fastcall
fatan( float )
{
  __asm {
    fld    dword ptr [esp+4]
    fld1
    fpatan
    fstp  dword ptr [esp+4]
    fld    dword ptr [esp+4]
    ret    4
  }
}

__forceinline /* inline */ static
__declspec( naked ) float __fastcall
fsqrt( float )
{
  __asm {
    fld    dword ptr [esp+4]
    fsqrt
    ret    4
  }
}

__forceinline /*inline*/ static
__declspec( naked ) float __fastcall
fabsf( float )
{
  __asm {
    push  ebp
    mov    ebp,esp
    sub    esp,44h

    mov    dword ptr [ebp-4],00000000h  //  0.0f;

    fld    dword ptr [ebp+8]
    fcomp  dword ptr [ebp-4]

    fnstsw  ax
    test  ah,1
    je    groesser    // größer als 0.0f ?

    fld    dword ptr [ebp+8]
    fchs  // *= -1.0f

    mov    esp,ebp
    pop    ebp

    ret    4

groesser:
    fld    dword ptr [ebp+8]

    mov    esp,ebp
    pop    ebp

    ret    4
  }
}

#define  M_HALFPI      1.5707963267948966192313216916397f
#define M_PI        3.1415926535897932384626433832795f
#define M_2PI        6.2831853071795864769252867665590f
#define M_PIOVER180      0.0174532925199432957692369076848f  // M_PI / 180.0
#define M_NPIOVER180    57.295779513082320876798154817014f  // M_PIOVER180 ^ (-1.0)

#define SIN( x )      ( fsin((x) * M_PIOVER180) )
#define COS( x )      ( fcos((x) * M_PIOVER180) )
#define TAN( x )      ( ftan((x) * M_PIOVER180) )

#define ASIN( x )      ( fasin(x) * M_NPIOVER180 )
#define ACOS( x )      ( facos(x) * M_NPIOVER180 )
#define ATAN( x )      ( fatan(x) * M_NPIOVER180 )

P.S.: was ist das esp eigentlich genau? Es fühlt sich zumindest so an
die die direkte Speicher-Hauptschlagader

*edit*
wenn jemand noch einen Vorschlag für atan2() hätte soll er das doch bitte posten

--


Dieser Beitrag wurde am 03.06.2002 um 23:10 von Diablo_bth bearbeitet.
zum Seitenanfang zum Seitenende Profil || Suche
008
04.06.2002, 00:49
Tron



esp ist der stackpointer (Extended Stack Pointer, extended, da 32bit breit)
ueber den stack werden die parameter uebergeben

--

'KEINE PANIK' - aus der Triologie in fuenf Baenden von Douglas Adams

'FÜR DEINN FERD' - aus 'Gevatter Tod' von Terry Pratchett

zum Seitenanfang zum Seitenende Profil || Suche