Deine Beobachtung war dagegen, dass mkf(100/60) etwas ganz großes sei, was aber nicht so sein sollte (und wohl auch nicht so ist, oder?).
Ich habe es jetzt nochmal mit der damaligen Anwendung ausprobiert und die Zeit verging mit der richtigen Geschwindigkeit (soweit ich das abschätzen kann); damals raste die Zeit nur so, weshalb es "etwas ganz großes" gewesen sein müsste. Wie damals von dir vermutet vermutlich irgendein Fehler, den ich gemacht hatte, da ich den Code anschließend geändert habe, lässt es sich jetzt weder rekonstruieren, noch reproduzieren.
Zitat von Sektenspinner
Dein Ergebnis von TestFloats ist ebenfalls absolut nachvollziehbar und dokumentationsgetreu. mkf(1/2) soll zum Null-Float auswerten, divf(mkf(1),mkf(2)) zum 0.5-Float.
Das liegt einfach daran, dass der Term 1/2 zu Null ausgewertet wird und erst dann in mkf eingesetzt wird.
Alles funktioniert wie es sein soll.
Ja, so hatte ich es mir auch gedacht. Bis zu meinem PS hatte ich nur deine damalige Aussage falsch verstanden.
Hi, I maded some simple function based on this package, maybe someone else find them useful.
Fraction: Nothing special, but you don't have to always do divf(mkf(1),mkf(2)) to have 0.5 etc. :P
Code:
// Example: fractionF(9,10) = 0.9 (float)
func int fractionF(var int d,var int c)
{
d = mkf(d);
c = mkf(c);
return divf(d,c);
};
Random Float: This one is rather experimental, I tested it couple of times and it looks to be working, but I guess it could be done in some nicer way, but anyway, here's the code: It needs fractionf to work properly, but it could be simply changed by editing this line:
f = fractionf(Hlp_Random(possibilities),possibilities);
f = divf(mkf(Hlp_Random(possibilities)),mkf(possibilities));
Code:
// **************************************************
// RandF: Function returns random value from
// [range_start,range)
// * range should be greater than range_start
// but even if not, func should still work properly.
// * range_start and range have to be a zfloat
// **************************************************
func int RandF(var int range_start,var int range)
{
// -I made only small research, but it looks like bigger numbers generate
// errors when dividing (floats don't have endless accuracy :-P)
// When I tried possibilities = 65536, it don't looked like returns
// were proper, numbers bigger than half of range was never returned...
// Unfortunaly this is an random function so I don't have idea
// how to check it, it only possibly to check it theoretically ;-(.
// But as you can see on instance it looks to be working OK.
// Unfortunaly low possibilities value, means returned floats
// could have big step/"jumps", if rDiff>posibilities it means
// step will be more than 1.0.
const int possibilities = 10000;
var int f; // fe[0,1)
var int rDiff; //range difference
rDiff = subf(range,range_start);
f = fractionf(Hlp_Random(possibilities),possibilities);//0.0-0.999..
f = mulf(f,rDiff);
return addf(range_start,f);
};
The fraction function is useful. I included it into my current version and it will be included in future releases as fracf. Thanks for the suggestion.
Your observations on the maximum return value of Hlp_Random may be related to this c++ constant: RAND_MAX
It seems like it has been 32767 in the Gothic building enviroment.
Zitat von orcwarriorPL
EDIT: One mistake(?) I find out in negf function, if you float is zero shouldn't it return 0? I made simple code to check it out:
-0.0 is a perfectly valid IEEE 754 float and is supposed to behave differently from +0.0 in several conditions. For example, let eps be a (very) small number and N be a (very) big number, then eps/N will evaluate to -0.0 or +0.0 depending on the sign of eps and N. Simularly 1/-0.0 evaluates to negative infinity instead of positive infinity.
My script does not implement certain features of IEEE 754, though. The behaviour in overflow and underflow situations (as in the examples above) is currently undefined. Consequently the distinction between -0.0 and +0.0 is useless in my script. I will stick to it anyway.
I could not reproduce the bug you found. The following code worked fine with the release of september:
Yeah, all looks to be ok, the reason was my method of printing: I'm using NicoDE Float32ToString for converting into string first.
Nicos function is not the problem.
addf(mkf(10),negf(0)) evaluated to the word 1090519040 in your test which represents 8.0.
The same term evaluted to 1092616192 on my setup which represents 10.0.
But somehow the problem seem to have magically solved itself, since you now get the same results as I do...
Ich habe gemäß diesem Wikipedia-Artikel noch eine performantere Methode der Quadratwurzelberechnung gebastelt, die Ungenauigkeit liegt bei ca. 0.175%...
Wer also öfter Wurzeln berechnen muss, sollte diese Funktion nehmen. Wurde z.B. auch in Quake III verwendet
Code:
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)))));
};
/*
float Q_rsqrt( float number )
{
long i;
float x2, y;
const float threehalfs = 1.5F;
x2 = number * 0.5F;
y = number;
i = * ( long * ) &y; // evil floating point bit level hacking [sic]
i = 0x5f3759df - ( i >> 1 ); // what the fuck? [sic]
y = * ( float * ) &i;
y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration
// y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration, this can be removed
return y;
}
*/
Der C-Code im Kommentar kommt aus Wikipedia und entstammt Quake III
Ich muss zugeben dass ich nicht genau weiß, ob diese Art der Wurzelziehung in Daedalus immer noch performanter ist, aber davon ist auszugehen
Ich habe die Funktion aufgenommen und den Einleitungspost aktualisiert (nun ist auch orcwarriorPLs Vorschlag für eine fracf Funktion enthalten).
Zitat von Lehona
Ich muss zugeben dass ich nicht genau weiß, ob diese Art der Wurzelziehung in Daedalus immer noch performanter ist, aber davon ist auszugehen
Ohne es getestet zu haben, tippe ich auf einen Faktor von etwa 10.
Meine Wurzelfunktion braucht 75 Floatingpoint Operationen, deine kommt mit 6 aus.
Wenn ich wüsste welche Genauigkeitsgarantien meine Variante hat, hätte ich evtl. auch meine Variante einfach durch deine ersetzen können. Aber ohne das genauer untersucht zu haben, wollte ich an der alten lieber nichts ändern (vielleicht ist sie ja die alte deutlich besser und jemand verlässt sich auf genaue Wurzeln).
Habe nur mal kurz Google bemüht, aber prinzipiell solltest du einen besseren Startwert als x nehmen... Einfach wäre z.B. den Exponenten zu halbieren (also z.B. exp = ((exp-bias)/2)+bias). Dann kannst du auch die Anzahl der Iterationen verringern und wirst vermutlich sogar noch an Genauigkeit gewinnen. Ansonsten kann ich gleich mal ein bisschen schauen, wie die Genauigkeit so ist.
Ich habe das alles mal durchgetestet:
(Wurzel aus | WolframAlpha | Heron-Verfahren (25) | Approx-Verfahren)
Ich habe es also mit kleinen und großen Werten getestet, ob euch das zu stark abweicht müsst ihr selbst entscheiden. Wenn du übrigens einen besseren Annäherungswert nimmst (Funktion s. unten), komme ich auf die Ergebnisse schon nach 3 Iterationen.
Code:
func int sqrtf (var int x){
if (x < FLOATNULL){Print("ERROR: sqrtf: x must be nonnegative.");
return FLOATNULL;
};
//25 Schritte müssten reichen, wenn nicht bitte erhöhen!
//Ich habe mir nicht hergeleitet wie schnell die Reihe für verschiedene x konvergiert.
//für MANCHE x war aber auch schon 15 sehr genau.
var int y; var int target; target = x;
y = ExtractExp(x);
y = y/2;
y = packExp(y);
x = x&~EXP_PATTERN;
x = x | y;
return sqrtf_hlp (target, x, 3) + 0;
};
Ich werde das wohl genauso übernehmen, wie du vorschlägst. Mein Grafikram hat sich aber gerade wieder verabschiedet weshalb ich Gothic nicht starten kann. Ich schau mir das am Wochenende am andern Rechner nochmal an und mache dann nochmal ne neue Version.
Hi, sry ,aber ich seh irgendwie nicht durch
Muss ich jetzt eine neue Floats.d anlegen und den Code von oben reinkopieren oder wie importiere ich es jetzt ?
Du musst den Code aus dem ersten Beitrag des Threads kopieren, in einer (z.B. neuen) .d Datei speichern und die Datei in der Gothic.src eintragen. Sie sollte dort oberhalb der LeGo Dateien stehen.