User talk:Strife Onizuka/Float Functions

From Second Life Wiki
Jump to navigation Jump to search

What's the purpose of llFloatCompare?

Hi, I'm a bit confused by llFloatCompare, why include fui, iuf and FloatCompare in a script when you can just do it this way:

<lsl>

       float f_1 = 0.00000003;
       float f_2 = 0.00000002;
       if(llFabs(f_1) - llFabs(f_2) > 0 ) {
           llOwnerSay("f_1 > f_2");
           return;
       }
       if(llFabs(f_1 - f_2) == 0.0) {
           llOwnerSay("f_1 = f_2");
           return;
       }
       llOwnerSay("f_1 < f_2");

</lsl>

I have run a test in Second Life, using your FloatCompare function (because none of required functions even compile on OpenSim) and compared it to my method and the results are the same, even my simple method succeeds where your method fails. I used the following script:

<lsl> // [ bla bla bla ] // I've spared you the 40 lines of code and functions that your FloatCompare method requires.

default {

   state_entry() {
       float f_1 = 0.999993;
       float f_2 = 0.999992;
       if(llFabs(f_1) - llFabs(f_2) > 0 ) {
           llOwnerSay("Kira: f_1 > f_2");
           jump strife;
       }
       if(llFabs(f_1 - f_2) == 0.0) {
           llOwnerSay("Kira: f_1 = f_2");
           jump strife;
       }
       llOwnerSay("Kira: f_1 < f_2");

@strife;

       llOwnerSay("Strife: " + (string)FloatCompare(f_1, f_2, 1));
   }

} </lsl>


Test 1, Your method fails.

For <lsl> float f_1 = 0.9999993; float f_2 = 0.9999992; </lsl>

Output

Object: Kira: f_1 > f_2
Object: Strife: 0

They are not equal... What is this?


Test 2, Your method fails.

For: <lsl> float f_1 = 0.9999003; float f_2 = 0.9999002; </lsl>

Output

Object: Kira: f_1 > f_2
Object: Strife: 0

Still equal? WTH?


Test 3, We both succeed.

For: <lsl> float f_1 = 0.999993; float f_2 = 0.999992; </lsl>

Output

Object: Kira: f_1 > f_2
Object: Strife: 1

Test 4, We both fail.

<lsl> float f_1 = 0.000000000000000000000000000000000000000000002; float f_2 = 0.000000000000000000000000000000000000000000001; </lsl>

Output

Object: Kira: f_1 = f_2
Object: Strife: 0

Here are a few funny ones:

Test 5, My method works, your method just crashes with Math Error

<lsl> float f_1 = 3.402E+38; float f_2 = 3.403E+38; </lsl>

Output

Object: Kira: f_1 < f_2
Object: Object [script:New Script] Script run-time error
Object: Math Error

This one too:

Test 6, My method works, your method just crashes with Math Error

<lsl> float f_1 = 3.403E+38; float f_2 = 3.402E+38; </lsl>

Output

Object: Kira: f_1 > f_2
Object: Object [script:New Script] Script run-time error
Object: Math Error

Don't get me wrong, you provide no documentation on what those functions are doing (what they mean) so I don't know if I used them correctly...

  • Could you please clarify what they are supposed to do?
  • Why include this chunk of obfuscated garbage with magic numbers:

<lsl> integer fui(float a)//Mono Safe, LSO Safe, Doubles Unsupported, LSLEditor Unsafe {//union float to integer

   if((a)){//is it non zero?
       integer b = (a < 0) << 31;//the sign, but later this variable is reused to store the shift
       if((a = llFabs(a)) < 2.3509887016445750159374730744445e-38)//Denormalized range check & last stirde of normalized range
           return b | (integer)(a / 1.4012984643248170709237295832899e-45);//the math overlaps; saves cpu time.
       integer c = llFloor((llLog(a) / 0.69314718055994530941723212145818));//extremes will error towards extremes. following yuch corrects it.
       return (0x7FFFFF & (integer)(a * (0x1000000 >> b))) | (((c + 126 + (b = ((integer)a - (3 <= (a /= (float)("0x1p"+(string)(c -= ((c >> 31) | 1)))))))) << 23 ) | b);
   }//for grins, detect the sign on zero. it's not pretty but it works. the previous requires alot of unwinding to understand it.
   return ((string)a == (string)(-0.0)) << 31;

}

float iuf(integer a) {//union integer to float

   return ((float)("0x1p"+(string)((a | !a) - 150))) * ((!!(a = (0xff & (a >> 23))) << 23) | ((a & 0x7fffff))) * (1 | (a >> 31));

}//will crash if the raw exponent == 0xff; reason for crash deviates from float standard; though a crash is warented.

integer FloatCompare(float a, float b, integer c) {//compare floats and allow for a margin of error, requires fui().

   if(a - b)//(c) Strife Onizuka 2006 
   {//they are not equal
       //First we convert the floats to integer form, as they would be in memory;
       integer a_i = fui(a);
       integer b_i = fui(b);
       integer a_e = (a_i >> 23) & 0xff;
       integer b_e = (b_i >> 23) & 0xff;
       if(!(a_e || b_e) || //to disable the +/- roll under support put a // just before the !
           ((a_i & 0x80000000) == (b_i & 0x80000000)))//sign match check
       {//start by getting and testing the difference, this is what limits c
           integer diff = a_e - b_e;//ugly is fast, basicly, it gets the mantissa, sets the sign on the mantisa,
           if(diff >= -1 || diff <= 1)//shifts it depending on exponent, finaly executes the test.
               if(llAbs(((((a_i & 0x7FFFFF) | (!!a_e << 23)) * ((a_i >> 31) | 1)) >> !~-diff) - 
                        ((((b_i & 0x7FFFFF) | (!!b_e << 23)) * ((b_i >> 31) | 1)) >> !~diff)) <= c)
                   jump out;
       }
       return (a > b) - (a < b);
   }
   @out;
   return 0;

} </lsl>

in every script when you can use the method above?

Your scripts seem to either give wrong answers, match mine or, in your case, they just crash...

Kira Komarov 06:12, 23 May 2012 (PDT)