• Bitte schaltet eure Ad Blocker aus. SLinfo kann nur betrieben werden, wenn es durch Werbung Einnahmen erzielt. Vielen Dank!!
  • Wir freuen uns, wenn du dich in unserem Forum anmeldest. Bitte beachte, dass die Freigabe per Hand durchgeführt wird (Schutz vor Spammer). Damit kann die Freigabe bis zu 24 Stunden dauern.
  • Wir verwenden Cookies, um Inhalte und Anzeigen zu personalisieren, Funktionen für soziale Medien anbieten zu können und die Zugriffe auf unsere Website zu analysieren. Sie geben Einwilligung zu unseren Cookies, wenn Sie unsere Webseite weiterhin nutzen.

Klitzekleines mathematisches Problem

Bittersweet Frostbite

Moderatorin in Urlaub
Weiss jemand wie ich LSL dazu bringe korrekt zu rechnen:

integer a=2458985;
float b=a-122.1;
llOwnerSay((string)b);

Da kommt 2458863.000000 raus, richtig wäre natürlich 2458862.900000...
 
Selbst das hier liefert das falsche Ergebnis:

Code:
default
{
    state_entry()
    {

    }

    touch_start(integer nr)
    {

        float a;
        
        float b;
        
        
        a=2458985.0;
        
        b=a-122.1;
        
        llOwnerSay((string)b);


    }
}



das sieht nach einem Bug aus.
 
Ich habe es nicht ausprobiert. Aber du könntest testweise in string umwandeln. Dann auf gewünschte Länge kürzen und die Berechnung ausführen.
 
lol, da war ich nicht ganz bei der Sache. Obwohl das prinzip einen test wert ist:

Code:
default
{
    state_entry()
    {

    }

    touch_start(integer nr)
    {

        float a;
        
        float b;
                
        a=2458985.0;
        
        a = a - 2450000.0;
                                
        b=a-122.1;
        
        llOwnerSay((string)b);
        
        b += 2450000.0;
        
        llOwnerSay((string)b);


    }
}



Das ist ein Bug.
 

Das ist nicht wirklich ein Bug.
Die Floats in LSL sind normale 32-bit Gleitkommazahlen nach IEE 754, mit denen sich sowohl sehr große als auch sehr kleine reelle Zahlen darstellen lassen.

Dabei ist die Zahl im Prinzip nach folgendem Muster aufgebaut:
Zahl = Vorzeichen* 2 ^(Exponent) * Mantisse
Zahl = [V][EEEEEEEE][MMMMMMMMMMMMMMMMMMMMMMMM] (binär), d.h. dabei hat das Vorzeichen 1 bit, der Exponent 8 bit und die Mantisse 23 bit.

Dabei legt das Vorzeichenbit fest, ob es sich um eine negative oder Positive Zahl handelt, der Exponent gibt den Wertebereich an und die Mantisse gibt die relevanten Ziffern an. Mit dieser Art und Weise die Zahlen mit einer 23-bit Mantisse aufzubauen kann man aber Prinzipiell nur auf log(2^23) = 7 Stellen genau berechnen. Weiter hinten liegende Stellen werden einfach abgeschnitten und gehen verloren.
D.h. je kleiner oder größer ein Float wird, desto ungenauer wird er.

Ein Float kann daher z.B. a = 123567.0 * 10^5 oder b= 0.1234567 * 10^0, also a= 123456700000 oder 0,1234567 sein.
Aber eben nicht 1234567.890123 * 10^5 = 123456789012,3 - für diese Genauigkeit ist die 23-bit Mantisse mit 7 Ziffern nicht ausreichend.

Wenn man genauer rechnen möchte mit Floats, dann gibt es eigentlich nicht viele Möglichkeiten:

a) Man benutzt dafür intern Floats mit 64 oder mehr bits, wobei man dann vermutlich diverse Bibliotheken für sein script selbst schreiben müsste um mit seinen Zahlen z.B. Addieren, Subtrahieren usw. zu können.
Und um aus dem eigenen 64-bit Float dann z.B. einen passenden String zu machen.

b) Man sorgt dafür, dass man nur mit kleinen Exponenten, d.h. mit nicht zu großen und nicht zu kleinen Floats rechnet. Wenn man z.B. mit sehr großen Zahlen rechnen muss, dann muss man eben den Wert einer Zahle "aufteilen" in Summen aus zwei oder mehr Zahlen. Und dann auch mit den kleinen Teilen exakt rechnen.

Z = 12345678901234567890,1234567 = (1234567 * 10^13) + (8901234 * 10^6) + (567890 * 10^0) + (1234567 * 10^-1)

D.h. man kann je nach Anwendung oft mit einem "Bias" bzw "Offset" arbeiten, den man natürlich am Ende einer Operation immer berücksichtigen muss.
Und wenn man diese Zahlen dann zu einem String umwandeln will muss man sich wohl auch eine eigene Funktion basteln, eben mal alles in einen LSL-Float zu konvertieren wegen des Typecastings sorgt ja dafür, dass die Genauigkeit wieder futsch ist.
 
Das ist kein Bug, wie Bittersweet schon sagte, 'floats' in LSL sind 32-Bit Zahlen.
Die können genau 7 Stellen genau darstellen. Der Rest wird - einfach ausgedrückt - gerundet (die 7 Stellen ganz links werden beibehalten, rechts davon wird gerundet).
Das kannst du ganz leicht mit diesem Skript testen:

Code:
default
{
    state_entry()
    {
        if (2458863 == 2458862.9)
        {
            llOwnerSay("Bazinga!");
        }
    }
}

Workaround ist, den Ganzzahl-Teil gesondert zu berechnen.
 
Ich habe es nicht ausprobiert. Aber du könntest testweise in string umwandeln. Dann auf gewünschte Länge kürzen und die Berechnung ausführen.

Float --> String --> Float kann leider per Typecasting nicht exakt umgewandelt werden, da man für Strings ein Dezimalsystem verwendet, Floats intern aber Binär sind. D.h. da treten wohl Rundungsfehler auf.
 
Wie gesagt, da war ich unkonzentriert und nicht ganz bei der Sache. Meine Idee war hier ohnehin untauglich. Anstatt durch Rechnerei wollte ich mit der Stringmethode einfach ein paar Nachkommastellen entfernen.

Ansonsten Danke für die Erläuterungen hier. Wieder etwas dazugelernt :thumbup
 
Danke für eure Antworten. Ich hab's jetzt mein Problem auch gelöst, stolzguckt. Eigentlich wollte ich endlich mal vernünftige Datumsfunktionen in LSL haben, sprich ich wollte Datumsangaben in einen Julian Day umrechnen und wieder zurück. Leider ist der JD etwas zu gross, da kommt LSL nicht mehr mit, wie wir oben gesehen haben. Gelöst hab ich das jetzt in dem ich meine eigene Tageszählung gescriptet hab. Die beginnt halt erst am 1.1.2011 und hat dadurch Zahlen, die klein genug sind ;-)
 
Rechne das Datum doch im US Format, so hast dann immer eine Fortlaufende Nummer die sich sehr leicht berechnen laesst.
Auf diesem weg kannst du sogar feststellen ob ein entsprechendes Datum in der Vergangenheit oder in der Zukunft ist.

Anfang diesen Monats: 20131101
Heutiges Datum: 20131127
Ende diesen Monats: 20131130

Fuer eine eventuelle ausgabe (chat oder xyz-Text) kannst du das Datum dann wieder rueckwaerts zerlegen und gegebenenfalls in ein deutsches Format umwandeln.

LG
Dae
 
Und wie berechnest du damit die Differenz zwischen 2 Daten oder wie addierst du ein paar Tage zu einem Datum oder wie bekommst du den Wochentag oder die Kalenderwoche? Ich sprach von vernünftigen Datumsfunktionen ;-)
 
WAnstatt durch Rechnerei wollte ich mit der Stringmethode einfach ein paar Nachkommastellen entfernen.

mach es so (tu ich ebenfalls)

PHP:
string Float2String(float f)
{
    return llGetSubString((string)f,0,-6); // -1: letzte Stelle entfernen, -2: die letzten Zwei ... usw
}

string Vector2String(vector v)
{
    return "<"+Float2String(v.x)+","+Float2String(v.y)+","+Float2String(v.z)+">";
}
 
Und wie berechnest du damit die Differenz zwischen 2 Daten oder wie addierst du ein paar Tage zu einem Datum oder wie bekommst du den Wochentag oder die Kalenderwoche? Ich sprach von vernünftigen Datumsfunktionen ;-)

Benutze llGetUnixTime - eine fortlaufende Integerzahl seit dem 1.1.1970

wenn du viel mit externen SQL Datenbanken und PHP arbeitest die beste Wahl, das Format ist identisch
 
Zuletzt bearbeitet:

Users who are viewing this thread

Zurück
Oben Unten