Difference between revisions of "Hex"

From Second Life Wiki
Jump to navigation Jump to search
m (→‎Design Rationale: restore some text lost without comment in the last couple of bursts of editing)
m (<lsl> tag to <source>)
 
(54 intermediate revisions by 4 users not shown)
Line 1: Line 1:
{{LSL Header}}__NOTOC__
{{LSL Header}}
 
__TOC__


<div id="box">
<div id="box">
{{#vardefine:p_value_desc|signed value to be expressed as signed hex}}
{{#vardefine:p_value_desc|signed value to be expressed as negative or nonnegative hex}}
== Function: [[string]] hex([[integer]] {{LSL Param|value}}); ==
== Function: [[string]] hex([[integer]] {{LSL Param|value}}); ==
<div style="padding: 0.5em;">
<div style="padding: 0.5em;">
Line 13: Line 15:
|}
|}


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.
Note: Always begins any result of eight nybbles 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, except for the boundary test case of the most negative integer "-0x80000000".
 
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 [[Talk:Hex|discussion]] tab.
</div>
</div>
</div>
</div>
Line 21: Line 21:
<div id="box">
<div id="box">


== Implementations ==
== Code ==
<div style="padding: 0.5em;">
<div style="padding: 0.5em;">
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 ===
The brief, clear, conventional code here implements this specification exactly.


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.
The [[Efficient Hex]] article presents an alternative approach: clever, small, and fast code to implement the same specification and related specifications, and also links to instruments that measure small and fast.


<pre>
<source lang="lsl2">
// http://wiki.secondlife.com/wiki/hex
// http://wiki.secondlife.com/wiki/hex


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


string bits2nybbles(integer bits)
string hexes(integer bits)
{
{
     string nybbles = "";
     string nybbles = "";
     while (bits)
     while (bits)
     {
     {
         integer lsbs = bits & 0xF;
         integer lsn = bits & 0xF; // least significant nybble
         string nybble = llGetSubString(XDIGITS, lsbs, lsbs);
         string nybble = llGetSubString(XDIGITS, lsn, lsn);
         nybbles = nybble + nybbles;
         nybbles = nybble + nybbles;
         bits = bits >> 4; // discard the least significant bits at right
         bits = bits >> 4; // discard the least significant bits at right
Line 54: Line 51:
     if (value < 0)
     if (value < 0)
     {
     {
         return "-0x" + bits2nybbles(-value);
         return "-0x" + hexes(-value);
     }
     }
     else if (value == 0)
     else if (value == 0)
     {
     {
         return "0x0"; // bits2nybbles(value) == "" when (value == 0)
         return "0x0"; // hexes(value) == "" when (value == 0)
     }
     }
     else // if (0 < value)
     else // if (0 < value)
     {
     {
         return "0x" + bits2nybbles(value);
         return "0x" + hexes(value);
     }
     }
}
}
</pre>
</source>


=== Fast ===
</div>
</div>


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.
<div id="box">


<pre>
== Demo Results ==
// http://wiki.secondlife.com/wiki/hex
<div style="padding: 0.5em;">
 
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);
}
</pre>


=== Small ===
Running the demo should produce exactly these results:
 
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>
// http://wiki.secondlife.com/wiki/hex
Hello
 
0x0 == 0
string hexu(integer bits)
0x400 == (0x00FEDC00 & -0x00FEDC00)
{
0x40000000 == (1 << 30)
    string nybbles = "";
-0x80000000 == 0x80000000
    do
-0x123678a == 0xFEDC9876
    {
-0x1 == -1
        integer index = bits & 0xF;
-0x1 == 0x123456789
        nybbles = llGetSubString("0123456789abcdef", index, index) + nybbles;
OK
    } while ((bits = (0xfffFFFF & (bits >> 4))));
Hello again
    return "0x" + nybbles;
0x7fffffff as base
}
0x7fffffff by owner
 
0x0 by group
string hex(integer value)
0x0 by anyone
{
0x82000 by next owner
    //saves one byte over "value < 0" and is faster.
aka 532480
    if (value & 0x80000000) return "-" + hexu(-value);
OK
    return hexu(value);
}
</pre>
 
=== 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.
 
<pre>
// 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;
}
</pre>
</pre>


Line 157: Line 102:
<div style="padding: 0.5em;">
<div style="padding: 0.5em;">


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.
To reproduce exactly the expected demo results above, run the demo code below.


Code:
We chose test cases that astonish people new to hex and test cases that astonish people new to LSL permission masks.
<pre>
 
You'll get the permission mask results we show if you create a New Script to run this demo in. If instead you try modifying some old script to run this demo, then you might have to edit its permission masks to get the demo results that we show here.
 
<source lang="lsl2">
default
default
{
{
Line 186: Line 134:
     }
     }
}
}
</pre>
</source>
 
Sample Results:
<pre>
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
</pre>


</div>
</div>
Line 214: Line 141:
<div id="box">
<div id="box">


== Design Rationale ==
== Specification ==
<div style="padding: 0.5em">
<div style="padding: 0.5em;">


The first few implementations we present do conform to our specification.
We chose requirements that astonish people who usually write clever, small, or fast code by taking as precedent a specification from the far off world of people who usually write brief, clear, and conventional code.


Our specification requires exactly the same results as the hex function of the Python scripting language.
We require exactly the same results as the hex function of the popular Python scripting language. We thus reproduce how hex integer literals often appear in LSL script, conforming to such arbitrary and traditional AT&T C conventions as:
 
This specification reproduces how hex integer literals often appear in LSL script, conforming to such arbitrary and traditional AT&T C conventions as:


# return lower case a b c d e f rather than upper case A B C D E F,
# return lower case a b c d e f rather than upper case A B C D E F,
# return a signed 31-bit result if negative, rather than an unsigned 32-bit result,
# return a signed 31-bit result if negative, rather than an unsigned 32-bit result,
# omit the leading quads of zeroed bits, except returns "0x0" rather than "0x" when the result is zero,
# omit the leading zeroed nybbles, except return "0x0" rather than "0x" when the result is zero,
# return a meaningless "0" before the "x",  as LSL and C compilers require,
# return a meaningless "0" before the "x",  as LSL and C compilers require,
# return the "x" on the left as in LSL and C, not the "h" on the right as in Assembly code, and
# return the "x" on the left as in LSL and C, not the "h" on the right as in Assembly code, and
Line 234: Line 159:
Disputes over the detailed specification of the Python hex function appear buried deep within http://www.python.org/dev/peps/pep-0237/
Disputes over the detailed specification of the Python hex function appear buried deep within http://www.python.org/dev/peps/pep-0237/


As you read this page, you have to wade thru more than one implementation only because not all our community yet agrees that the only code you wish to see is the code that I like.
</div>
</div>
</div>
</div>
Line 241: Line 165:


== See Also ==
== See Also ==
<div style="padding: 0.5em">
<div style="padding: 0.5em;">
 
'''Articles'''
* [[Efficient Hex]]


'''Functions'''
'''Functions'''
Line 247: Line 174:
* [[llGetObjectPermMask]]
* [[llGetObjectPermMask]]
* [[llIntegerToBase64]]
* [[llIntegerToBase64]]
* [[llBase64ToInteger]]
 
* [[llMessageLinked]]
'''Wikipedia'''
* [[llList2Integer]]
* {{Wikipedia|Exemplar}}
* [[llList2String]]
* {{Wikipedia|Principle_of_least_astonishment}}


</div>
</div>

Latest revision as of 14:14, 24 January 2015

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 negative or nonnegative hex

Note: Always begins any result of eight nybbles 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, except for the boundary test case of the most negative integer "-0x80000000".

Code

The brief, clear, conventional code here implements this specification exactly.

The Efficient Hex article presents an alternative approach: clever, small, and fast code to implement the same specification and related specifications, and also links to instruments that measure small and fast.

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

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

string hexes(integer bits)
{
    string nybbles = "";
    while (bits)
    {
        integer lsn = bits & 0xF; // least significant nybble
        string nybble = llGetSubString(XDIGITS, lsn, lsn);
        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" + hexes(-value);
    }
    else if (value == 0)
    {
        return "0x0"; // hexes(value) == "" when (value == 0)
    }
    else // if (0 < value)
    {
        return "0x" + hexes(value);
    }
}

Demo Results

Running the demo should produce exactly these 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

Demo

To reproduce exactly the expected demo results above, run the demo code below.

We chose test cases that astonish people new to hex and test cases that astonish people new to LSL permission masks.

You'll get the permission mask results we show if you create a New Script to run this demo in. If instead you try modifying some old script to run this demo, then you might have to edit its permission masks to get the demo results that we show here.

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

Specification

We chose requirements that astonish people who usually write clever, small, or fast code by taking as precedent a specification from the far off world of people who usually write brief, clear, and conventional code.

We require exactly the same results as the hex function of the popular Python scripting language. We thus 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 zeroed nybbles, except return "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.

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/