wrote this ages ago, it isn't very fast but it is accurate.

Works flawlessly and LSL can parse directly to floats again without any special code

just use a (float) typecast.

**Discussion thread:**/54/fb/84483/1.html

Changes:

Rewrote the code almost from scratch, imported much of the knowledge learned from Float2Hex and float-union-integer (shares some code with FUI). Optimized the code, added comments, and descriptive variable names. Fixed a crashing bug and added precision to the math (won't effect the output). Relaxed some of the string method to be faster. Basically, everything has changed. It should also be *faster*. Cleaner logic.

CODE

string Float2Sci(float input)

{

if(input == 0.0)//handles negitive zero

return llDeleteSubString((string)input, -5, -1);//trim off the trailing zero's, don't need them.

float frac = llFabs(input);//we put the negitive back at the end.

string mantissa = (string)frac;//this may be a string of about 47 characters long.

integer exponent = -6;//default exponent for optical method

if(frac < 16.0)//optical might fail

if(frac != (float)mantissa)//optical did fail

jump in;

//optical will work, so all we need do is remove the decimal point and jump to optical.

mantissa = llDeleteSubString(mantissa, -7, -7);

jump optical;

@in;

//Ugly Math version; ugly in the sence that it is slow and not as elegant as working with it as a string.

//A) calculate the exponent via approximation of C log2()

//B) use cludge to avert fatal error in approximation of log2 result (only a problem with values >= 0x1.FFFFF8p127)

// the exponent is sometimes reported as 128, which will bork float math, so we subtract the test for 128.

// max_float btw is 0x1.FFFFFEp127, so we are only talking a very small number of numbers.

//C) normalize the float with questionable exponent

//D) calculate rounding error left from log2 approimation and add to normalization value.

// the '|' acts like a '+' in this instance but saves us one byte.

integer position = (24 | (3 <= frac)) - (integer)( //D

frac /= (float)("0x1p"+(string)( //C

exponent = (exponent - (( //B

exponent = llFloor(llLog(frac) / 0.69314718055994530941723212145818) //A

) == 128))

))

);

//this pushes the float into the interger buffer exactly.

//since the shift is within integer range, we don't need to make a float.

integer int = (integer)(frac * (1 << position));

integer target = (integer)(frac = 0.0);//since the float is in the integer buffer, we need to clear the float buffer.

//we don't use a traditional while loop, and instead opt for a do-while, because it's faster

//since we may have to do about 128 iteration, this savings is important,

//the exponent needs one final adjustment because of the shift, we do it here to save memory & it's fasfter.

//The two loops try to make exponent == position by shifting and multiplying.

//when they are equal, then this should be true ((int * llPow(10, exponent)) == llFabs(input))

//That is of course assuming that the llPow(10, exponenet) result has enough percision.

//We recycle position for these loops as a temporary buffer. This is so we can save a few operations.

//If we didn't, then we could actualy optimize the variable out of the code; though it would be slower.

if(target > (exponent -= position))

{//apply the rest of the bit shift if |input| < 1

do

{

if(int < 0x19999999)//(0x80000000 / 5)

{//won't overflow, multiply in 5

int = int * 5 + (position = (integer)(frac *= 5.0));

frac -= (float)position;

target = ~-target;

}

else

{//overflow predicted, devide by 2

frac = (frac + (int & 1))/2;

int = int >> 1;

exponent = -~exponent;

}

}while(target ^ exponent);

}

else if(target ^ exponent)//target < exponent

{//apply the rest of the bit shift if |input| > 1

do

{

if(int < 0x40000000) //(0x80000000 / 2)

{//won't overflow, multiply in 2

int = (int << 1) + (position = (integer)(frac *= 2.0));

frac -= (float)position;

exponent = ~-exponent;

}

else

{//overflow predicted, devide by 5

frac = (frac + int%5) / 5.0;

int /= 5;

target = -~target;

}

}while(target ^ exponent);

}

//int is now properly calculated, it holds enough data to accurately describe the input in conjunction with exponent.

//we feed this through optical to clean up the answer.

mantissa = (string)int;

@optical;

//it's not an issue that we may be jumping over the initialization of some of the variables,

//we initialize everything we use here.

//to accurately describe a float you only need 9 decimal places; so we throw the extra's away

if(9 < (target = position = llStringLength(mantissa)))

position = 9;

//chop off the tailing zero's; we don't need them.

do; while(llGetSubString(mantissa, position, position) == "0" && (position = ~-position));//faster then a while loop

//we do a bad thing, we recycle 'target' here, position is one less then target,

//"target + ~position" is the same as "target - (position + 1)" saves 6 bytes.

//this block of code actualy does the cutting.

if(target + ~position) mantissa = llGetSubString(mantissa, 0, position);

//insert the decimal point (not strictly needed). We add the extra zero for asthetics.

//by adding in the decimal point, it simplifies some of the code.

mantissa = llInsertString(mantissa, 1, llGetSubString(".0", 0, !position));

//adjust exponent from having added the decimal place

if((exponent += ~-target))

mantissa += "e" + (string)exponent;

//return with the correct sign.

if(input < 0)

return "-" + mantissa;

return mantissa;

}

Old Version:

CODE

float LOG2 = 0.30102999566398119521373889472449;

string FloatToSci(float Feed)

{

integer c;

integer d;

integer e;

float AFeed = llFabs(Feed);

integer Exp;

string Mant = (string)AFeed;

if(AFeed<16.0) //unsure about optical

{

if(AFeed!=(float)Mant) //optical fails

{

//55 bits used.

//d is the bitshift

//AFeed is the

integer f;

float tff;

c=(integer)((AFeed / llPow(2,d = llFloor(llLog10(AFeed) / LOG2))) * llPow(2,24));

d -= 24;

//time to apply the rest of the bit shift AFeed<1

while(e>d)

{

//overflow test

if(c >= 0x19999999) //(0x80000000 / 5)

{//overflow predicted, devide by 2

tff = (tff + c%2)/2;

c/=2;

++d;

}

else

{//won't overflow, multiply in 5

c = c*5 + (f = (integer)(tff*=5.0));

tff -= (float)f;

--e;

}

}

//time to apply the rest of the bit shift AFeed>1

while(e<d)

{

if(c >= 0x40000000) //(0x80000000 / 2)

{//overflow predicted, devide by 5

tff = (tff + c%5) / 5.0;

c /= 5;

++e;

}

else

{//won't overflow, multiply in 2

c= c * 2 + (f = (integer)(tff *= 2.0));

tff -= (float)f;

--d;

}

}

Mant = (string)c;

Exp = d;

//use this to speed things up, but output will be ugly and possibly wasteful.

// jump quick;

d = llStringLength(Mant);

jump go;

}

}

d = llStringLength(Mant);

if((c = llSubStringIndex(Mant,"."))+1)

{//remove the decimal, this makes everything else easier.

Exp -= (d -= 1) - c;

Mant = llDeleteSubString(Mant,c,c);

}

@go;

if(d>9 || llGetSubString(Mant,-1,-1)=="0")

{

if((e = d)>9)

c = 9;

else

c = d - 2;//already checked the last digit.

while(llGetSubString(Mant,c,c)=="0" && c)

--c;

Exp += e - (d = (c + 1)) + (c!=-1)*c;

Mant = llInsertString(llDeleteSubString(Mant, c+1, e), 1, llGetSubString("0.0", d>0, 1 + (d<2)));

}

else

{

if(d)

Exp += d - 1;

Mant = llInsertString(Mant, 1, llGetSubString("0.0", d>0, 1 + (d<2)));

}

@quick;

if(Exp)

{

if(Exp>0)

Mant += "E+" + (string)Exp;

else

Mant += "E" + (string)Exp;

}

if(Feed<0)

return "-" + Mant;

return Mant;

}