Difference between revisions of "User:Strife Onizuka/Float Functions"
m (→Float {{LSL_VR|-Union-}} Integer: Typo fix: stirde -> stride) |
(spell checking, the browser has it, I should use it.) |
||
Line 10: | Line 10: | ||
integer c = llFloor((llLog(a) / 0.69314718055994530941723212145818));//extremes will error towards extremes. following yuch corrects it. | 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); | 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 | }//for grins, detect the sign on zero. it's not pretty but it works. the previous requires a lot of unwinding to understand it. | ||
return ((string)a == (string)(-0.0)) << 31; | return ((string)a == (string)(-0.0)) << 31; | ||
} | } | ||
Line 17: | Line 17: | ||
{//union integer to float | {//union integer to float | ||
return ((float)("0x1p"+(string)((a | !a) - 150))) * ((!!(a = (0xff & (a >> 23))) << 23) | ((a & 0x7fffff))) * (1 | (a >> 31)); | 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 | }//will crash if the raw exponent == 0xff; reason for crash deviates from float standard; though a crash is warranted. | ||
</lsl> | </lsl> | ||
Line 26: | Line 26: | ||
if(a){//is it non zero? | if(a){//is it non zero? | ||
integer b = (a < 0) << 31;//the sign, but later this variable is reused to store the shift | 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 | 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. | b = b | (integer)(a / 1.4012984643248170709237295832899e-45);//the math overlaps; saves cpu time. | ||
else | else | ||
Line 34: | Line 34: | ||
} | } | ||
return llGetSubString(llIntegerToBase64(b),0,5); | return llGetSubString(llIntegerToBase64(b),0,5); | ||
}//for grins, detect the sign on zero. it's not pretty but it works. the previous requires | }//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((string)a == (string)(0.0)) | if((string)a == (string)(0.0)) | ||
return "AAAAAA"; | return "AAAAAA"; | ||
Line 44: | Line 44: | ||
integer a = llBase64ToInteger(b); | integer a = llBase64ToInteger(b); | ||
return ((float)("0x1p"+(string)((a | !a) - 150))) * ((!!(a = (0xff & (a >> 23))) << 23) | ((a & 0x7fffff))) * (1 | (a >> 31)); | 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 | }//will crash if the raw exponent == 0xff; reason for crash deviates from float standard; though a crash is warranted. | ||
</lsl> | </lsl> | ||
Line 60: | Line 60: | ||
((a_i & 0x80000000) == (b_i & 0x80000000)))//sign match check | ((a_i & 0x80000000) == (b_i & 0x80000000)))//sign match check | ||
{//start by getting and testing the difference, this is what limits c | {//start by getting and testing the difference, this is what limits c | ||
integer diff = a_e - b_e;//ugly is fast, | 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, | 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) - | 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) | ((((b_i & 0x7FFFFF) | (!!b_e << 23)) * ((b_i >> 31) | 1)) >> !~diff)) <= c) |
Revision as of 21:15, 23 December 2012
LSL Portal | Functions | Events | Types | Operators | Constants | Flow Control | Script Library | Categorized Library | Tutorials |
Float <-Union-> Integer
<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 stride 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 a lot 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 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 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 stride of normalized range b = b | (integer)(a / 1.4012984643248170709237295832899e-45);//the math overlaps; saves cpu time. 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 == 128)))))))) << 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((string)a == (string)(0.0)) return "AAAAAA"; return "gAAAAA";
}
float siuf(string b) {//base64ed integer union to float
integer a = llBase64ToInteger(b); 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>
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>