Difference between revisions of "Category:LSL Float"

From Second Life Wiki
Jump to navigation Jump to search
(typo fix)
(Improve wording. Add caveat on float precision. Add float string validation routine.)
Line 2: Line 2:
{{RightToc}}{{LSLC|}}{{LSLC|Types}}
{{RightToc}}{{LSLC|}}{{LSLC|Types}}
Floating point data types are 32 bit numbers in IEEE-754 form.  
Floating point data types are 32 bit numbers in IEEE-754 form.  
If you want a decimal point in your number, then it is a float.
If a number is written with a decimal point in LSL, then it is taken to be a float.


The range is 1.401298464E-45 to 3.402823466E+38  
The valid range is 1.401298464E-45 to 3.402823466E+38  


They can be specified in scientific notation like 2.6E-5.
Floats can be specified in scientific notation such as 2.6E-5.


If a function requires a float as a parameter, and the number is an integer (e.g. 5), be sure to add a .0 so it is created as a float (e.g. 5.0)
If a function requires a float as a parameter, and the number is an integer (e.g. 5), you can add the .0 to clearly indicate it's a float, but omitting the .0 is equally valid and actually saves bytecode space in the compiled code.


If you are dividing 2 constants, be sure to define them as floats or your result may get rounded. Better yet, do the math on your calculator and save the server some cycles.
When dividing 2 constants, defining them as floats will avoid the chance of unwanted rounding down. Better still, do the math on your calculator and save the server some cycles.


<div id="box">
<div id="box">
Line 37: Line 37:
However, the following is more efficient, but comes with the noted caveats. If these are not an issue to you then it is the recommended option, particularly under Mono:
However, the following is more efficient, but comes with the noted caveats. If these are not an issue to you then it is the recommended option, particularly under Mono:
<lsl>integer isValidFloat(string s) { return (float)(s + "1") != 0.0; }</lsl>
<lsl>integer isValidFloat(string s) { return (float)(s + "1") != 0.0; }</lsl>
The above snippets are of limited use, as they stop validating at the first character that is not valid in a float string. The following code rigorously validates the whole of a string to ensure it represents a float.
<lsl>
// Validate a string containing a float value
// handles scientific notation and "nan" / "inf"
// Does not handle hex floats (!)
integer  ValidateFloatString(string ss)
{
    ss = llToLower(ss);
    if (ss == "")                                        return FALSE;
    if (ss == "inf" || ss == "-inf" || ss == "nan")      return TRUE;
    integer flagDP;
    integer flagEXP;
    integer num = llStringLength(ss);
    integer x;
    string char;
    for ( ; x < num; ++x)          // Examine the string byte by byte left to right
    {
        char = llGetSubString(ss, x, x);
        if (char == "-" || char == "+")
        {
            if (x)  return FALSE;
        }
        else if (char == ".")
        {
            if (flagEXP)          return FALSE;      // '.' cannot come after 'E' / 'e'
            if (flagDP++)          return FALSE;      // cannot have more than 1 '.'
        }
        else if (char == "e")
        {
            if (!flagDP)          return FALSE;        // E/e must have been preceeded by a '.'
            if (flagEXP++)        return FALSE;        // ... and no other 'E'
            char = llGetSubString(ss, x+1, x+1);        // Examine the following character
            if (char == "+" || char == "-")        ++x;     
            if ( (num - x) > 3 || (num - x) < 2)  return FALSE;    // 'e' should be followed by 1 or 2 digits after optional sign
        }
        else if ( (string) ( (integer) char) != char)      return FALSE;        // effectively  checking for 0 thru 9
    }
    return TRUE;
}
</lsl>
'''Caveats''':
'''Caveats''':
* Under LSO-LSL scientific notation with an exponent greater than 38 will fail (throw a Math Error). Mono is unaffected as it supports <code>infinity</code>
* Under LSO-LSL scientific notation with an exponent greater than 38 will fail (throw a Math Error). Mono is unaffected as it supports <code>infinity</code>
* Under both Mono and LSO-LSL you may find strange results if dealing with strings containing more than 9 decimal places. Remember that string casting in LSL only gives up to 6 so is safe, and human input is rarely going to be that accurate, plus values that small are not usually all that useful.
* Under both Mono and LSO-LSL you may find strange results if dealing with strings containing more than 9 decimal places. Remember that string casting in LSL only gives up to 6 so is safe, and human input is rarely going to be that accurate, plus values that small are not usually all that useful.
* "nan", "inf" and their negatives are special text values that can be cast from a string (with any leading spaces or trailing characters). those values will cause a math error when the variable is evaluated in LSO. If you are parsing user data, by casting a string to a float, use the following code (replacing vStrDta with your string variable name) see [https://jira.secondlife.com/browse/SVC-6847 SVC-6847]
* Due to the limited precision with which floats are stored, not all integer values can be accurately held in a float. Integers above 16,777,216 are rounded down to the nearest even number; above 33,554,432 to the lower multiple of 4 etc.
* "nan" (not-a-number), "inf" (infinity) and their negatives are special text values that can be cast from a string (with any leading spaces or trailing characters). those values will cause a math error when the variable is evaluated in LSO. If you are parsing user data, by casting a string to a float, use the following code (replacing vStrDta with your string variable name) see [https://jira.secondlife.com/browse/SVC-6847 SVC-6847]
** <lsl>(float)llList2String( llParseStringKeepNulls( llToLower( llStringTrim( vStrDta, STRING_TRIM ) ), ["inf", "nan"], [] ), 0 )</lsl>
** <lsl>(float)llList2String( llParseStringKeepNulls( llToLower( llStringTrim( vStrDta, STRING_TRIM ) ), ["inf", "nan"], [] ), 0 )</lsl>
</div></div>
</div></div>

Revision as of 09:33, 22 January 2014

Floating point data types are 32 bit numbers in IEEE-754 form. If a number is written with a decimal point in LSL, then it is taken to be a float.

The valid range is 1.401298464E-45 to 3.402823466E+38

Floats can be specified in scientific notation such as 2.6E-5.

If a function requires a float as a parameter, and the number is an integer (e.g. 5), you can add the .0 to clearly indicate it's a float, but omitting the .0 is equally valid and actually saves bytecode space in the compiled code.

When dividing 2 constants, defining them as floats will avoid the chance of unwanted rounding down. Better still, do the math on your calculator and save the server some cycles.

Examples

<lsl>float min = 1.175494351E-38; float max = 3.402823466E+38; float sci = 2.6E-5; float sci_a = 2.6E+3; float sci_b = 2.6E3; float sci_c = 26000.E-1; float f = 2600;//implicitly typecast to a float float E = 85.34859; float cast = (float)"42";//explicit typecast to a float float Infintity = (float)"inf"; //-- may be negative, will cause a math error if evaluated in LSO, see 'caveats' below float NotANumber = (float)"nan"; //-- may be negative, will cause a math error if evaluated in LSO, see 'caveats' bleow </lsl>

Useful Snippets

If you need to validate an arbitrary float without limitations then the following function is ideal: <lsl>integer isValidFloat(string s) { return (string)((float)s) != (string)((float)("-" + llStringTrim(s, STRING_TRIM_HEAD))); }</lsl>

However, the following is more efficient, but comes with the noted caveats. If these are not an issue to you then it is the recommended option, particularly under Mono: <lsl>integer isValidFloat(string s) { return (float)(s + "1") != 0.0; }</lsl>

The above snippets are of limited use, as they stop validating at the first character that is not valid in a float string. The following code rigorously validates the whole of a string to ensure it represents a float. <lsl> // Validate a string containing a float value // handles scientific notation and "nan" / "inf" // Does not handle hex floats (!)

integer ValidateFloatString(string ss) {

   ss = llToLower(ss);
   if (ss == "")                                         return FALSE; 
   if (ss == "inf" || ss == "-inf" || ss == "nan")       return TRUE;

   integer flagDP;
   integer flagEXP;
   integer num = llStringLength(ss);
   integer x;
   string char;

   for ( ; x < num; ++x)           // Examine the string byte by byte left to right
   {
       char = llGetSubString(ss, x, x);
       if (char == "-" || char == "+")
       {
           if (x)  return FALSE;
       }
       else if (char == ".")
       {
           if (flagEXP)           return FALSE;      // '.' cannot come after 'E' / 'e'
           if (flagDP++)          return FALSE;      // cannot have more than 1 '.'
       }
       else if (char == "e")
       {
           if (!flagDP)           return FALSE;        // E/e must have been preceeded by a '.'
           if (flagEXP++)         return FALSE;        // ... and no other 'E'
           char = llGetSubString(ss, x+1, x+1);        // Examine the following character
           if (char == "+" || char == "-")        ++x;       
           if ( (num - x) > 3 || (num - x) < 2)   return FALSE;     // 'e' should be followed by 1 or 2 digits after optional sign
       }
       else if ( (string) ( (integer) char) != char)       return FALSE;         // effectively  checking for 0 thru 9
   }
   return TRUE;

} </lsl> Caveats:

  • Under LSO-LSL scientific notation with an exponent greater than 38 will fail (throw a Math Error). Mono is unaffected as it supports infinity
  • Under both Mono and LSO-LSL you may find strange results if dealing with strings containing more than 9 decimal places. Remember that string casting in LSL only gives up to 6 so is safe, and human input is rarely going to be that accurate, plus values that small are not usually all that useful.
  • Due to the limited precision with which floats are stored, not all integer values can be accurately held in a float. Integers above 16,777,216 are rounded down to the nearest even number; above 33,554,432 to the lower multiple of 4 etc.
  • "nan" (not-a-number), "inf" (infinity) and their negatives are special text values that can be cast from a string (with any leading spaces or trailing characters). those values will cause a math error when the variable is evaluated in LSO. If you are parsing user data, by casting a string to a float, use the following code (replacing vStrDta with your string variable name) see SVC-6847
    • <lsl>(float)llList2String( llParseStringKeepNulls( llToLower( llStringTrim( vStrDta, STRING_TRIM ) ), ["inf", "nan"], [] ), 0 )</lsl>

Float-to-String

There are several ways to convert a float to a string. The first of which is to typecast it to a string (string)(1.0). This however has the disadvantage of rounding and being limited to six decimal places. Several functions have been written to provide more options. They fall into two categories, lossless and lossy.

Lossy functions
Name inf/nan Rounding Truncation Notes
Typecast Yes Yes No (string)float_value
Mono only gives 6 digits of precision.
Format Decimal No Yes No
Float2String No Yes Yes
Lossless functions
Name Speed Reversible inf/nan support PI Notes
Float2Hex Fast (float) No 0x6487ED5p-25 Since the output is in the Hexadecimal Scientific Notation, it's not really human readable.
Float2Sci Slow (float) No 3.1415925 Useful when you want the result to be lossless but also human readable, comes at the cost of speed.
FUIS Fastest SIUF No "QEkP2g" Not at all human readable. Guarantied to always use six characters.
  • Infinity is only accessible in Mono.

Subcategories

This category has only the following subcategory.

Pages in category "LSL Float"

The following 8 pages are in this category, out of 8 total.