Difference between revisions of "User:Strife Onizuka/Float Functions"

From Second Life Wiki
Jump to navigation Jump to search
m (→‎Float {{LSL_VR|-Union-}} Integer: NaN and Infinity support added.)
m (→‎Float {{LSL_VR|-Union-}} Integer: carry over from LSLEditor sorry.)
Line 14: Line 14:
     }//the previous requires a lot of unwinding to understand it.
     }//the previous requires a lot of unwinding to understand it.
     if(a == 0)//Just because it's not greater than or less than zero doesn't mean it's non-zero.
     if(a == 0)//Just because it's not greater than or less than zero doesn't mean it's non-zero.
         return (integer)((string)a == (string)(-0.0)) << 31;//for grins, detect the sign on zero. it's not pretty but it works.
         return ((string)a == (string)(-0.0)) << 31;//for grins, detect the sign on zero. it's not pretty but it works.
     //Mono does not support indeterminates so I'm not going to worry about it.
     //Mono does not support indeterminates so I'm not going to worry about it.
     return 0x7FFFFFFF;//NaN time! We have no way to tell NaN's apart so lets just choose one.
     return 0x7FFFFFFF;//NaN time! We have no way to tell NaN's apart so lets just choose one.
Line 75: Line 75:
     }//the previous requires a lot of unwinding to understand it.
     }//the previous requires a lot of unwinding to understand it.
     if(a == 0)//Just because it's not greater than or less than zero doesn't mean it's non-zero.
     if(a == 0)//Just because it's not greater than or less than zero doesn't mean it's non-zero.
         return (integer)((string)a == (string)(-0.0)) << 15;//for grins, detect the sign on zero. it's not pretty but it works.
         return ((string)a == (string)(-0.0)) << 15;//for grins, detect the sign on zero. it's not pretty but it works.
     //Mono does not support indeterminates so I'm not going to worry about it.
     //Mono does not support indeterminates so I'm not going to worry about it.
     return 0x7FFF;//NaN time! We have no way to tell NaN's apart so lets just choose one.
     return 0x7FFF;//NaN time! We have no way to tell NaN's apart so lets just choose one.

Revision as of 23:36, 27 December 2012

Float <-Union-> Integer

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

   if((a)){//is it greater than or less than 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 stride of normalized range
           return b | (integer)(a / 1.4012984643248170709237295832899e-45);//the math overlaps; saves cpu time.
       if(a > 3.4028234663852885981170418348452e+38)//Round up to infinity
           return b | 0x7F800000;//Positive or negative infinity
       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);
   }//the previous requires a lot of unwinding to understand it.
   if(a == 0)//Just because it's not greater than or less than zero doesn't mean it's non-zero.
       return ((string)a == (string)(-0.0)) << 31;//for grins, detect the sign on zero. it's not pretty but it works.
   //Mono does not support indeterminates so I'm not going to worry about it.
   return 0x7FFFFFFF;//NaN time! We have no way to tell NaN's apart so lets just choose one.

}

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

   if((a & 0x7F800000) == 0x7F800000)
       return (1 | (a >> 31)) * (float)llList2String(["NaN","Infinity"], !(a & 0x7FFFFF));
   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 warranted. </lsl>

Base64-Float

As a specialized mode of transport, this is faster then Float2Hex and just as lossless. <lsl> string fuis(float a){//float union to base64ed integer

   if((a)){//is it greater than or less than 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 stride of normalized range
           b = b | (integer)(a / 1.4012984643248170709237295832899e-45);//the math overlaps; saves cpu time.
       else if(a > 3.4028234663852885981170418348452e+38)//Round up to infinity
           b = b | 0x7F800000;//Positive or negative infinity
       else
       {
           integer c = llFloor(llLog(a) / 0.69314718055994530941723212145818);//extremes will error towards extremes. following yuch corrects it.
           b = (0x7FFFFF & (integer)(a * (0x1000000 >> b))) | (((c + 126 + (b = ((integer)a - (3 <= (a /= (float)("0x1p"+(string)(c -= ((c >> 31) | 1)))))))) << 23 ) | b);
       }
       return llGetSubString(llIntegerToBase64(b),0,5);
   }//for grins, detect the sign on zero. it's not pretty but it works. the previous requires a lot of unwinding to understand it.
   if(a != 0)
       return "f////w";
   if((string)a == (string)(0.0))
       return "AAAAAA";
   return "gAAAAA";

}

float siuf(string b) {//base64ed integer union to float

   integer a = llBase64ToInteger(b);
   if((a & 0x7F800000) == 0x7F800000)
       return (1 | (a >> 31)) * (float)llList2String(["NaN","Infinity"], !(a & 0x7FFFFF));
   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 warranted. </lsl>

Half-Precision

<lsl> integer fui16(float a)//Mono Safe, LSO Safe, Doubles Unsupported, LSLEditor Unsafe {//union half-precision float to short integer

   if((a)){//is it greater than or less than zero?
       integer b = (integer)(a < 0) << 15;//the sign, but later this variable is reused to store the shift
       if((a = llFabs(a)) < 0.0001220703125)//Denormalized range check & last stride of normalized range
           return b | (integer)(a * 16777216.0);//the math overlaps; saves cpu time.
       if(a > 65504.0)//Round up to infinity
           return b | 0x7C00;//Positive or negative infinity
       integer c = llFloor((llLog(a) / 0.69314718055994530941723212145818)) + 14;//extremes will error towards extremes. following yuch corrects it.
       return (0x3FF & (integer)(a * (0x800 >> b))) | (((c + (b = ((integer)a - (3 <= (a *= (0.0000152587890625 * (0x40000000 >> c)))))) << 10 ) | b);
   }//the previous requires a lot of unwinding to understand it.
   if(a == 0)//Just because it's not greater than or less than zero doesn't mean it's non-zero.
       return ((string)a == (string)(-0.0)) << 15;//for grins, detect the sign on zero. it's not pretty but it works.
   //Mono does not support indeterminates so I'm not going to worry about it.
   return 0x7FFF;//NaN time! We have no way to tell NaN's apart so lets just choose one.

}

float i16uf(integer a) {//union short integer to half-precision float

   if((a & 0x7C00) == 0x7C00)
       return (1 | ((a << 16) >> 31)) * (float)llList2String(["NaN","Infinity"], !(a & 0x3FF));
   return 0.000000059604644775390625 * (1 << (a - !!a)) * ((!!(a = (0x1f & (a >> 10))) << 10) | ((a & 0x3ff))) * (1 | ((a << 16) >> 31));

} </lsl>

Float Compare

<lsl>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, basically, it gets the mantissa, sets the sign on the mantissa,
           if(diff >= -1 || diff <= 1)//shifts it depending on exponent, finally 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>

FUI2HexFloat

<lsl> //This implementation isn't meant to create the most compact hexfloat and makes no effort to. //It was designed to quickly produce an accurate hexfloat. //Do keep in mind it does not handle NAN or INF. string FUI2HexFloat(integer b) {//Dump FUI float-integer to a hex-float string

   string c = "";
   integer d = 0;
   integer e = 0xff & (b >> 23);
   string f = "0x"+(string)(!!e) + ".";
   if(b & 0x80000000)
       f = "-"+ f;
   if(e ^ 127) c = "p" + (string)((e | !e) - 127);
   if((e = 0xfffffe & (b << 1)))
   {
       while(!((e >> d) & 0xf))
           d+=4;
       while(d < 24)
       {
           c = llGetSubString(hexc, b = 0xf & (e >> d), b) + c;
           d += 4;
       }
   }
   return f + c;

}

string Float2Hex(float a) {//Another way to do Float2Hex, i wrote this for the heck of it; not because it's a good idea.

   return FUI2HexFloat(fui(a));

} </lsl>