LSL 101/LSL in Focus: Integers

From Second Life Wiki
Jump to: navigation, search
← Types ↑̲  Language Topics in Focus  ̲↑ Floats →

Integers in LSL roughly correspond to integers in mathematics. They can be written in either the familiar decimal (e.g. 20, 0, -1) or hexadecimal (e.g. 0x14, 0x0, 0xFFFFFFFF).

Integers in LSL are used in four distinct ways:

  • Signed integers
  • Truth values (Booleans)
  • Enumerations
  • Bit vectors

There are a three operators, namely = (assignment), == (test for equality) and != (test for inequality) that are common to all uses of integers. Other than those, the four different uses of integers generally involve separate sets of operators.

Signed Integers

This is the use of integers that corresponds to the normal use in mathematics. The only substantive difference is that in mathematics, there are infinitely many integers, while in LSL integers are limited to the range −2,147,483,648 to 2,147,483,647. Also, in LSL, no commas or other separators are allowed when writing integers, so these numbers would be written −2147483648 and 2147483647.

Arithmetic Operators

LSL has the normal arithmetic operators +, -, * and / (for division). The first three have the same meaning as what you used in grade school as long as the result is in the range −2147483648 to 2147483647. If the result is outside that range, different rules apply. The typical scripter doesn't need to use numbers that are so big (or small), so there's nor reason to feel you need to learn the details of what happens when the limits are exceeded. But there are instances where it is actually useful to allow numbers to exceed the limits. For the details of what happens in that case, see the Integer Overflow section, below.

Division of integers in LSL is a variation on what you learned in elementary school. If the division results in a whole number, say 10/2, the answer is 5. But 15/2 is neither 7.5 nor 7 with a remainder of 1. Instead, it is exactly 7. Any remainder is simply thrown away. Alternatively, you can think of it as being rounded toward zero. It's more accurate to say "rounded toward zero" than "rounded down", because -15/2 is -7, not -8. If you're scripting something where you really want 15 divided by 2 to be 7.5, don't despair. You'll just need to use the "float" type instead of integers.

Closely related to integer division is the remainder operator, written as %. It gives you what would remain if you were to ask for integer division on the same numbers. Here are some examples:

 integer i;
 i = 15 % 2;     // i is assigned the value 1
 i = 15 % 4;     // i is assigned the value 3
 i = -15 % 4;    // i is assigned the value -3

If an attempt is made to divide by 0 (using either / or %), a run-time error occurs and script execution halts.

Each of the arithmetic operators also has a corresponding assignment type operation. For example

 integer x;
 integer y;
 x += y;    // Synonymous with x = x + y;
 x -= y;    // Synonymous with x = x - y;
 x *= y;    // Synonymous with x = x * y;
 x /= y;    // Synonymous with x = x / y;

In addition, since incrementing or decrementing by 1 is quite common, is special unary operator for that. The operator is written ++ and is pronounced plus-plus. To increment the variable i by 1, we can write either ++i or i++. So for example

 integer i = 0;
 i++;     // i now has the value of 1
 ++i;     // i now has the value of 2

But the two operators are not identical, because i++ and ++i are expressions that can occur as part of a larger expression. When used as part of a larger expression, i++ contributes its value to the expression before it is incremented. For example, the fragment

 integer i = 0;
 if (i++ == 0)
    llSay( 0, "The value of i was 0 when the comparison was done" )
 else
    llSay( 0, "The value of i was 1 when the comparison was done" )

would chat "The value of i was 0 when the comparison was done" even though i ends up with the value of 1. On the other hand, if we switch i++ to ++i, e.g.:

 integer i = 0;
 if (++i == 0)
    llSay( 0, "The value of i was 0 when the comparison was done" )
 else
    llSay( 0, "The value of i was 1 when the comparison was done" )

the chat output would be "The value of i was 1 when the comparison was done".

The operator minus-minus (written --) works similarly, but by decrementing (-1) rather than incrementing (+1).

Comparison Operators

In addition to the arithmetic operators, there are also the normal integer comparison operators < (less than) and > (greater than). For "less than or equal", or "greater than or equal", there are two-character operators <= and >=. There can't be any space between the two characters of a two-character operator.

The result of a comparison operator is either 0 (representing FALSE) or 1 (representing TRUE). See Truth Values (Booleans).

Integer Overflow

  • During script execution, integers wraps from 2147483647 to -2147483648 in the normal way
  • The compiler treats integers outside the range -2147483648 to 2147483647 somewhat strangely. No compile time warning or error is generated. (If the following explanation, doesn't make sense to you don't worry -- just know to avoid using numbers outside the valid range in your script.)
    • For an integer outside the range -2147483648 to 2147483647, the absolute value of the number is reduced to fall in the range 0 to 4294967295 (0xFFFFFFFF).
    • This number is then parsed as an unsigned 32 bit integer and cast to the corresponding signed integer.
    • If the value in the script had a negative sign, the sign of the internal representation is switched.
    • The net effect is that very large positive numbers get mapped to -1 and very large negative numbers get mapped to 1.

Truth Values (Booleans)

There is not a special type for TRUE and FALSE in LSL. Instead, TRUE is defined to be the integer 1 and FALSE is defined to be the integer 0.

This has an interesting consequence in a conditional statement. Consider the following example

 integer i = 3;     // 3 is neither TRUE nor FALSE
 if (i)
    llSay( 0, "i is treated as being true." );
 else
    llSay( 0, "i is treated as being false." );
 if (i == TRUE)
    llSay( 0, "i is equal to TRUE." );
 else
    llSay( 0, "i is not equal to TRUE." );

When run, the output will be

i is treated as being true.
i is not equal to TRUE.

This is because the condition in the if statement can be any integer. Any non-zero value will cause the true block or statement to be executed, while a zero value will cause the false block or statement to be executed.

The same zero/non-zero distinction is made wherever a truth value is expected. In what follows, we'll use the word true and false to mean non-zero versus zero, while TRUE and FALSE will mean one and zero.

Truth Value Operators

There are three truth value operators in LSL:

  •  ! (representing not)
  • && (representing and)
  • || (representing or)

The ! operator takes a single operand and evaluates to TRUE if the operand is false, and FALSE otherwise. For example

 integer i;
 i = !(3 == 7);     // 3 == 7 is FALSE, so i gets the value TRUE

The && operator takes two operands and evaluates to TRUE if both its operands are true, and FALSE otherwise.

 i = (3 < 7) && (3 > 7);     // 3 < 7 is TRUE, but (3 > 7) is FALSE, so i gets the value FALSE

The || operator takes two operands and evaluates to TRUE if either one of its operands are true, and FALSE otherwise.

 i = (3 < 7) || (3 > 7);     // one of the operands (3 < 7) is TRUE, so i gets the value TRUE


Statements Requiring Truth Values

There are four statement types that require a truth value condition:

  • if
  • for
  • while
  • do-while

Enumerations

Many built-in functions have a parameter or return value that takes one of a fixed number of alternatives. For example, llAttachToAvatar has a single parameter which specifies the attachment point. The attachment point is specified to be an integer, but the specific integer corresponding to each attachment point is arbitrary. Since the numbers themselves have no significance, LSL defines names such as ATTACH_HEAD, ATTACH_LFOOT and ATTACH_BELLY, which are simply meaningful names for the arbitrary integers. Integers used in this way are called enumerations.

Generally, no operators besides the ubiquitous =, == and != are used with enumerations because there is no expected relationship between the arbitrarily selected integer values.

Bit Vectors

Bit Vector Operators

Analogous to the truth value operators, LSL defines four operators specifically for bit vectors:

  • ~ (bitwise not)
  • & (bitwise and)
  • | (bitwise or)
  • ^ (bitwise exclusive or)

In contrast to the truth value operators, these operate independently on each bit position.

The corresponding assignment operators such as |= are not supported in LSL.

Other Uses of Integers

Although the four uses described above cover all the ways that integers are used with LSL built-in functions, they are not really exhaustive of the ways integers can be used. There are algorithms in mathematics and computer science that mix arithmetic and bit vector operations, along with bit shift operators. LSL supports this kind of computation with the bit shift operators inherited from C:

  • << shift bits left
  • >> shift bits right

Contrary to previous information on this page, bit shift assignment operators, >>= and <<= are not permitted in LSL.

Discussion of these algorithms is beyond the scope of this article, but see Bit Twiddling Hacks for some examples.

Type conversions

Other types to integers

Casting a positive float to an integer has the same end effect as using the llFloor function. A negative float can produce different results from the two operations.

Integers to other types

Differences between Integers in LSL and in C

Much of LSL is patterned after the C programming language, and integers are no exception. Programmers who already know C can immediately apply most of their understanding of integers to LSL.

Differences to note are

  • The type must be spelled integer instead of int.
  • There are no size modifiers (short, long, ...). All integers are 32 bits.
  • There is no unsigned modifier. All integers are signed.
  • Comparison operators evaluate to an integer (1 or 0), as they did in C prior to C99.
  • The && and || operators are strict, i.e. both operands are always evaluated, even if the result can be determined after evaluating the left operand.

Hexadecimal Notation

There's actually not much use for hexadecimal notation in LSL. If you do feel a need to use it, you probably already know how it works. If not, you can consult Wikipedia.