Difference between revisions of "Category talk:LSL Float"

From Second Life Wiki
Jump to navigation Jump to search
Line 126: Line 126:


::Also since LSL doesn't care about how things end "infinity" and "infinite" and even "infant" are all parsed as "inf". I'm not ever sure how we want to validate that. -- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 21:34, 19 December 2013 (PST)
::Also since LSL doesn't care about how things end "infinity" and "infinite" and even "infant" are all parsed as "inf". I'm not ever sure how we want to validate that. -- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 21:34, 19 December 2013 (PST)
<lsl>
integer allFloat(string in) {
string lower = llStringTrim(llToLowerCase(in), STRING_TRIM_BOTH);
if(llGetSubString(lower, 0, 0) == "-") lower = llDeleteSubString(lower, 0, 0);
if(~llListFindList(["inf", "nan"], [lower])) return TRUE;//yeah I'm not solving this one either.
if(lower) {
list split;
integer length;
string dec = lower;
if(llGetSubString(lower, 0, 1) == "0x"){//hex
split = llParseStringKeepNulls(llDeleteSubString(lower, 0, 1), [], ["p+","p-","p"]);
length = llGetListLength(split);
if((length | 2) != 3) return FALSE; //must be 1 or 3
if(length == 3){
dec = llList2String(split, 2);
if(dec == "") return FALSE;
}
lower = llList2String(split, 0);
if(~llListFindList(["", "."], [lower])) return FALSE;
split = llParseStringKeepNulls(lower, ["."], []);
length = llGetListLength(split);
if((length | 2) != 3) return FALSE; //must be 1 or 3
lower = (string)split;
if((string)llParseString2List((string)llParseString2List(lower, ["0","1","2","3","4","5","6","7"], []), ["8","9","a","b","c","d","e","f"], [])) return FALSE;
if(dec == "") return TRUE;
} else { //decimal
split = llParseStringKeepNulls(llDeleteSubString(lower, 0, 1), [], ["e+","e-","e"]);
length = llGetListLength(split);
if((length | 2) != 3) return FALSE; //must be 1 or 3
if(length == 3){
dec = llList2String(split, 2);
if(dec == "") return FALSE;
}
lower = llList2String(split, 0);
if(~llListFindList(["", "."], [lower])) return FALSE;
split = llParseStringKeepNulls(lower, ["."], []);
length = llGetListLength(split);
if((length | 2) != 3) return FALSE; //must be 1 or 3
dec += (string)split;
}
if(dec){
return "" == (string)llParseString2List((string)llParseString2List(lower, ["0","1","2","3","4","5","6","7"], []), ["8","9"], []);
}
}
return FALSE;
}</lsl>
My solution (not compiled or debugged) --'''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 21:50, 19 December 2013 (PST)

Revision as of 21:50, 19 December 2013

Something Seems Off

Simple Script <lsl> default {

   state_entry()
   {
       llOwnerSay((string)((float)"3.402823466E+38"));
   }

} </lsl> In Mono It Says: 340282300000000000000000000000000000000.000000

In LSL Is Says: 340282346638528859811704183484516925440.000000

Shouldn't Both Give The Same? Adi 20:51, 15 July 2009 (UTC)

You can report it as a bug on Jira. The two values are however identical when read as floats. It's a feature of floating point precision types; the precision is at the top, not the bottom of the value. -- Strife (talk|contribs) 20:30, 17 July 2009 (UTC)
I believe some inconsistency is to be expected, though the difference does seem a little odd. In any event Mono's floats are definitely different as they support infinity where LSO will throw a Math Error beyond the maximum or minimum values, the differences in general are a good thing and it's unlikely it cause any real faults between LSO and Mono scripts. I would definitely report it on the JIRA though, and maybe add the issue to Kelly Linden's Scripting Triage so it can investigated to find out if it's a true float error, or if it's a bug in the way Mono casts it back to a string (perhaps it's rounding by significant figures rather than decimal places, or intentionally removing "error"?), is worth investigating further at least.
-- Haravikk (talk|contribs) 10:16, 23 October 2010 (UTC)
Infinity support was added intentionally to Mono. -- Strife (talk|contribs) 14:23, 24 October 2010 (UTC)

inf/nan handling in MONO

Last I checked both of those will crash a MONO script when used in math, just not on evaluation. I'll try and remember to confirm that. and see what they do when fed to a few functions.... might give me an excuse to reopen that jira Joshua nuked =S
-- Void (talk|contribs) 16:42, 30 May 2012 (PDT)

I only know about it because 3.403E+38 gets rounded up to infinity in Mono (it came up in a discussion recently). I thought I should document the situation. I'm pretty sure *nothing* supports it but I'm looking forward to finding a clever way to do so with FUI. -- Strife (talk|contribs) 21:04, 30 May 2012 (PDT)

nevermind, looks like the change was either reverted or I got it wrong.... and the functions I tested that took float/vector seem to treat them as 0, although I do note that color actually saves the actual value. Like you, I actually wanted them to print the extended signaling. although i wanted it for crushing keys into rotation data types, and storage of integers into float parameters.
-- Void (talk|contribs) 20:30, 3 June 2012 (PDT)

Validation of float strings

The first example of a validation function:-

integer isValidFloat(string s) { return (string)((float)s) != (string)((float)("-" + llStringTrim(s, STRING_TRIM_HEAD))); }

seems to be very limited, in that the process examines the leading float-compatible characters only. Hence a string such as 1w2x3y will be treated as a valid float. I've yet to check the second validation example.

Secondly, be aware that under LSO, ( "abc" != "def") returns -1, whereas under Mono it returns 1. So the function result can't be tested for TRUE. Omei Qunhua 03:52, 19 December 2013 (PST)

In LSO, != was strcmp. I tried to get them to keep it the same in Mono but they wouldn't.
As to validation:
We set the bar pretty low for validation. To just test the beginning of the string. LSL as you already know stops parsing a float and returns what it currently has when it encounters a bad character. So basically we set validation to: Is LSL going to find something or nothing? Also LSL is not sensitive to leading spaces, at least not for spaces. This validator is really fast.
Say you want to validate more carefully, ok, down the rabbit hole we go. We assume you do not want left over characters, does that include leading and trailing whitespace?
Writing a complete validator for LSL would be difficult but not impossible, especially now. You could use JSON to do the number parsing for decimal floats, but you would still need to write a parser for hexfloats. That is the advantage of the current validator, it's format agnostic and fast. Having to test all characters is not fast, it's going to be quite slow.
That said I've had a few ideas on how to do it faster (but still not fast). -- Strife (talk|contribs) 11:04, 19 December 2013 (PST)
Sure, sensible validation of a float string is tricky, but I just think the current offering is pointless. People's eyes will light up when they see a proposed solution on the Wiki, and then be lifted to the heavens as they realise it does next to nothing :) Omei Qunhua 14:03, 19 December 2013 (PST)
It's very non-trivial. However, I am currently working on a solution. I should have it up later tonight. It won't be pretty but it will work. -- Strife (talk|contribs) 14:51, 19 December 2013 (PST)

Here's a stab at it:- <lsl> // Validate a string containing a float value // Omei Qunhua

integer ValidateFloatString(string ss) {

   if (ss == "inf" || ss == "nan")       return TRUE;
   integer flagDP;
   integer flagEXP;
   integer wv;
   integer int;
   integer decimals;
   integer exponent;
   integer sign = 1;
   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 != 0)      return FALSE;       // + and - can only occur as first character, [ or after E ]
           sign = -1;
           if (char == "+")  sign = 1;
       }
       else if (char == ".")
       {
           if (flagEXP)         return FALSE;      // '.' cannot come after 'E'
           if (++flagDP > 1)    return FALSE;      // cannot have more than 1 '.'
           int = wv * sign;
           wv = 0;
           sign = 1;
       }
       else if (char == "E")
       {
           if (x != (num -4) )    return FALSE;        // E must be followed by 3 characters
           if (!flagDP)           return FALSE;        // ... and must have been preceeded by a '.'
           if (++flagEXP > 1)     return FALSE;        // ... and no other 'E' 
           decimals = wv * sign;
           wv = 0;
           char = llGetSubString(ss, ++x, x);
           if (char == "-")           sign = -1;
           else if (char == "+")      sign = 1;
           else                       return FALSE;
       }
       else if ( (string) ( (integer) char) == char)       // effectively  checking for 0 thru 9
       {
           wv = wv * 10 + (integer) char;
       }
       else                             return FALSE;    // invalid character
   }
   // end of string
   if (flagEXP)
       exponent = wv * sign;
   else if (flagDP)
       decimals = wv * sign;
   if ( (flagDP + flagEXP) == 0)
       int = wv * sign;
   // The ranges of 'int' , 'decimals' and 'exponent' could be checked here if desired
   return TRUE;

} </lsl> Omei Qunhua 20:39, 19 December 2013 (PST)

It's a good start but it doesn't include signed infinities, hex floats and it's currently case sensitive. "E" also does not have to be followed by a sign.-- Strife (talk|contribs) 21:13, 19 December 2013 (PST)
Also since LSL doesn't care about how things end "infinity" and "infinite" and even "infant" are all parsed as "inf". I'm not ever sure how we want to validate that. -- Strife (talk|contribs) 21:34, 19 December 2013 (PST)

<lsl> integer allFloat(string in) { string lower = llStringTrim(llToLowerCase(in), STRING_TRIM_BOTH); if(llGetSubString(lower, 0, 0) == "-") lower = llDeleteSubString(lower, 0, 0); if(~llListFindList(["inf", "nan"], [lower])) return TRUE;//yeah I'm not solving this one either. if(lower) { list split; integer length; string dec = lower; if(llGetSubString(lower, 0, 1) == "0x"){//hex split = llParseStringKeepNulls(llDeleteSubString(lower, 0, 1), [], ["p+","p-","p"]); length = llGetListLength(split); if((length | 2) != 3) return FALSE; //must be 1 or 3 if(length == 3){ dec = llList2String(split, 2); if(dec == "") return FALSE; } lower = llList2String(split, 0); if(~llListFindList(["", "."], [lower])) return FALSE; split = llParseStringKeepNulls(lower, ["."], []); length = llGetListLength(split); if((length | 2) != 3) return FALSE; //must be 1 or 3 lower = (string)split; if((string)llParseString2List((string)llParseString2List(lower, ["0","1","2","3","4","5","6","7"], []), ["8","9","a","b","c","d","e","f"], [])) return FALSE; if(dec == "") return TRUE; } else { //decimal split = llParseStringKeepNulls(llDeleteSubString(lower, 0, 1), [], ["e+","e-","e"]); length = llGetListLength(split); if((length | 2) != 3) return FALSE; //must be 1 or 3 if(length == 3){ dec = llList2String(split, 2); if(dec == "") return FALSE; } lower = llList2String(split, 0); if(~llListFindList(["", "."], [lower])) return FALSE; split = llParseStringKeepNulls(lower, ["."], []); length = llGetListLength(split); if((length | 2) != 3) return FALSE; //must be 1 or 3 dec += (string)split; } if(dec){ return "" == (string)llParseString2List((string)llParseString2List(lower, ["0","1","2","3","4","5","6","7"], []), ["8","9"], []); } } return FALSE; }</lsl>

My solution (not compiled or debugged) --Strife (talk|contribs) 21:50, 19 December 2013 (PST)