Difference between revisions of "Hex"

From Second Life Wiki
Jump to navigation Jump to search
(claim easy to call for all understood implementations, present fast vs. small neutrally, don't claim our inability to max all qualities is inescapable)
Line 23: Line 23:
== Implementations ==
== Implementations ==
<div style="padding: 0.5em;">
<div style="padding: 0.5em;">
=== Why Multiple Implementations ===
We present one implementation after another, each tuned to maximize a different quality, at the expense of other qualities.


LSL programmers have different priorities when writing code, these priorities are typically characterized as schools of thought. Depending upon the situation one priority may trump another. There are four principal priorities in LSL in contention with each other. They are: '''Design Conformance''', '''Readability''', '''Speed''' and '''Size'''. Rarely is it possible to optimize code for all four.  
We find the first few implementations equally easy to call, because we have studied all those implementations enough to believe each actually does produce exactly the same output for any input.


=== Design Conformance & Readability ===
=== Correct At A Glance ===


You should find this implementation feels easy to call and modify and review. For example, you could substitute the easy-to-read upper case A B C D E F nybbles of IBM style for the easy-to-type lower case a b c d e f nybbles of AT&T style. Please consider sharing your experience in the [[Talk:Hex|discussion]] tab.
You should feel this code is easy to review and call and modify. For example, in a glance you should see that this code conforms to our specification and you should also see how to substitute the easy-to-read upper case A B C D E F nybbles of IBM style for the easy-to-type lower case a b c d e f nybbles of AT&T style. Please consider sharing your experience in the [[Talk:Hex|discussion]] tab.


<pre>
<pre>
Line 67: Line 67:
</pre>
</pre>


=== Design Conformance & Speed ===
=== Fast ===


You should agree this implementation feels like it could run fast in 2007 SL before Mono. Please consider contributing measures of how much faster/ smaller this code is to the [[Talk:Hex|discussion]] tab.
You should feel this code would run fast in 2007 SL before Mono and you should also feel that naive compilation of this code would produce more bytecode than naive compilation of our small implementation below. Please consider contributing measures of how much faster/ bigger this code is to the [[Talk:Hex|discussion]] tab.


<pre>
<pre>
Line 97: Line 97:
</pre>
</pre>


=== Design Conformance & Size ===
=== Small ===


Re-optimized version of Speed code for Size. Not as fast on the loop but less bytecode.
You should feel this code would run small in 2007 SL before Mono and you should also feel that naive compilation of this code would produce slower bytecode than naive compilation of our fast implementation above. Please consider contributing measures of how much smaller/ slower this code is to the [[Talk:Hex|discussion]] tab.


<pre>
<pre>
Line 123: Line 123:
</pre>
</pre>


=== Size ===
=== Different ===


Reworked design to allow for more size optimization. There is only a benefit if the function is called from no more then 8 places in the script.
You should notice that 2007 SL before Mono can construct other kinds of hex more efficiently. Please consider contributing here an example or summary of how the example code here differs from our specification. Please consider contributing here what you discover of how this code differs measurably from our other code when this code is called between 0 and 7 times in the script.


<pre>
<pre>

Revision as of 07:07, 13 October 2007

Function: string hex(integer value);

Returns the hexadecimal nybbles of the signed integer value in order. Specifically returns the nybbles from most to least significant, starting with the first nonzero nybble, folding every nybble to lower case, and beginning with the nonnegative prefix "0x" or the negative prefix "-0x".

Parameters:

• integer value signed value to be expressed as signed hex

Note: Results with eight nybbles begin always with one of the positive signed nybbles 1 2 3 4 5 6 7, never with a zero or unsigned nybble 0 8 9 A B C D E F.

Caution: This page was a work in progress as of 2007-10. The specification, the implementations, the demo, and the sample results may not yet be totally consistent. See the discussion tab.

Implementations

We present one implementation after another, each tuned to maximize a different quality, at the expense of other qualities.

We find the first few implementations equally easy to call, because we have studied all those implementations enough to believe each actually does produce exactly the same output for any input.

Correct At A Glance

You should feel this code is easy to review and call and modify. For example, in a glance you should see that this code conforms to our specification and you should also see how to substitute the easy-to-read upper case A B C D E F nybbles of IBM style for the easy-to-type lower case a b c d e f nybbles of AT&T style. Please consider sharing your experience in the discussion tab.

// http://wiki.secondlife.com/wiki/hex

string XDIGITS = "0123456789abcdef"; // could be "0123456789ABCDEF"

string bits2nybbles(integer bits)
{
    string nybbles = "";
    while (bits)
    {
        integer lsbs = bits & 0xF;
        string nybble = llGetSubString(XDIGITS, lsbs, lsbs);
        nybbles = nybble + nybbles;
        bits = bits >> 4; // discard the least significant bits at right
        bits = bits & 0xfffFFFF; // discard the sign bits at left
    }
    return nybbles;
}

string hex(integer value)
{
    if (value < 0)
    {
        return "-0x" + bits2nybbles(-value);
    }
    else if (value == 0)
    {
        return "0x0"; // bits2nybbles(value) == "" when (value == 0)
    }
    else // if (0 < value)
    {
        return "0x" + bits2nybbles(value);
    }
}

Fast

You should feel this code would run fast in 2007 SL before Mono and you should also feel that naive compilation of this code would produce more bytecode than naive compilation of our small implementation below. Please consider contributing measures of how much faster/ bigger this code is to the discussion tab.

// http://wiki.secondlife.com/wiki/hex

string XDIGITS = "0123456789abcdef"; // could be "0123456789ABCDEF"

string hexu(integer bits)
{
    integer index = (bits & 0xF);
    string nybbles = llGetSubString(XDIGITS, index, index);
    if ((bits = (0xfffFFFF & (bits >> 4))))
    {
        do
        {
            nybbles = llGetSubString(XDIGITS, index = (bits & 0xF), index) + nybbles;
        } while ((bits = (bits >> 4)));
    }
    return "0x" + nybbles;
}

string hex(integer value)
{
    if (value < 0) return "-" + hexu(-value);
    return hexu(value);
}

Small

You should feel this code would run small in 2007 SL before Mono and you should also feel that naive compilation of this code would produce slower bytecode than naive compilation of our fast implementation above. Please consider contributing measures of how much smaller/ slower this code is to the discussion tab.

// http://wiki.secondlife.com/wiki/hex

string hexu(integer bits)
{
    string nybbles = "";
    do
    {
        integer index = bits & 0xF;
        nybbles = llGetSubString("0123456789abcdef", index, index) + nybbles;
    } while ((bits = (0xfffFFFF & (bits >> 4))));
    return "0x" + nybbles;
}

string hex(integer value)
{
    //saves one byte over "value < 0" and is faster.
    if (value & 0x80000000) return "-" + hexu(-value);
    return hexu(value);
}

Different

You should notice that 2007 SL before Mono can construct other kinds of hex more efficiently. Please consider contributing here an example or summary of how the example code here differs from our specification. Please consider contributing here what you discover of how this code differs measurably from our other code when this code is called between 0 and 7 times in the script.

// http://wiki.secondlife.com/wiki/hex

string hex(integer value, integer signed)
{
    //saves one byte over "value < 0" and is faster.
	string lead = "0x";
    if ((value & 0x80000000) && signed)
    {
        lead = "-0x";
        value = -value;
    }
    string nybbles = "";
    do
    {
        integer index = value & 0xF;
        nybbles = llGetSubString("0123456789abcdef", index, index) + nybbles;
    } while ((value = (0xfffFFFF & (value >> 4))));
    return lead + nybbles;
}

Demo

Show the most astonishing test cases for the hex function and then also the permission masks of the script running to demo the hex function.

Code:

default
{
    state_entry()
    {
        llOwnerSay("Hello");
        llOwnerSay(hex(0) + " == 0");
        llOwnerSay(hex(0x00FEDC00 & -0x00FEDC00) + " == (0x00FEDC00 & -0x00FEDC00)");
        llOwnerSay(hex(1 << 30) + " == (1 << 30)");
        llOwnerSay(hex(0x80000000) + " == 0x80000000");
        llOwnerSay(hex(0xFEDC9876) + " == 0xFEDC9876");
        llOwnerSay(hex(-1) + " == -1");
        llOwnerSay(hex(0x123456789) + " == 0x123456789");
        llOwnerSay("OK");
        
        llOwnerSay("Hello again");
        string item = llGetScriptName();
        llOwnerSay(hex(llGetInventoryPermMask(item, MASK_BASE)) + " as base");
        llOwnerSay(hex(llGetInventoryPermMask(item, MASK_OWNER)) + " by owner");
        llOwnerSay(hex(llGetInventoryPermMask(item, MASK_GROUP)) + " by group");
        llOwnerSay(hex(llGetInventoryPermMask(item, MASK_EVERYONE)) + " by anyone");
        llOwnerSay(hex(llGetInventoryPermMask(item, MASK_NEXT)) + " by next owner");
        llOwnerSay("aka " + (string) llGetInventoryPermMask(item, MASK_NEXT));
        llOwnerSay("OK");
    }
}

Sample Results:

Hello
0x0 == 0
0x400 == (0x00FEDC00 & -0x00FEDC00)
0x40000000 == (1 << 30)
-0x80000000 == 0x80000000
-0x123678a == 0xFEDC9876
-0x1 == -1
-0x1 == 0x123456789
OK
Hello again
0x7fffffff as base
0x7fffffff by owner
0x0 by group
0x0 by anyone
0x82000 by next owner
aka 532480
OK

Design Rationale

Why These Implementations

These implementations reproduce how hex integer literals often appear in LSL script, conforming to such arbitrary and traditional AT&T C conventions as:

  1. return lower case a b c d e f rather than upper case A B C D E F,
  2. return a signed 31-bit result if negative, rather than an unsigned 32-bit result,
  3. omit the leading quads of zeroed bits, except returns "0x0" rather than "0x" when the result is zero,
  4. return a meaningless "0" before the "x", as LSL and C compilers require,
  5. return the "x" on the left as in LSL and C, not the "h" on the right as in Assembly code, and
  6. return the nybbles listed from most to least significant as in English, not listed from least to most significant as in Arabic.

Why Python Hex Relevant

Our implementations produce exactly the same results as the hex function of the Python scripting language.

Brief doc for the Python hex function appears buried deep within http://docs.python.org/lib/built-in-funcs.html

Disputes over the detailed specification of the Python hex function appear buried deep within http://www.python.org/dev/peps/pep-0237/