$nav
===== Float type =====
The $ty[float] type represents a number with decimals, as opposed to the $lty[integer] type which is for whole numbers only.
Floating-point ($ty[float]) constants can be entered in two formats. The first is by just writing the number with its sign, the decimal point (mandatory for the constant to actually be a float and not an integer), and the decimals. For example, ''3.7'' or ''-5.4164'' are valid float constants. Neither the part to the left of the point nor the part to the right of the point are mandatory (e.g. ''37.'' or ''-.25'' are valid), but a point without any digits around it is not a valid floating-point constant.
The second format is scientific notation. That means to write a number (with or without decimals, and with an optional minus sign) that is to be multiplied by a power of ten, then an ''e'' (upper or lower case, doesn't matter), then the power of ten (optionally with a plus or minus sign). It can be optionally followed by an ''f'' (upper or lower case) but that extra ''f'' has no effect, and it is only allowed if there's a point present. For example: ''2e4'' and ''2.0E+4F'' are float constants that represent the same number, namely 2.0 times 10 to the 4th power, which can also be written as ''20000.0''; other examples are: ''-3.6123e-7'', ''1.2e-27f'', ''5e30''. The number ''2e4f'' is not valid because it has an ''f'' and there is no point present. When the power of ten is negative, it means to //divide// by 10 to that power without sign; for example, ''3.3e-5'' means 3.3/100000 or 0.000033.
This so called scientific notation allows writing very big and very small numbers without having to write that many digits. For example, imagine having to write ''5.4e30'' as ''5400000000000000000000000000000.0''.
The range of a float is approximately from -3.4028234e38 to 3.4028234e38. The smallest positive number that it can represent is approx. 1.4e-45. It can also have the value minus zero (-0.0) but that one is usually not distinguished from a regular zero. In Mono, a float can also have three special values: $pinf, $minf, and $nan (Not a Number). In LSO, however, any operation that would result in any of these values will instead cause a math error and stop the script until it's reset.
==== Automatic type conversion between float and integer ====
Most places that accept a $ty[float]-type value also accept an $ty[integer]-type value, which will be automatically converted to $ty[float] if necessary. For example:
// 3 is an integer constant, but it is automatically converted to float
float x = 3;
// llSetTimerEvent accepts a float parameter, but this will work;
integer j = 2;
llSetTimerEvent(j);
This can save some space in Mono, because integer constants that get converted to floats take less bytes than float constants.
The opposite is not true in general. If a $ty[float] is used where an $ty[integer] is expected, that will generate a compiler or run-time error, depending on the context. An exception is the $lfn[llList2Integer] function, which will implicitly convert a floating-point value in a list to $ty[integer]. For example:
integer a = 3.0; // will give a type mismatch error when compiling
// PRIM_MATERIAL should be followed by an integer.
// The following line will cause a run-time error when executed.
llSetPrimitiveParams([PRIM_MATERIAL, 1.0]);
// This will display 3 and not cause any errors, because
// llList2Integer can be used on a float value.
llOwnerSay((string)llList2Integer([3.0], 0));
==== Precision ====
$ty[float] values are [[http://en.wikipedia.org/wiki/Single-precision_floating-point_format|single-precision]] floats. An implication is that their precision is 6 to 9 significant digits, that is, total digits starting from the leftmost non-zero digit.
For example, in this format, the number 1.000000001 can't be distinguished from the number 1.000000002 because it requires 10 significant digits to distinguish them, and there are not enough significant digits in the float type. However, the number 1.00001 can be distinguished from the number 1.00002 because it has 6 significant digits.
Due to the way floats work, the closer to zero they are the more precision after the decimal point they have, and vice versa. Numbers above 8,388,608.0 or less than -8,388,608.0 don't have any decimal places at all, while numbers between -1.0 and 1.0 have at least 6 decimal places, possibly more depending on how close to zero they are.
=== Type casting a float to string ===
When they are typecast to $lty[string], floats are always translated with all of their digits to the left of the decimal point, and six decimal places to the right, rounded. However, as an exception, when a $lty[vector] (a collection of three floats) or a $lty[rotation] (a collection of four floats) is typecast to $ty[string], its floats are converted using five decimal places to the right of the decimal point. This exception does not apply if they are inside a list and the list is converted to string.
In Mono, the typecast of a $ty[float] to $ty[string] will only store up to 7 significant digits and set the rest to zero, rounding the last digit; for example, ''1234567890.0'' will be converted to ''"1234568000.000000"''.
Some examples will illustrate these rules (the results from these examples are generated with Mono; output in LSO will be different because the float formatting functions differ):
llOwnerSay((string)1.);
// Prints 1.000000
llOwnerSay((string)3e38);
// Prints 300000000000000000000000000000000000000.000000
llOwnerSay((string)1e-6);
// Prints 0.000001
llOwnerSay((string)1e-7);
// Prints 0.000000
llOwnerSay((string)5e-7);
// Prints 0.000001 because of the rounding
llOwnerSay((string)3.1415926535897932384626433832);
// Prints 3.141593
llOwnerSay((string)<1.0, 2.0, 3.0>);
// Prints <1.00000, 2.00000, 3.00000>
// (note each number displayed with 5 decimal places, not 6)
llOwnerSay((string)<1.0, 2.0, 3.0, 4.0>);
// Prints <1.00000, 2.00000, 3.00000, 4.00000>
// (note each number displayed with 5 decimal places, not 6)
llOwnerSay((string)[<1.0, 2.0, 3.0>]);
// In this case, it's a list what gets converted to string.
// When a list is converted to string, the floats in the vectors and rotations
// that it contains are converted with 6 decimal places instead of 5.
// The output is thus: <1.000000, 2.000000, 3.000000>
llOwnerSay(llList2String([<1.0, 2.0, 3.0>], 0));
// Same as above. llList2String applied to a vector element will convert to
// string using 6 decimal places too.
The float value $nan is translated to the string ''NaN'', no matter the kind; the float value $pinf is translated to the string ''Infinity'' and the float value $minf to the string ''-Infinity''. This happens also with other functions that convert floats to string (e.g. $lfn[llList2String], $lfn[llDumpList2String]), except one: $lfn[llList2CSV] translates the float value $nan to the string ''nan'' (if it's regular NaN) or ''-nan'' (if it's the indeterminate kind of NaN), and translates $pinf and $minf to ''inf'' and ''-inf'' respectively.
=== Precision caveats ===
Floats are represented internally in base 2, not in base 10. That leads many people to confusion, because some decimal numbers can't be represented accurately in base 2, and rounding errors occur. It's not a bug; it's a limitation of the type, and a necessary compromise. For example:
default
{
state_entry()
{
float a = 0.6 + 0.1;
float b = 0.7;
if (a == b)
llOwnerSay("equal");
else
llOwnerSay("different");
}
}
The code above prints "different", because the addition introduces rounding errors. A frequent instance of this problem arises when counting from 0 to 1 in increments of 0.1. The following example illustrates a typical case:
default
{
state_entry()
{
float f;
for (f = 0.0; f <= 1.0; f += 0.1)
{
llOwnerSay((string)f);
}
}
}
This example prints 0.000000, 0.100000, etc. up to 0.900000 but //not// 1.000000. Due to accumulated rounding error, the actual final value is approximately 1.00000012 instead of 1, which is slightly larger than 1 and thus doesn't meet the condition for f <= 1. That is unfortunate but expected, because 0.1 can not be represented exactly in a $ty[float] type, and it has to be approximated.
A $ty[float] can only //exactly// represent fractions which have a power of two as a denominator when simplified. For example, 3.75 = 15/4 has a power of two in its denominator and can thus be represented exactly in a $ty[float]. Same happens with 3.78125 = 121/32. However, 0.1 = 1/10 can't be represented in that form, because 10 is not a power of two. Instead, it's represented with the approximation 13421773/134217728 which is approximately 0.1000000015, and when adding many of these together, rounding does not always get the desired result, and it's expectable that sooner or later, the obtained result will differ from the expected one. That causes the above problem, and confuses many unaware people who use floating-point math in many languages, not just LSL.
In general, it's not a good idea to loop over floats, unless you are aware of the limitations and know that the operations you're doing are safe. One possible solution to the problem in the particular example above is to loop using integers instead, and divide inside the loop, like this:
default
{
state_entry()
{
integer i;
for (i = 0; i <= 10; ++i)
{
llOwnerSay((string)(i/10.0));
}
}
}
This example will print 0.000000, 0.100000, 0.200000, etc. up to 1.000000 inclusive.
Another possible solution is to use a step that is a power of 2, like 0.125 (1/8), instead of 0.1, because that step is not affected by rounding errors, since it can be represented exactly. This will work as expected:
default
{
state_entry()
{
float f;
for (f = 0.0; f <= 1.0; f += 0.125)
{
llOwnerSay((string)f);
}
}
}
That loop will print 0.125000, 0.250000, 0.375000, etc. up to 1.000000 inclusive.