Portal-Zone Gothic-Zone Gothic II-Zone Gothic 3-Zone Gothic 4-Zone Modifikationen-Zone Download-Zone Foren-Zone RPG-Zone Almanach-Zone Spirit of Gothic

 

Seite 1 von 3 123 Letzte »
Ergebnis 1 bis 20 von 56
  1. Homepage besuchen Beiträge anzeigen #1 Zitieren
    Exodus Avatar von Sektenspinner
    Registriert seit
    Jul 2004
    Ort
    Karlsruhe
    Beiträge
    7.827
     
    Sektenspinner ist offline

    [Instrumentarium] Floats

    In einem Thema über Distanzenberechnung hat mich Sumpfkrautjunkie darüber aufgeklärt, dass Gothic gar keine Berechnungen mit float-Werten unterstützt.
    Mir war das vorher nicht bekannt und vermutlich sind auch sonst noch nicht viele Modder darüber gestolpert.

    Halb aus Spaß, halb aus Trotz habe ich mich nun hingesetzt und floats in Daedalus implementiert. Das Script möchte ich hier allen, die es brauchen zur Verfügung stellen.
    Mir ist bewusst, dass es eine Spezialanwendung ist und vermutlich, ähnlich wie mein Script zu arrays, wenig Anwendung finden wird. Wer sich mit Ikarus auseinandersetzt wird auch durchaus über floats stolpern und die hier vorgestellten Funktionen nutzen können um mit ihnen umzugehen.

    Das Skript hat keine Abhängigkeiten zu anderen Skripten und enthält eine Dokumentation zu den zur Verfügung stehenden Funktionen:
    Code:
    //#################################################################
    //
    //  32 bit IEEE 754 floats (kurz: Gleitkommazahlen) für Daedalus:
    //      Script vom 26.11.2008, erstellt von Sektenspinner
    //
    //  Es wird NICHT der vollständige IEEE 754 Standard unterstützt
    //  Es gibt Unterschiede in Spezialfällen und Rundungsfehler.
    //  Das grundsätzliche Format wird aber eingehalten, sodass
    //  auch mit Engine-Floats gerechnet werden kann.
    //
    //  Bugfix am 19.03.2010:
    //      Grober Fehler: Exponent war stets um eins falsch.
    //      Das fiel auf, da durch die neue "Forschung" auch
    //      "externe floats" aus der Engine aus den Scripten
    //      erreichbar sind.
    //  Bugfix am 1.07.2010:
    //      Grober Fehler: mulf lieferte stets positive Ergebnisse
    //      Danke an orcwarriorPL!
    //  Bugfix am 23.09.2010:
    //      Behoben sind:
    //          -Problem in truncf bei sehr kleinen Zahlen
    //          -Problem in addf falls Exponenten sich um
    //           mehr als 31 unterscheiden.
    //          -Subtraktion von zwei gleichen Zahlen ergibt nun
    //           null (anstatt ~2^(-23) mal diese Zahl)
    //          -Die Funktionen sollten nun beliebig schachtelbar sein.
    //      Danke an mud-freak!
    //  Erweiterung am 5.2.2011:
    //      -fracf hinzugefügt, danke an orcwarriorPL!
    //  Erweiterung am 7.4.2011:
    //      -sqrtf_approx hinzugefügt, geschrieben von Lehona
    //  Performanceverbesserung 8.4.2011:
    //      -sqrtf beschleunigt, Dank gebührt Lehona
    //
    //#################################################################
    
    /*####################################
    //      Kurzdokumentation
    //####################################
    
    //*********************
    //  Grundsätzliches
    //*********************
    
    32-bit Floats der Genauigkeit "single" werden mit den in diesem Script enthaltenen Funktionen auf einem gewöhnlichen integer simuliert. Dabei ist darauf zu achten floats und integer trotz des formal gleichen Datentyps penibel zu unterscheiden. Wenn eine Zahl in Floatdarstellung mit einer Zahl in Integerdarstellung verrechnet wird oder Funktionen auf integer angewendet werden, die eigentlich für floats gedacht sind oder umgekehrt kommt im besten Fall einfach nur Blödsinn heraus. Normalerweise meckert in so einem Fall der Compiler, Gothic kennt aber den Unterschied nicht!
    
    //************************************
    //  Das Instrumentarium
    //************************************
    
    Um mit floats rechnen zu können, müssen diese zunächst erzeugt werden. Dazu gibt es eine Abbildung mkf, die eine integer Ganzzahl in einen float umwandelt.
    floats können untereinander addiert, subtrahiert, multipliziert und dividiert werden. Eine Wurzelfunktion ist ebenfalls definiert.
    Um den Wert der floats intepretieren zu können, sind die Ordnungsrelationen >=, >, <, <= mit den Funktionen ge, g, l, le gegeben.
    Ferner können floats mit der truncf und roundf Funktion zurück in einen integer konvertiert werden.
    
    //************************************
    //  Die Funktionen im Überblick:
    //************************************
    
    "func float" und "var float" wie hier angegeben gibt es nicht wirklich (für Gothic sind alles integer). Diese Notation soll hier nur zur Veranschaulichung dienen.
    Um sich die Funktionsnamen merken zu können hilft vielleicht folgende Liste, die die Abkürzungen erklärt:
    
    mkf    = make float
    truncf = truncate float
    roundf = round float
    addf   = add floats
    subf   = subtract floats
    negf   = negate float
    mulf   = multiply floats
    divf   = divide floats
    invf   = inverse float
    gf     = greater
    gef    = greater or equal
    lf     = lower
    lef    = lower or equal
    sqrtf  = square root of float
    printf = print float
    
    **************** Umwandlung *******************
    func float mkf (var int x) //Erzeugt die Floatdarstellung aus einer Ganzzahl.
    func int truncf (var float x) //reduziert einen float auf seinen Ganzzahlanteil, wobei alle Nachkommastellen verworfen werden. Der Ergebnistyp ist Integer. (-1.5 würde zu -1.0, nicht zu -2)
    func int roundf (var float x) //reduziert einen float auf eine Ganzzahl, die durch Runden ermittelt wird. Wie truncf, nur das zuvor 0.5 addiert wird. Der Ergebnistyp ist Integer.
    
    **************** Addition *********************
    func float addf (var float x, var float y) //addiert x und y und gibt das Ergebnis zurück.
    func float subf (var float x, var float y) //subtrahiert y von x und gibt das Ergebnis zurück.
    func float negf (var float x) //Gibt das additive Inverse von x (also -x) zurück.
    
    **************** Multiplikation ***************
    func float mulf (var float x, var float y) //multipliziert x und y miteinander und gibt das Ergebnis zurück.
    func float divf (var float x, var float y) //dividiert x durch y und gibt das Ergebnis zurück.
    func float invf (var float x) //Gibt das multiplikative Inverse des floats x, also 1/x zurück. Gibt für x = 0 einen Fehler aus.
    func float fracf (var int p, var int p) //Gibt den Bruch p/q als float zurück. Äquivalent zu divf(mkf(p), mkf(q))
    
    **************** Ordnungsrelationen ***********
    func int gf (var float x, var float y) //gibt für x > y TRUE zurück, sonst FALSE
    func int gef (var float x, var float y) //gibt für x >= y TRUE zurück, sonst FALSE
    func int lef (var float x, var float y) //gibt für x <= y TRUE zurück, sonst FALSE
    func int lf (var float x, var float y) //gibt für x < y TRUE zurück, sonst FALSE
    
    **************** Verschiedene *****************
    func float sqrtf (var float x) //gibt die Wurzel des floats x zurück. Gibt für negative x einen Fehler aus.
    func float sqrtf_approx (var float x) //berechnet die Wurzel erheblich performanter als sqrtf aber möglicherweise ungenauer
    func void printf (var float x) {}; //gibt einen float als Kommazahl auf dem Bildschirmaus. Diese Funktion funktioniert für sehr große und sehr kleine x nicht richtig.
    
    //************************************
    //  Sonstiges
    //************************************
    
    Es sind fünf float Konstanten definiert, die genutzt werden können, ohne dass sie erst berechnet/erzeugt werden müssen:
    
    FLOATNULL = 0
    FLOATEINS = 1
    FLOATHALB = 0.5
    PI = 3.1415...
    E = 2.7182...
    
    //************************************
    //  Beispiele
    //************************************
    
    Folgende Funktion soll das Volumen eines Zylinders in cm³ berechnen und gerundet zurückgeben:
    
    func int Zylindervolumen (var int radius, var int hoehe) {
        var int radiusf, var int hoehef;
        radiusf = mkf (radius);
        hoehef = mkf (hoehe);
    
        //Volumen = r² * PI * h
    
        var int ergebnisf;
        ergebnisf = mulf (radiusf, radiusf);
        ergebnisf = mulf (ergebnisf, PI);
        ergebnisf = mulf (ergebnisf, h);
    
        return roundf (ergebnisf);
    };
    
    Folgende Funktion berechnet eine Zahl und gibt sie auf dem Bildschirm aus. Sie schachtelt dabei manche Funktionen
    
    func void antwort () {
        var int foo;
    
        foo = mulf (mkf (1337), PI);
        printf (divf (foo, mkf (100)));
    
        //(1337*PI)/100 ist verblüffend genau 42. ;-)
    };
    
    Folgende Funktion macht ein paar Vergleiche. Es wird in keinem Fall "FEHLER" ausgegeben.
    
    func void floattest()
    {
        var int halb; var int eins; var int zwei;
        var int null;
        var int minuseins; var int minuszwei;
    
        halb = invf (mkf (2));
        eins = mkf (1);
        zwei = mkf (2);
        null = mkf (0);
        minuseins = mkf (-1);
        minuszwei = mkf (-2);
    
        if (gf (zwei,eins))           {} else { print ("FEHLER!"); };
        if (gf (eins,null))           {} else { print ("FEHLER!"); };
        if (lf (minuseins,null))      {} else { print ("FEHLER!"); };
        if (lf (minuszwei,minuseins)) {} else { print ("FEHLER!"); };
        if (gf (halb,minuseins))      {} else { print ("FEHLER!"); };
        if (lf (halb,zwei))           {} else { print ("FEHLER!"); };
        if (lef (null,null))          {} else { print ("FEHLER!"); };
        if (gef (null,null))          {} else { print ("FEHLER!"); };
    };
    
    //************************************
    //  Beschränkungen und Fallen
    //************************************
    
    ***********  Nutzerfehler ************
    Es sollten unter keinen Umständen die Operatoren +, -, * oder / auf floats angewendet werden. Sie haben dort keine sinnvolle Anwendung. Bestensfalls kommt einfach nur Blödsinn heraus. Wie oben beschrieben sind addf, subf, mulf und divf anzuwenden.
    Wer versteht wie ein float intern aufgebaut ist, kann zum Beispiel innerhalb der positiven Zahlen die Ordnungsrealtionen (>, <, <= >=) benutzen. Wer sich nicht sicher ist, sollte auf die gegebenen Funktionen zurückgreifen.
    Natürlich sind umgekehrt die Floatfunktionen für Integer unbrauchbar. Der Ausdruck sqrtf (4) ist nicht 2 sondern einfach nur falsch, da 81 ein Integer ist!
    
    *********** Float-Fehler *************
    Die Genauigkeit der floats ist sehr begrenzt, ab etwa 4 Dezimalstellen ist mit Rundungsfehlern zu rechnen. Dafür können sehr große und sehr kleine Zahlen dargestellt werden.
    Es gelten die gewöhnlichen Einschränkungen und Empfehlungen für floats. Zum Beispiel ist es selten sinnvoll floats auf Gleichheit zu überprüfen, da es durch Rundungsfehler wahrscheinlich ist, dass auch zwei floats, die eigentlich gleich sein müssten kleine Abweichungen zueinander aufweisen. Es sollte in einem solchen Fall besser geprüft werden, ob die Differenz der beiden floats einen (im Verhältnis zur Problemstellung) kleinen Wert unterschreitet.
    
    //************************************
    //  Vielen Dank...
    //************************************
    
    ...dass du dich für dieses Script interessierst und es gelesen, oder zumindest überflogen hast. Dann war meine Arbeit nicht ganz umsonst. ;-)
    Mir ist allerdings bewusst, dass dies wohl eher ein Randgebiet des Gothicmoddings ist.
    
    Edit: März 2010: Haha! Mit direktem Zugriff auf zEngine Objekte ist dies mitnicht ein Randgebiet! Es lassen sich einige hochinteressante Floatwerte in Gothic finden!
    
    */
    
    //#################################################################
    //
    //  DIE FUNKTIONEN
    //
    //#################################################################
    
    const int BIT_VZ = 1; //Vorzeichen hat 1 Bit (was auch sonst?!)
    const int BIT_EXP = 8; //nach IEEE 754 ist 8 die Norm
    const int BIT_MT = 23; //bleiben 23 bit für die Mantisse
    const int EXP_OFFSET = 127; //exp = characteristic - EXP_OFFSET
    
    const int EXP_PATTERN = ((1 << BIT_EXP) - 1) << BIT_MT;
    const int MT_PATTERN = ((1 << BIT_MT) - 1);
    
    const int MINUS = 1 << 31;
    const int MININT = 1 << 31;
    const int MAXINT = MININT - 1;
    
    const int FLOATNULL = 0; //vz 0, exp -128, mt 1.0 //nicht echt 0! Aber so ziemlich. Damit die Vergleiche gut funktionieren. Letztendlich ist der Wert aber egal. FLOATNULL ist ein Symbol mit dem nicht gerechnet wird.
    const int FLOATEINS = 1065353216; //vz 0, exp 0 (also 127), mt 1.0
    const int FLOATHALB = 1056964608; //vz 0, exp -1 (also 126), mt 1.0
    
    const int PI = 1078530011;
    const int E =  1076754516;
    
    //************************************
    //  Interne Hilfsfunktionen
    //************************************
    
    func int HighestBitPos (var int x) {
        if (x == 0) {
            return 0;
        }
        else {
            return 1 + HighestBitPos (x >> 1);
        };
    };
    
    func int extractExp (var int x) {
        var int exp;
        exp = x & EXP_PATTERN;
        exp = exp >> BIT_MT;
        exp = exp - EXP_OFFSET; //wegen Vergleichen ist der exponent verschoben
    
        return exp;
    };
    
    func int extractMt (var int x) {
        var int mt;
        mt = x & MT_PATTERN;
        //das erste bit, was gespart wurde wieder hin:
        mt = mt | (1 << BIT_MT);
    
        return mt;
    };
    
    func int packExp (var int exp) {
        //exponent -> Charakteristik -> und schieben
        return (exp + EXP_OFFSET) << BIT_MT;
    };
    
    //************************************
    //      float bauen:
    //************************************
    
    func int mkf (var int x) {
        var int result; result = 0;
        //das Vorzeichen bit
        if (x < 0) {
            result = MINUS;
            x = -x;
        };
    
        var int exp;
        exp = HighestBitPos (x) - 1;
    
        if (exp < 0) { //kann nur heißen, dass die Zahl null ist
            return FLOATNULL;
        };
    
        //Dass die erste Zahl eine 1 ist, ist ja wohl klar, also wird sie abgeschnitten:
        x = x & (~(1 << exp));
    
        //Und jetzt packe ich das ganze in einen float:
        result = result | packExp(exp); //den Exponenten neben die Mantisse schieben.
    
        if (BIT_MT > exp) {
            return result | (x << (BIT_MT - exp)); //Die Mantisse wird nach vorne geschoben, aber eben nur soweit Platz ist
        }
        else {
            return result | (x >> (exp - BIT_MT));
        };
    };
    
    //************************************
    //  Rückumwandlung zu integer
    //************************************
    
    func int truncf (var int x) {
        //Sonderbehandlung für das Symbol NULL
        if (x == FLOATNULL) {
            return 0;
        };
    
        var int exp; exp = extractExp (x); //Exponenten holen
        var int mt; mt = extractMt (x); //Mantisse holen
    
        var int result;
    
        //Überläufe:
        if (exp >= 31) { //2^31 * 1.0 läuft ins Vorzeichenbit rein!
            if (x > 0) {
                return MAXINT;
            } else {
                return MININT;
            };
        };
    
        //schneidet
        if (exp > BIT_MT) {
            result = mt << (exp - BIT_MT); //Mantisse zurechtschieben
        }
        else {
            //32 bit oder mehr schieben geht schief.
            if (BIT_MT - exp > 31) {
                return 0;
            };
    
            result = mt >> (BIT_MT - exp);
        };
    
        if (x < 0) {
            return - result;
        }
        else {
            return result + 0;
        };
    };
    
    //************************************
    //  Addition
    //************************************
    
    func int addf (var int x, var int y) {
        var int expX; expX = extractExp (x);
        var int expY; expY = extractExp (y);
        var int mtX; mtX = extractMt (x);
        var int mtY; mtY = extractMt (y);
        var int isnegX; isnegX = x & MINUS;
        var int isnegY; isnegY = y & MINUS;
    
        //Sonderbehandlung für das Symbol NULL
        if (x == FLOATNULL) {
            return y + 0;
        }
        else if (y == FLOATNULL) {
            return x + 0;
        };
    
        //Die Betragsmäßig kleinere Zahl an die größere anpassen
        if (expX > expY)
        {
            if (expX - expY > 31) {
                //dann schlagen die folgenden shiftoperationen fehl.
                //Aber x ist soviel größer als y, einfach x zurückgeben.
                return x + 0;
            };
    
            mtY = mtY >> (expX - expY);
            expY = expX;
        }
        else
        {
            if (expY - expX > 31) {
                //dann schlagen die folgenden shiftoperationen fehl.
                //Aber y ist soviel größer als x, einfach y zurückgeben.
                return y + 0;
            };
    
            mtX = mtX >> (expY - expX);
            expX = expY;
        };
    
        //Das Ergebnis berechnen:
        var int mtRes;
        if (isnegX) {
            mtRes = -mtX;
        }
        else {
            mtRes = mtX;
        };
    
        if (isnegY) {
            mtRes -= mtY;
        }
        else {
            mtRes += mtY;
        };
    
        var int isnegRes;
        if (mtRes < 0) {
            isnegRes = MINUS;
            mtRes = -mtRes;
        }
        else {
            isnegRes = 0;
        };
    
        //Präzisierung:
        if (!mtRes) { //damit abziehen eines Wertes von sich selbst präzise ist.
            return FLOATNULL;
        };
    
        var int shift;
        shift = HighestBitPos (mtRes) - (BIT_MT + 1);
    
        if  (shift > 0) {
            mtRes = mtRes >> shift;
        }
        else {
            mtRes = mtRes << (-shift);
        };
    
        //Noch die erste Zahl abschneiden (also zuschneiden):
        mtRes = mtRes & ((1 << BIT_MT) - 1);
    
        var int expRes;
        expRes = expX + shift;
    
        return isnegRes | packExp(expRes) | mtRes;
    };
    
    //************************************
    //  Es lassen sich vier kleine
    //  nützliche Hilfsfunktionen
    //  definieren:
    //************************************
    
    func int negf (var int x) {
        if (x < 0) { return x & (~MINUS); }
        else { return x | MINUS; };
    };
    
    func int absf (var int x) {
        if (x < 0) { return negf (x); }
        else       { return x + 0; };
    };
    
    func int subf (var int x, var int y) {
        return addf (x, negf (y));
    };
    
    func int roundf (var int x) {
        if (x < 0) {
            return truncf (subf (x, FLOATHALB));
        } else {
            return truncf (addf (x, FLOATHALB));
        };
    };
    
    //************************************
    //  Multiplikation
    //************************************
    
    func int mulf (var int x, var int y) {
        var int expX; expX = extractExp (x);
        var int expY; expY = extractExp (y);
        var int mtX; mtX = extractMt (x);
        var int mtY; mtY = extractMt (y);
        var int isnegX; isnegX = x & MINUS;
        var int isnegY; isnegY = y & MINUS;
    
        //Sonderbehandlung für das Symbol NULL
        if (x == FLOATNULL)
        || (y == FLOATNULL) {
            return FLOATNULL;
        };
    
        //Die Exponenten werden addiert
        var int expRes;
        expRes = expX + expY;
    
        //Die Mantissen multipliziert (wobei auf die 32 bit Grenze geachtet werden muss)
        var int mtRes;
        mtRes = (mtX >> (BIT_MT - 14)) * (mtY >> (BIT_MT - 14));
        mtRes = mtRes >> (28 - BIT_MT);
    
        if (mtRes >= (1 << (BIT_MT + 1)))
        {
            mtRes = mtRes >> 1;
            expRes += 1;
        };
    
        //Noch die erste Zahl abschneiden (also die Mantisse zuschneiden):
        mtRes = mtRes & ((1 << BIT_MT) - 1);
    
        var int isNegRes;
        if (isnegX == isnegY) {
            isNegRes = 0;
        }
        else {
            isNegRes = MINUS;
        };
    
        //noch Erkenntnisse zusammenfügen
        return isnegRes | packExp(expRes) | mtRes;
    };
    
    //************************************
    //  Die Division lässt sich
    //  nicht auf die Multiplikation
    //  zurückführen. Das multiplikative
    //  Inverse ist schließlich schwerer
    //  zu finden, als das additive
    //  Inverse. Also, gesonderte Funktion:
    //************************************
    
    func int divf (var int x, var int y) {
        var int expX; expX = extractExp (x);
        var int expY; expY = extractExp (y);
        var int mtX; mtX = extractMt (x);
        var int mtY; mtY = extractMt (y);
        var int isnegX; isnegX = x & MINUS;
        var int isnegY; isnegY = y & MINUS;
    
        //Sonderbehandlung für das Symbol NULL
        if (y == FLOATNULL) {
            Print ("### ERROR: DIVISION BY ZERO ###");
            return FLOATNULL;
        }
        else if (x == FLOATNULL) {
            return FLOATNULL;
        };
    
        //Exponent subtrahieren
        var int expRes;
        expRes = expX - expY;
    
        //Die Mantissen dividieren, davor Divident und Divisor passend hinschieben
        var int mtRes;
        mtRes = (mtX << (7)) / (mtY >> 9); //X soweit es geht nach links, Y auf die Mitte
        mtRes = mtRes << (BIT_MT - 7 - 9);
    
        //Und das Ergebnis wieder zurückschieben
        if (mtRes < (1 << (BIT_MT))) {
            mtRes = mtRes << 1;
            expRes -= 1;
        };
    
        //Noch die erste Zahl abschneiden (also die Mantisse zuschneiden):
        mtRes = mtRes & ((1 << BIT_MT) - 1);
    
        var int isNegRes;
        if (isnegX == isnegY) {
            isNegRes = 0;
        }
        else {
            isNegRes = MINUS;
        };
    
        //noch Erkenntnisse zusammenfügen
        return isnegRes | packExp(expRes) | mtRes;
    };
    
    //************************************
    //  Kleine Hilfsfunktion
    //************************************
    
    func int invf (var int x) {
        return divf (FLOATEINS, x);
    };
    
    /* thanks to orcwarriorPL for the idea! */
    func int fracf (var int p, var int q) {
        return divf(mkf(p), mkf(q));
    };
    
    //************************************
    //  Wurzelziehen
    //************************************
    
    func int sqrtf_hlp (var int target, var int guess, var int steps) {
        //babylonisches Wurzelziehen / Heron
        guess = addf (guess, divf (target, guess));
        guess = mulf (FLOATHALB, guess);
    
        if (steps == 0) {
            return guess;
        } else {
            return sqrtf_hlp (target, guess, steps - 1);
        };
    };
    
    func int sqrtf (var int x) {
        if (x < FLOATNULL) {
            Print ("ERROR: sqrtf: x must be nonnegative.");
    
            return FLOATNULL;
        };
        
        //guess wird der Startwert des Heronverfahrens
        //der Exponent von guess soll der halbe Exponent von x sein.
        var int e;
    	e = ExtractExp(x);
    	e = e/2;
        var int guess;
        guess = packExp(e); //Mantisse ist egal.
        
        //4 ist schon eher viel. Man kann hier auch auf 3 runtergehen.
        //ab 4 dürfte sich das Ergebnis spätestens stabilisiert haben.
        return sqrtf_hlp (x, guess, 4) + 0;
    };
    
    //Schnelles Wurzelziehen von Lehona getreu dem Wikipedia Artikel:
    // http://en.wikipedia.org/wiki/Fast_inverse_square_root
    
    func int sqrtf_approx(var int f) {
        var int x2f;
        var int threehalfs;
        if (!threehalfs) {
            threehalfs = addf(FLOATEINS, FLOATHALB);
        };
    
        x2f = mulf(f, FLOATHALB);
    
        f = 1597463007 /* 5F3759DFh */ - (f >> 1);
        return invf(mulf(f, subf(threehalfs, mulf(x2f, mulf(f,f)))));
    };
    
    //************************************
    //  Ordnungsrelationen
    //************************************
    
    func int gf (var int x, var int y) {
        var int isnegX; isnegX = x & MINUS;
        var int isnegY; isnegY = y & MINUS;
    
        if (isNegX && isNegY) { //beide negativ
            if (x < y) {
                return TRUE;
            };
        }
        else {
            if (x > y) {
                return TRUE;
            };
        };
    
        return FALSE;
    };
    
    func int gef (var int x, var int y) {
        if (gf (x,y)) || (x == y) {
            return TRUE;
        };
        return FALSE;
    };
    
    func int lef (var int x, var int y) {
        if (!gf (x,y)) {
            return TRUE;
        };
        return FALSE;
    };
    
    func int lf (var int x, var int y) {
        if (!gef (x,y)) {
            return TRUE;
        };
        return FALSE;
    };
    
    //************************************
    //  Ausgabefunktionen
    //************************************
    
    func string BuildNumberHlp (var string res, var int x, var int kommapos) {
        if (kommapos == 0) {
            res = ConcatStrings (",", res);
            res = ConcatStrings (IntToString (x), res);
    
            return res;
        };
    
        res = ConcatStrings (IntToString (x % 10), res);
    
        return BuildNumberHlp (res, x / 10, kommapos - 1);
    };
    
    func string BuildNumber (var string res, var int x, var int kommapos) {
        if (x < 0) {
            return ConcatStrings ("-", BuildNumberHlp (res, -x, kommapos));
        }
        else {
            return BuildNumberHlp (res, x, kommapos);
        };
    };
    
    func void printf (var int x) { //Ok, ok sorry c-ler. Aber ich will konsistente Namen haben.
        //Ich bekomme nur eine primitive Darstellung als Kommazahl hin.
        //für die Darstellung als X * 10^EXP fehlen mir Ideen oder Logarithmusfunktionen
    
        x = mulf (x, mkf (10000));
        x = truncf (x);
    
        Print (BuildNumber ("", x, 4));
    };
    Edit: Um synaktische floats (var float) in diese andere Darstellung umzuwandeln (um damit rechnen zu können) oder umgekehrt (zum Beispiel zur Übergabe an externe Funktionen wie FloatToString) gibt es folgende Lösung, die aber auf dem Ikarus Skriptpaket aufbaut:

    Code:
    //************************************
    //		Aus Integerfloat einen
    //		syntaktischen float machen
    //************************************
    
    func float cast_int2float (var int pf) {
    	//Schiebe Float auf den Stack:
    	MEMINT_StackPushInst (pf);
    	MEMINT_StackPushInst (zPAR_TOK_PUSHINT);
    	//Aufrufer kann ihn in einen Float popen.
    };
    
    //************************************
    //		Rückrichtung:
    //		Aus syntaktischem float	
    //		einen Integerfloat machen
    //************************************
    
    var int cast_float2int_result;
    func void cast_float2int_Hlp1 (var float f, var int i) {};
    func int cast_float2int_Hlp2 () {
    	/* Wird aufgerufen, wenn f (also der Parameter von cast_float2int)
    	 * gerade auf dem Stack liegt.
    	 * f jetzt vorzeitig runterholen: */
    	cast_float2int_result = MEMINT_StackPopInt();
    	
    	/* Irgendwas anderes wieder draufschieben: */
    	MEMINT_StackPushInst (FLOATNULL);
    	MEMINT_StackPushInst (zPAR_TOK_PUSHINT);
    };
    
    func int cast_float2int (var float f) {
    	/* Parser-Data-Stackhacking hat mit floats Probleme
    	 * da Funktionen keine floats zurückgeben können.
    	 * Lösung: Einen float bekommt man durch einen Funktionsaufruf
    	 * auf den Stack. Durch folgenden Code wird f auf den Stack
    	 * gelegt, danach cast_float2int_Hlp2 aufgerufen
    	 * cast_float2int_Hlp2 wird f vom Stack holen. */
    	cast_float2int_Hlp1 (f, cast_float2int_Hlp2());
    	return cast_float2int_result;
    };
    cast_int2float wandelt hierbei einen float in Integer Darstellung in einen syntaktischen float um. cast_float2int kann umgekehrt einen syntaktischen Float in Integer Darstellung bringen, sodass dieses Paket damit rechnen kann.
    Für Spieler:
    Velaya # Velaya in English # Exodus Demo # Irrwichtel
    Tools für Modder:
    DiaDepp # DOPA-PARTER # zSlang
    Scripte für Modder:
    Ikarus Skriptpaket # Floats # Broadcasts
    Geändert von Sektenspinner (08.04.2011 um 22:18 Uhr)

  2. Homepage besuchen Beiträge anzeigen #2 Zitieren
    Ritter Avatar von Watschnbaum
    Registriert seit
    Feb 2008
    Ort
    Sag mal wo lebst du..... ts....
    Beiträge
    1.719
     
    Watschnbaum ist offline
    Könntest du einem laien erklären was floats sind?

    Und was für Anwendungszwecke bringen die?

  3. Beiträge anzeigen #3 Zitieren
    Provinzheld Avatar von BlackNapalm
    Registriert seit
    Feb 2007
    Ort
    Oberstenfeld (BW)
    Beiträge
    242
     
    BlackNapalm ist offline
    Floats sind Fließkommazahlen
    Legal, illegal, scheißegal!!!!

  4. Beiträge anzeigen #4 Zitieren
    Ehrengarde Avatar von HolyWater
    Registriert seit
    Aug 2007
    Beiträge
    2.214
     
    HolyWater ist offline
    Zitat Zitat von BlackNapalm Beitrag anzeigen
    Floats sind Fließkommazahlen
    dann is z.b. eine ip ein float oder was?
    ♥ HolyWater ♥ YAY xD

  5. Homepage besuchen Beiträge anzeigen #5 Zitieren
    Exodus Avatar von Sektenspinner
    Registriert seit
    Jul 2004
    Ort
    Karlsruhe
    Beiträge
    7.827
     
    Sektenspinner ist offline
    Zitat Zitat von Marlus
    dann is z.b. eine ip ein float oder was?
    Nein, eine IP ist ein normales Wort aus 4 bytes. Für gewöhnlich werden die Werte der Bytes als Dezimalzahlen dargestellt und mit einem Punkt getrennt. mit floats hat das nichts zu tun.

    Kurz etwas zu Zahlen und Speicher:
    Ein Computer arbeiten mit Bitfolgen, meist Folgen von 8 bit, 16 bit oder 32 bit. Diese Bitfolgen werden Wörter genannt.

    Es gibt nur endlich viele Wörter einer bestimmten Länge, zum Beispiel nur 2^8 Wörter (das sind 256) der Länge 8. Nun geht man her und ordnet den Bitfolgen eine Interpretation, also eine Bedeutung zu, je nachdem was man gerade gespeichert und verarbeitet haben möchte. Zum Beispiel könnte man der Bitfolge 01000001 die Bedeutung "a" zuordnen, der Bitfolge 010111010 die Bedeutung Kugelschreiber usw. Die Bitfolgen bleiben dann zwar nach wie vor Bitfolgen, aber sie tragen eine Information, genau wie das Wort "Stuhl" der natürlichen Sprache eine Information trägt. Wir wissen sofort was gemeint ist, wenn wir Stuhl sagen und können mit anderen nun über Stühle reden, und das obwohl "Stuhl" nur eine Folge von Buchstaben (und nichts weiter) ist.

    Da man häufig mit Zahlen arbeitet, definiert man sich auch eine Repräsentation für Zahlen. Weil es aber nur endlich viele Wörter einer bestimmten Länge gibt und Rechner zwar immer mehr, aber doch nur endliche Längen von Wörtern erlauben (mittlerweile meist 32 oder 64 bit) muss man sich einige Zahlen aussuchen, die man darstellen können möchte.

    Welche Zahlen das sind, ist je nach Anwendungszweck verschieden. Oft nimmt man den Anfang der natürlichen Zahlen und 0, also die Zahlen 0,1,2,3... bis einem die Wörter ausgehen und man kein Wort mehr findet, was nicht schon für eine Zahl steht. Bei 32 bit Rechnern kann man so Zahlen von 0 bis 4294967295 darstellen, das sind viele, aber eben nur endlich viele. Die Schulden der Bundesrepublik Deutschland in Euro kann man so zum Beispiel nicht mehr darstellen. Da muss man tricksen oder andere Zahlen auswählen, sodass man die Schulden doch darstellen kann.

    Wegen solcher Probleme hat man sich eine Auswahl überlegt in der (auch nur 2^32 verschiedene Zahlen aber) sowohl ziemlich große als auch ziemlich kleine Zahlen enthalten sind. Es sind z.B. absurd große Zahlen wie 3,403 * 10^38 und absurd kleine Zahlen wie 1,401·10^ (-45) enthalten. Das kostet natürlich Genauigkeit, denn wie gesagt, die Anzahl der Zahlen ist immernoch gleich, das heißt man muss ziemliche viele Zahlen auslassen.

    Mit floats kann man daher nicht wirklich genau, aber dafür eben mit sehr großen, sehr kleinen und insbesondere mit Kommazahlen rechnen.

    Nun wäre diese Methode aber ziemlich mühsam, wenn man immer in einer großen Tabelle nachschlagen müsste welche Bitfolge für welche Zahl steht. In der Praxis funktioniert das so, dass bestimmten Bits bestimmte Bedeutungen zugeordnet werden.
    Es gibt ein Bit für das Vorzeichen, das für + oder für - steht. Dann gibt es 8 bit, die den Exponenten festlegen und 23 bit für die sogenannte Mantisse. Die Zahl, die mit einer Bitfolge gemeint ist, berechnet sich dann durch:

    (-/+) Mantisse * 2^Exponent

    Das heißt für
    Vorzeichen = +
    Exponent = 5
    Mantisse = 1,5

    ergibt sich:

    + 1,5 * 2^5 = 1,5 * 32 = 48

    (Das ^ Zeichen steht für die "hoch" Operation, beschreibt also eine Potenz)

    Vorteile die sich daraus ergeben sind:
    Jeder Zahl X kann man (ungefähr) ihr multiplikatives Inverses X^(-1) zuordnen, das heißt 1/X ausrechnen. Bei Ganzahlen geht das nicht, 3/5 ergibt 0. Bei floats dagegen würde eine Zahl herauskommen, die ungefähr (aber nicht genau) 0.6 ist. Auch sind wichtige Zahlen wie PI, e und eben Brüche nicht mit Ganzzahlen darstellbar, wohl aber mit float-Zahlen annäherbar.

    Um das noch genauer zu verstehen, kannst du ja nochmal eine Wissensquelle deiner Wahl konsultieren.

    Zitat Zitat von Watschnbaum
    Könntest du einem laien erklären was floats sind?
    Für Laien: Kommazahlen und sehr große Zahlen passen nicht in Integer, da braucht man float.
    Zitat Zitat von Watschnbaum
    Und was für Anwendungszwecke bringen die?
    Du kannst ausrechnen, wie schwer die Erde ist, du kannst die Wurzel einer Zahl (ungefähr) berechnen und damit zum Beispiel den Satz des Pythagoras anwenden. Du kannst ausrechnen, wie viele km/h eine Schnecke schafft oder ausrechnen, wie schwer eine Kugel Blei ist, die 1 Meter Radius hat.

    Für Gothic ist das ganze aber zugegebenermaßen wenig relevant.
    Für Spieler:
    Velaya # Velaya in English # Exodus Demo # Irrwichtel
    Tools für Modder:
    DiaDepp # DOPA-PARTER # zSlang
    Scripte für Modder:
    Ikarus Skriptpaket # Floats # Broadcasts

  6. Beiträge anzeigen #6 Zitieren
    Veteran Avatar von Machtl
    Registriert seit
    Mar 2008
    Ort
    Österreich
    Beiträge
    596
     
    Machtl ist offline
    Daedlus unterstützt Bitmanipulation? Das hätte ich nicht gedacht und hab eigentlich auch noch nie davon gehört bzw. ein Script gesehen wo davon Gebrauch gemacht wurde.

  7. Beiträge anzeigen #7 Zitieren
    Demigod Avatar von Sumpfkrautjunkie
    Registriert seit
    Nov 2004
    Ort
    München
    Beiträge
    9.091
     
    Sumpfkrautjunkie ist offline

    Du zeigst immer wieder, was man so alles aus Daedalus herausquetschen kann

  8. Beiträge anzeigen #8 Zitieren
    Ehrengarde Avatar von HolyWater
    Registriert seit
    Aug 2007
    Beiträge
    2.214
     
    HolyWater ist offline
    Zitat Zitat von Sumpfkrautjunkie Beitrag anzeigen

    Du zeigst immer wieder, was man so alles aus Daedalus herausquetschen kann
    sind doch auch in den pfxen????
    ♥ HolyWater ♥ YAY xD

  9. Beiträge anzeigen #9 Zitieren
    Demigod Avatar von Sumpfkrautjunkie
    Registriert seit
    Nov 2004
    Ort
    München
    Beiträge
    9.091
     
    Sumpfkrautjunkie ist offline
    Zitat Zitat von Marlus Beitrag anzeigen
    sind doch auch in den pfxen????
    Ja, aber nur als Konstanten.
    Bei Konstanten meckert Gothic ja nicht, aber sobald man mit floats irgendwas in Deadalus berechnen will klappts nicht.

  10. Homepage besuchen Beiträge anzeigen #10 Zitieren
    Exodus Avatar von Sektenspinner
    Registriert seit
    Jul 2004
    Ort
    Karlsruhe
    Beiträge
    7.827
     
    Sektenspinner ist offline
    Zitat Zitat von Machtl Beitrag anzeigen
    Daedlus unterstützt Bitmanipulation? Das hätte ich nicht gedacht und hab eigentlich auch noch nie davon gehört bzw. ein Script gesehen wo davon Gebrauch gemacht wurde.
    In den Constants Dateien sind an manchen stellen flags mit Hilfe von links shift deklariert. In den System Scripten (Menu zum Beispiel) werden auch gelegentlich Bitoperationen benutzt um einzelne flags aus einer Menge von flags rauszuschmeißen (flags & ~ flag).

    Ich habe mir aber auch schon einen anderen simplen Datentyp damit gebaut; einen Spell Datentyp, der Schaden, Manaverbrauch, Götterzugehörigkeit Kreis und Lernpunkteverbrauch speichert. War aber ein ziemliches gequetsche.
    Sowas kann sehr praktisch sein.

    Zitat Zitat von Marlus Beitrag anzeigen
    sind doch auch in den pfxen????
    Man darf trotzdem nicht damit rechnen. Das ist echt abgefahren, was sich PB da an Scriptsprache gebaut hat. Man darf floats initialisieren und übergeben, aber nicht damit rechnen. Ich wusste das bis vor kurzem auch nicht.
    Zitat Zitat von Sumpfkrautjunkie Beitrag anzeigen

    Du zeigst immer wieder, was man so alles aus Daedalus herausquetschen kann
    Thx.
    Für Spieler:
    Velaya # Velaya in English # Exodus Demo # Irrwichtel
    Tools für Modder:
    DiaDepp # DOPA-PARTER # zSlang
    Scripte für Modder:
    Ikarus Skriptpaket # Floats # Broadcasts

  11. Beiträge anzeigen #11 Zitieren
    research Avatar von NicoDE
    Registriert seit
    Dec 2004
    Beiträge
    7.410
     
    NicoDE ist offline
    Da ist man mal ein paar Monate mit anderen Dingen beschäftigt, und dann sowas

    Gute Arbeit.

    Wäre es bei den ganzen "Spracherweiterungen" nicht bald angebracht, einen eigenen Daedalus-Compiler zu bauen, der die fehlenden Operatoren und Syntaxelemente unterstützt? Gut, dann hat man halt das Problem, dass Gothic die Skripte selbst nicht mehr kompilieren kann - aber dafür würde sich sicherlich auch eine komfortable Lösung finden lassen.
    "Unter diesen schwierigen Umständen bin ich mir sicher, daß diese guten Menschen meinen augenblicklichen Bedarf an deren Gold verstehen werden." -- Connor

  12. Homepage besuchen Beiträge anzeigen #12 Zitieren
    Exodus Avatar von Sektenspinner
    Registriert seit
    Jul 2004
    Ort
    Karlsruhe
    Beiträge
    7.827
     
    Sektenspinner ist offline
    Vielleicht, aber damit kenne ich mich nicht aus und mir fehlt die Zeit mich da hereinzuarbeiten und was gutes zu bauen.
    Das hier war ein spontanes zwei Tage Projekt.

    Außerdem gibt es doch soetwas schon: Ich glaube der Gothic Sourcer unterstützt diverse Konstruktionen die Gothic nicht unterstützt.
    Für Spieler:
    Velaya # Velaya in English # Exodus Demo # Irrwichtel
    Tools für Modder:
    DiaDepp # DOPA-PARTER # zSlang
    Scripte für Modder:
    Ikarus Skriptpaket # Floats # Broadcasts

  13. Homepage besuchen Beiträge anzeigen #13 Zitieren
    Benutzer, die ihr Benutzerkonto per E-Mail bestätigen müssen Avatar von Player140
    Registriert seit
    Jul 2004
    Beiträge
    3.111
     
    Player140 ist offline
    Respekt, gute Arbeit! Sollte ich irgendwann anfangen für Gothic zu skripten, werde ich darauf zurückgreifen
    Als ich gelesen habe, dass Deadalus keine Fließkommazahlen unterstützt, hab ich schon insgeheim gehofft, dass sich jemand erbarmt das Ganze zu implementieren. Ist bestimmt hilfreich um z.B. genauer mit der Spielerpossition in der Welt zu arbeiten.

    Hast du das hier u. deine Array-Implementierung schon im Wiki eingetragen?
    Habs mal unter Diverses/Foren Threads hinzugefügt, hab allerdings dein Array-Skript nirgends gefunden. Kannst du den Link zum Thread bitte hier posten?
    Geändert von Player140 (29.11.2008 um 13:33 Uhr)

  14. Homepage besuchen Beiträge anzeigen #14 Zitieren
    Exodus Avatar von Sektenspinner
    Registriert seit
    Jul 2004
    Ort
    Karlsruhe
    Beiträge
    7.827
     
    Sektenspinner ist offline
    Zitat Zitat von Player140 Beitrag anzeigen
    Hast du das hier u. deine Array-Implementierung schon im Wiki eingetragen?
    Habs mal unter Diverses/Foren Threads hinzugefügt, hab allerdings dein Array-Skript nirgends gefunden. Kannst du den Link zum Thread bitte hier posten?
    Habe ich noch nirgendwo eingetragen. Ich kenne auch noch keinen dem das wirklich geholfen hat.
    Die Lösung hat auch ein erhebliches Problem: Die Arrays sind jeweils nur in der Welt verfügbar, in der sie ereugt wurden (weil die Werte in C_NPC Objekten gespeichert wird, die an eine Welt gebunden sind).

    Hier der Link: *klick*
    Für Spieler:
    Velaya # Velaya in English # Exodus Demo # Irrwichtel
    Tools für Modder:
    DiaDepp # DOPA-PARTER # zSlang
    Scripte für Modder:
    Ikarus Skriptpaket # Floats # Broadcasts

  15. Beiträge anzeigen #15 Zitieren
    Deus Avatar von Oparilames
    Registriert seit
    May 2004
    Ort
    ex contrariis
    Beiträge
    11.015
     
    Oparilames ist offline
    So dann schenke ich diesem Thread doch mal meine Aufmerksamkeit...

    Ich hätte ein paar Fragen zu dem Script.
    [Jetzt wo ich mal "Lust" und (eigentlich keine) Zeit habe, das Script zu betrachten [ich habe nähmlich endlich mal wieder zeit, überhaupt Scripts zu beschauen, die letzten Wochen waren dann doch sehr schulfixiert...] und habe einige Fragen zum Script...
    1. Was bedeutet x = x & (~(1 << exp)); genau?
    X ist so groß wie x und wird auf ungefähr 1( wenn es größer als der expotentialwert ist) Dezimalstelle gerundet???
    Tut mir leid, ich bin noch sehr unerfahren im Programmieren.
    Außerdem würde mich interessieren, wie das ganze in der Praxis aussieht.
    Mein erster Versuch (das ganze auch praktisch an zu wenden) ist nähmlich nicht ertragreich gewesen:
    Ich wollte mit einem float rechnen, aber zuvor eine Ausgabe bekommen.
    Nur kam keine Ausgabe, alsob alles übergangen wäre.
    Ich habe den Script übernommen wie er da steht und versucht eine kleine Funktion zu basteln.
    Hier ist sie.
    Code:
    //Folgende Funktion soll Einen Float erzeugen mitdem gerechnet werden kann. 
    //Dieser soll ein Bruchteil (RichtigerFloat) des Heldenlevels in Prozent angeben.
    
    func void Faktorberechner (mkf (RichtigerFaktor)) 
    {
    	var int Faktor;
    	Faktor = mulf (mkf (pc_hero.level), 100);				// Heldenlevel = 100 (Prozent)
    	Faktor = divf (Faktor, mkf (RichtigerFaktor));	// Auf RichtigerFaktor Prozent berechnen
    	//printf 	(divf (Faktor, mkf (150)));							//Faktor durch 
    	printf 	(Faktor);							//Faktor durch 
    	//(1337*PI)/100 ist verblüffend genau 42. ;-)
    };
    Benutzt wird sie so:
    Code:
    FUNC void B_AssessGuidePlayer ()
    {
    	Faktorberechner (1.5);
    //[...]
    };
    Oparilames nachdem er seinen Gesellenbrief erhalten hat:
    »Das war's mit dir, du Mistvieh!«

  16. Beiträge anzeigen #16 Zitieren
    research Avatar von NicoDE
    Registriert seit
    Dec 2004
    Beiträge
    7.410
     
    NicoDE ist offline
    Zitat Zitat von Oparilames Beitrag anzeigen
    Was bedeutet x = x & (~(1 << exp)); genau?
    Das sind alles Bitoperationen.

    Eine 1 wird um <exp> Bits nach links verschoben und negiert (aus allen 0-en werden 1-en und umgekehrt). Dabei erhält man einen Wert, bei dem alle Bits gesetzt sind, bis auf das <exp>-te. Nun wird x mit diesem Wert ver-UND-det (nur die 1-en bleiben übrig, die in beiden Operanden gesetzt sind).

    Kurz: Das <exp>-te Bit aus x wird entfernt (auf 0 gesetzt).
    "Unter diesen schwierigen Umständen bin ich mir sicher, daß diese guten Menschen meinen augenblicklichen Bedarf an deren Gold verstehen werden." -- Connor

  17. Homepage besuchen Beiträge anzeigen #17 Zitieren
    Exodus Avatar von Sektenspinner
    Registriert seit
    Jul 2004
    Ort
    Karlsruhe
    Beiträge
    7.827
     
    Sektenspinner ist offline
    func void Faktorberechner (mkf (RichtigerFaktor))
    Du kannst in der Parameterliste keine Funktion reinschreiben. Da muss schon etwas in Richtung: "var int richtigerFaktor" stehen.

    Faktorberechner (1.5);
    Unschön und auf 64 bit Systemen vielleicht sogar falsch. Selbst wenn Gothics interne Darstellung mit meiner Darstellung übereinstimmt, solltest du nicht Gothic floats mit meinen floats mischen. Außerdem sollte Gothic eine Umwandlung von einem syntaktischen float (var float) in einen "Fakefloat" von mir, der syntaktisch gesehen integer ist, gar nicht zulassen.

    Faktor = mulf (mkf (pc_hero.level), 100);
    100 ist kein vernünftiger Wert in diesem Kontext. mulf möchte zwar syntaktisch gesehen integer, aber semantisch ist 100 hier Blödsinn, denn als float interpretiert ist das irgendeine verdammt kleine Zahl, die überhaupt nichts mit 100 zutun hat. Du müsstest mkf(100) übergeben. Aber Achtung! Hinweis beachten:
    Code:
    *********** Gothic Fehler ************
    Gothic hat eine eigenwillige (fehlerhafte) Art verschachtelte Ausdrücke auszuwerten. Wenn hierbei eine Funktion mehrfach angewendet wird, überschreibt der zwei Aufruf das Ergebnis des ersten. Beispiel:
    
    Der Ausdruck
    divf (mkf (42), mkf (6))
    liefert das Ergebnis 1 obwohl 42/6 = 7 ist. Das liegt daran, dass Gothic zwar mkf für 42 und für 6 aufruft, aber beim zweiten mal das Ergebnis des ersten Males vergisst. Das heißt schlussendlich wird 6 durch 6 geteilt, wobei 1 herauskommt. Wer also Funktionen gerne schachtelt sollte sich in acht nehmen! Wer sich unsicher ist, wann Gothic ein solches Verhalten zeigt, sollte solche Berechnungen schrittweise und mit Zwischenvariablen ausführen.
    Für Spieler:
    Velaya # Velaya in English # Exodus Demo # Irrwichtel
    Tools für Modder:
    DiaDepp # DOPA-PARTER # zSlang
    Scripte für Modder:
    Ikarus Skriptpaket # Floats # Broadcasts

  18. Beiträge anzeigen #18 Zitieren
    research Avatar von NicoDE
    Registriert seit
    Dec 2004
    Beiträge
    7.410
     
    NicoDE ist offline

    Post code spam

    Ich habe mir zum Testen der Fließkommazahlen eine Float32ToString mit 8 Ziffern Genauigkeit, inklusive wissenschaftlicher Darstellung und Unterstützung von denormalisierten Zahlen geschrieben.
    Die Berechnung basiert auf vorberechneten BCD-Werten für alle möglichen Bits des Signifikanten (Mantisse).

    Siehe Anhang. Fehler inklusive.
    Miniaturansichten angehängter Grafiken Miniaturansichten angehängter Grafiken Float32ToString.png  
    Angehängte Dateien
    "Unter diesen schwierigen Umständen bin ich mir sicher, daß diese guten Menschen meinen augenblicklichen Bedarf an deren Gold verstehen werden." -- Connor

  19. Homepage besuchen Beiträge anzeigen #19 Zitieren
    Exodus Avatar von Sektenspinner
    Registriert seit
    Jul 2004
    Ort
    Karlsruhe
    Beiträge
    7.827
     
    Sektenspinner ist offline
    Groben Fehler in der Floatimplementierung behoben:
    Bei der Konvertierung von Ganzzahlen in Gleitkommazahlen ging ich von einer falschen Norm aus. Der Exponent lag um 1 daneben.

    Das fällt nur auf, wenn "externe" floats ins Spiel kommen, das heißt floats, die einer anderen Norm folgen. Das ist natürlich bei Engine floats der Fall.

    Da man erst seit neustem Zugriff auf Engine-Floats hat, ist das erst jetzt aufgefallen.
    Für Spieler:
    Velaya # Velaya in English # Exodus Demo # Irrwichtel
    Tools für Modder:
    DiaDepp # DOPA-PARTER # zSlang
    Scripte für Modder:
    Ikarus Skriptpaket # Floats # Broadcasts

  20. Homepage besuchen Beiträge anzeigen #20 Zitieren
    Adventurer Avatar von orcwarriorPL
    Registriert seit
    Jan 2006
    Ort
    themodders.org
    Beiträge
    79
     
    orcwarriorPL ist offline
    Hi, first sorry but I can write in english only. I'm here to report small bug in your floats functions. It looks like the function of multiplication don't work properly, it always returns positive value, even if the result should be negative. Here is screen that shows multiplication bug:
    [Bild: 25ev2jb.jpg]
    If there is much to work, don't bother, I can use invf and divf instead of mulf, because divf works alright ;P

    Note: I'm working on Gothic 1 but I don't think that could be a problem.

    EDIT:
    Huh, I've done it by my self There was only a small mistake in isNegRes. I'm posting corrected code:
    Code:
    func int mulf (var int x, var int y) {
    	var int expX; expX = extractExp (x);
    	var int expY; expY = extractExp (y);
    	var int mtX; mtX = extractMt (x);
    	var int mtY; mtY = extractMt (y);
    	var int isnegX; isnegX = x & MINUS;
    	var int isnegY; isnegY = y & MINUS;
    	
    	//Sonderbehandlung für das Symbol NULL
    	if (x == FLOATNULL)
    	|| (y == FLOATNULL) {
    		return FLOATNULL;
    	};
    	
    	//Die Exponenten werden addiert
    	var int expRes;
    	expRes = expX + expY;
    	
    	//Die Mantissen multipliziert (wobei auf die 32 bit Grenze geachtet werden muss)
    	var int mtRes;
    	mtRes = (mtX >> (BIT_MT - 14)) * (mtY >> (BIT_MT - 14));
    	mtRes = mtRes >> (28 - BIT_MT);
    	
    	if (mtRes >= (1 << (BIT_MT + 1)))
    	{
    		mtRes = mtRes >> 1;
    		expRes += 1;
    	};
    	
    	//Noch die erste Zahl abschneiden (also die Mantisse zuschneiden):
    	mtRes = mtRes & ((1 << BIT_MT) - 1);
    	
    	var int isNegRes;
    	if (isnegX == isnegY) {
    		isNegRes = FALSE;
    	}
    	else {
    		isNegRes = MINUS;
    	};
    	
    	//noch Erkenntnisse zusammenfügen
    	return isnegRes | packExp(expRes) | mtRes;
    };
    Geändert von orcwarriorPL (01.07.2010 um 14:10 Uhr)

Seite 1 von 3 123 Letzte »

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
Impressum | Link Us | intern
World of Gothic © by World of Gothic Team
Gothic, Gothic 2 & Gothic 3 are © by Piranha Bytes & Egmont Interactive & JoWooD Productions AG, all rights reserved worldwide