Category talk:LSL Float

From Second Life Wiki
Jump to navigation Jump to search

Something Seems Off

Simple Script

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

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)
I don't care if it's slow while reading a notecard, nor while awaiting user type. My script will still be twiddling its thumbs awaiting the next input. Omei Qunhua 05:31, 21 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 compiled and tested solution:- It accepts "inf", "-inf" and "nan" ... and not "infant" etc. which would clearly by balderdash It makes no attempt to validate hex floats. My view is that validation is required where the input has been provided by a human, and who is going to want to encode a hex float by hand? (Oh! Silly me - Strife would!!) I've removed the code that was computing the value of the various sub components.

// Validate a string containing a float value
// Does not handle hex floats (!)
// Compiled and tested. Omei Qunhua. Dec 2013

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;
}

Omei Qunhua 03:57, 20 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)
Fixed above points bar hex floats and extensions to inf and nan Omei Qunhua 14:43, 20 December 2013 (PST)
integer allFloat(string in) {
	string lower = llStringTrim(llToLower(in), STRING_TRIM_BOTH);
	if(~llListFindList(["inf", "-inf", "nan"], [lower])) return TRUE;//yeah I'm not solving this one either.
	if(llGetSubString(lower, 0, 0) == "-") lower = llDeleteSubString(lower, 0, 0);
	if(lower) {
		list split;
		integer length;
		string dec;
		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;
}

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

may want to double check that casts do not convert extended +/- signs (two plus) I seem to remember some odd behavior around that at one point, I'd check but, unable at the moment
-- Void (talk|contribs) 05:11, 20 December 2013 (PST)
I am worried about "+" but I know it fails on double "-" (it's one of the techniques for testing if a number is a number, slap a "-" in front). -- Strife (talk|contribs) 11:12, 20 December 2013 (PST)
One line doesn't compile:- string lower = llStringTrim(llToLowerCase(in), STRING_TRIM_BOTH); should be string lower = llStringTrim(llToLower(in), STRING_TRIM);
Omei coughs gently, passes Strife his spectacles and a cut-and-paste tool, and another tool lslEditor Omei Qunhua 05:31, 21 December 2013 (PST)
I really don't like writing in LSLEditor, it's too darn slow. It's like pulling teeth. That said, I do like to test code with it (but there are somethings it just does not do right and you have to know which ones those are). I'll start testing the darn thing and figure out where the bugs are (day off). -- Strife (talkcontribs) 12:00, 21 December 2013 (PST)
There were two typos on that one line. Then after your line } else { //decimal the next line shouldn't include the llDeleteSubString... After that, I tested it via lslEditor, and it validates pure integers OK, but decimals and scientific all fail. I've not tried putting hex through it. Have fun debugging! Omei Qunhua 15:48, 21 December 2013 (PST)

Omei Qunhua 05:31, 21 December 2013 (PST) Float string validation will very rarely need to accommodate scientific notation

// Version 2:  validates input such as [-]aaaa.bbbb
// Compiled and tested. Omei Qunhua. Dec 2013

integer  ValidateSimpleFloat(string sin)
{
    sin = llToLower(sin);
    // Avoid run time fail (for lslEditor at least) if string looks remotely like scientific notation 
    if (llSubStringIndex(sin, "e") != -1)   	return FALSE; 	
    list temp = llParseStringKeepNulls(sin, ["."], [] );
    string subs = llList2String(temp, 0);
    if ( (string) ( (integer) subs) != subs)    return FALSE;
    if ( (temp != []) > 2)                      return FALSE;
    if ( (temp != [])== 2)
    {
	subs = llList2String(temp, 1);    // extract the decimal part
        // must have no sign after DP, so handle first decimal discretely
	string first = llGetSubString(subs, 0, 0);
	if ( (string) ( (integer) first) != first)     return FALSE;  
	if ( (string) ( (integer) subs)  != subs)      return FALSE;
    }
    return TRUE;
}
Omei Qunhua 05:31, 21 December 2013 (PST)

This function integer isValidFloat(string s) { return (string)((float)s) != (string)((float)("-" + llStringTrim(s, STRING_TRIM_HEAD))); } rejects this string under Mono as not a float: "-0.0000001". I've written a validation function that doesn't have that problem and rejects trailing characters, and posted it here: [1] --Sei Lisa (talk) 16:14, 27 January 2016 (PST)

Float2Sci

Float2Sci is listed under "lossless functions", yet next to that function PI is shown as 3.1415925, whereas (off the top of my head, LOL) PI is 3.141592653589793... so at least the 7th DP is wrong, so how can it be a lossless function? Omei Qunhua 15:31, 22 January 2014 (PST)

First lossless in this care means that every bit of information that is held in the float is preserved and the can be used to reconstruct the input. Floats do not have a large quantity of precision, which translates roughly to the number of accurate digits. Unfortunately PI is irrational and irrational numbers cannot be losslessly stored in a float because they require an infinite number of digits to express them accurately. So, PI gets truncated. When you do math operations, errors creep. You would think that 10 * 0.1 would equal 1.0, it does not. The reason for this is that 0.1 can't be accurately represented as a float. The point of the lossless functions are to keep more errors from creeping in as a result of converting the number back into a float. Also for debugging purposes, you may want to know the exact value, if you can't find out the exact value, you may have numbers that look like they should work but then don't and you won't know why. -- Strife (talk|contribs) 15:21, 23 January 2014 (PST)
TL;DR: The functions are lossless, LSL is not.
Yep, I woke up in the night thinking that must be the explanation LOL Omei Qunhua 15:31, 23 January 2014 (PST)
I find the math really interesting, I'd recommend looking over "Wikipedia logo"Floating_point for more details if you are interested in the math. -- Strife (talk|contribs) 15:49, 23 January 2014 (PST)