Talk:Hex
91+-2 milliseconds or more
Scientifically reproducible summary measures of code space and run time now appear in the article:
347 bytes, 147+-30 milliseconds
197 bytes, 105+-7 milliseconds
202 bytes, 102+-6 milliseconds
139 bytes, 113+-7 milliseconds
More bytes, 91+-2 milliseconds
Quoting the millisecond results took more calculation than anyone has yet programmed into the Efficiency Tester.
I ran that harness 3 x 1,000 times for each version of code, then took the (min, max) pair and reported { middling = ((fastest + slowest) / 2) } with a +- imprecision of { max(middling - fastest, slowest - middling)) }.
The raw data was as follows:
[5:51] Object: 15146 free bytes of code at default.state_entry [5:53] Object: 98.496002+-FIXME milliseconds passed on average in each of [5:53] Object: 1000 trials of running the code in the loop [5:55] Object: 96.188004+-FIXME milliseconds passed on average in each of [5:55] Object: 1000 trials of running the code in the loop [5:56] Object: 106.851997+-FIXME milliseconds passed on average in each of [5:56] Object: 1000 trials of running the code in the loop [6:01] Object: 15151 free bytes of code at default.state_entry [6:03] Object: 111.475998+-FIXME milliseconds passed on average in each of [6:03] Object: 1000 trials of running the code in the loop [6:04] Object: 112.019997+-FIXME milliseconds passed on average in each of [6:04] Object: 1000 trials of running the code in the loop [6:06] Object: 98.428001+-FIXME milliseconds passed on average in each of [6:06] Object: 1000 trials of running the code in the loop [6:09] Object: 15209 free bytes of code at default.state_entry [6:11] Object: 120.155998+-FIXME milliseconds passed on average in each of [6:11] Object: 1000 trials of running the code in the loop [6:12] Object: 15209 free bytes of code at default.state_entry [6:14] Object: 115.272003+-FIXME milliseconds passed on average in each of [6:14] Object: 1000 trials of running the code in the loop [6:16] Object: 106.751999+-FIXME milliseconds passed on average in each of [6:16] Object: 1000 trials of running the code in the loop [6:18] Object: 111.919998+-FIXME milliseconds passed on average in each of [6:18] Object: 1000 trials of running the code in the loop [6:25] Object: 15001 free bytes of code at default.state_entry [6:28] Object: 176.723999+-FIXME milliseconds passed on average in each of [6:28] Object: 1000 trials of running the code in the loop [6:30] Object: 131.716003+-FIXME milliseconds passed on average in each of [6:30] Object: 1000 trials of running the code in the loop [6:32] Object: 117.820000+-FIXME milliseconds passed on average in each of [6:32] Object: 1000 trials of running the code in the loop [6:35] Object: 15204 free bytes of code at default.state_entry [6:36] Object: 89.372002+-FIXME milliseconds passed on average in each of [6:36] Object: 1000 trials of running the code in the loop [6:38] Object: 92.748001+-FIXME milliseconds passed on average in each of [6:38] Object: 1000 trials of running the code in the loop [6:40] Object: 93.180000+-FIXME milliseconds passed on average in each of [6:40] Object: 1000 trials of running the code in the loop
18 October Rewrite
So I'm baaack again, trying to fold all our talk to date into the article. I also did my best guess of how to keep the uncommented changes to the article itself.
I think I've now got the story straight on the concise, conventional, & small code. Concise & conventional I can see at a glance. Small I can easily measure with llGetFreeMemory.
I think the article may by now have a structure now that lets us briefly & clearly tell the story of the fast code also. You can see the FIXME spots where we need reproducible quoted milliseconds. I'm not sure how much +- inaccuracy we should allow for quotes of milliseconds. I'll either standby to see someone else volunteer to tell the story of the fast code, or I'll return to measure that story and tell that story myself. I see we have Code Racer and other articles available to help us call llGetTimestamp to measure run time. Looks like nobody has yet found a technique returns results much faster than like three real world minutes per trial, ouch.
I think/hope we're moving towards implementing exactly one fast hex function that implements the specification for the hex function. I don't think we need a fast implementation of the bits2nybbles function.
Have we progressed?
Will we finish soon?
- I hate this revision. It's a step backwards.
- You shouldn't use llGetTimestamp for profiling, you should be using the script time functions (llGetTime).
- I cannot replicate your bytecode cost. Since you didn't post instructions and you used llGeTimestamp I can only conclude that your measurements are entirely invalid. My steps are below:
- Compile and execute
default{state_entry(){llOwnerSay((string)llGetFreeMemory());}}
to establish a baseline - Paste an implementation at the top of script from #1, compile and run.
- Subtract the result from #2 from the result of #1; you now have the bytecode cost.
- Repeat steps #2 & #3 for each implementation.
- Compile and execute
- Here you go again about a single implementation. You may not need a fast implementation, but someone might. -- Strife Onizuka 12:42, 19 October 2007 (PDT)
- We have progressed! I hated your last revision, I saw no point to the changes. I see you now say you hate my revision. Yes please, let's talk. I'll send just this brief remark now to show my engagement, I'll return to fill in more detail as soon as I can. -- Ppaatt Lynagh 14:53, 19 October 2007 (PDT)
- I do plan to return to quote you line by line to give you answer by answer.
- Meanwhile, I hope I can help a little instantly by pointing out that the article and the talk by now (19 Oct PDT) to do answer many of these questions, e.g., Hex#Measuring_Concise_.26_Conventional_.26_Small_.26_Fast points to the Efficiency Tester to reproduce the "milliseconds of run time reported by llGetTimestamp" and briefly explains the ( insert three, delete one, delete another ) procedure to reproduce the "bytes of code reported by llGetFreeMemory" results. I'm surprised to see you ask those questions in particular, I thought I had given those answers here already as I first talked of me working to understand your last burst of changes, e.g., the difference of 4 bytes in your procedure and mine. I never did succeed in understanding any one of your last burst of changes in particular. I thought I had partly reflected the changes as a whole, I'm sorry to hear I failed so completely. I look forward to our line-by-line talk teaching me what I am not yet understanding.
- I do hope to return soon to quote you line by line to give you answer by answer. -- Ppaatt Lynagh 15:32, 19 October 2007 (PDT)
Loop Costs Unscientific
I see we were quoting loop costs of:
"2 variables, 124 bytes" = Clear & Conventional
"1 variable, 105 bytes" = Small
"0 variables, 81 bytes" = Fast
"1 variables, 105 bytes" = Different & Small - Signed Only
"0 variables, 100 bytes" = Different & Small - Signed or Unsigned
I don't know what we mean by "loop cost". I see we didn't link to a definition on how to reproduce these results. I'll strike the loop costs, pending someone making these results repeatable, thus scientific.
-- Ppaatt Lynagh 19:34, 17 October 2007 (PDT)
In the event I see I also struck a couple of other undefined terms.
We had been speaking of "executing" "operators", without a definition for "operators". We may have meant operations? Or LSL bytecodes? I substituted the word "work".
We had been speaking of "LSO". I don't know if/how "LSO byte code" differs from LSL "byte code", so I cut the English to just "bytes" and "code" and "size".
-- Ppaatt Lynagh 22:18, 17 October 2007 (PDT)
- <rant>Unscientific? Maybe you should try to understand the science before you call it unscientific. The Loop Cost is exactly what it sounds like, the cost in bytes of each iteration of the loop. If you had any understanding of LSO this would be obvious but you don't even know what LSO is. It would be remiss not to mention the the variable cost as it is important when it comes to size and performance, but that is beyond you. I could spend a long time answering your questions but there is a more authoritative source... the compiler source code.</rant>
- "operations" would have been a better word there but "operators" is valid (just a bit awkward). "work" should not be used, it is vague.
- There are a few ways of calculating the loop cost.
- A) compile the compiler as a stand alone application.
- B) hack the client cache to extract compiled scripts
- C) have a perfect understanding of how the compiler works and of LSO. If you have a good understanding of the compiler you can manually count the cost and you can design a framework for checking those numbers (you have to account for the number of variables lest the numbers be off). I tend to just add things up but for the information you butchered, I did in fact verify them.
- --Strife Onizuka 12:18, 19 October 2007 (PDT)
- Which procedure do you intend for us to publish together with your results, to allow the scientific audience to most inexpensively repeat your experiment? -- Ppaatt Lynagh 15:34, 19 October 2007 (PDT)
- Rants are not useful, so far as I know. I don't mean to be rejecting an effort by you to grow our cooperative community, I just don't know how to engage usefully with a rant. Engaging a rant is like feeding a troll, so far as I know. -- Ppaatt Lynagh 15:34, 19 October 2007 (PDT)
Neutral Point Of View
I notice I continue to feel delighted by the way our community interacting together makes the point of view we publish ever more neutral.
You Deleting My Work, Me Deleting Your Work
I wonder if I can help by mentioning the two guides toward a neutral point of view that I am myself working to hold in mind as I play here:
1. I think the essence of any wikipedia is the astonishing idea that people can end up working together more when all together we agree "if you don't want your writing to be edited mercilessly and redistributed at will, then don't submit it here", as our edit page warns us.
2. I think the perspectives we represent run across the range of perspectives balanced at http://en.wikipedia.org/wiki/Optimization_(computer_science)#When_to_optimize. Some of us naturally care most about clear and conventional code, some of us care most about small code, some of us care most about fast code. That's great balance.
-- Ppaatt Lynagh ~16 October 2007 (PDT)
Why bother with fast or small or different code exemplars
Kuhn defines an exemplar as a solution paired with a problem to teach the new people how to solve problems (at least, that's my paraphrase of http://en.wikipedia.org/wiki/Exemplar).
Me, I launched this hex page on 8 October 2007, foolishly thinking I was writing out an obvious and adequate exemplar. Me, I thought I was just sharing the trivial work of me the LSL newbie getting the hex out to make some permission masks intelligible, in contrast with how confused the masks look in decimal. I thought I was just saving the next newbie some effort in working out the details.
I didn't think much about whether the masks were signed or unsigned. LSL permission masks only take on values that can be seen as positive or unsigned. LSL permission masks never set the most significant unsigned bit which is the sign bit of a signed two's-complement integer.
The creative tension that we subsequently worked thru then taught me much.
I now know that I initially saw value only in clear & conventional code examplars. In effect, I saw this wiki only teaching LSL to newbies like me.
I now guess this wiki has a wider purpose. Sure, this wiki teaches LSL to newbies, but this wiki also gives experts a place to share between themselves exemplars of making code fast or small, including exemplars of respecifying code to make the code faster or smaller even at the extreme cost of making the code less clear & conventional, thus harder to call and reuse and read.
As yet I still don't yet understand the burst of changes ff. 14:59, 14 October 2007 ...
... but at least we now have found a perspective from which I can hope to understand those changes.
-- Ppaatt Lynagh 19:24, 17 October 2007 (PDT)
Due Diligence
Part of the difference between us is that my history of pain tells me it is irresponsible to claim "substantial" differences in how fast or small we made code, at the expense of the to-me-most-essential "correct at a glance" quality, without quoting reproducible numbers. When we don't publish a reproducible experimental setup, we're trading opinion, not science, hardly a worthwhile trade. When we mean to contribute the half-an-edit that is just the opinion to invite the community to finish our work by adding the science, then I think we should include an explicit link over here to this Talk:Hex tab. I see with surprise that Strife chose to delete my explicit invitations for the community to complete our unsubstantiated fast & small claims. -- Ppaatt Lynagh 09:16, 14 October 2007 (PDT)
- [... snipped ...] I'll qualify that with numbers when I next log in. I'll write an article on profiling functions and we can link to it. I believe the Readability version uses about 150% to 200% the bytecode of the other versions; it's really chunky (I'm not keen on counting the bytes in my head atm). Linking to the talk page for every implementation is a bit overkill, having a link at the end of the header paragraph would be ok. -- Strife Onizuka 09:51, 14 October 2007 (PDT)
- a) I see numbers! Thank you!! I look forward to learning how to reproduce your results. Hints welcome! Without hints, I'll be exploring llGetFreeMemory. I guess I can measure that, add code, measure that again, and call the diff the LSO size. How to measure time I have no memory of a clue, but I think I've found hints inside this wiki.secondlife.com, I will google ... ah, likely I was remembering the llGetTimestamp example found at Efficiency Tester and then explored in more depth at LSL_Script_Efficiency. I grumble to see us counting time progressing in the real world as a measure of speed even we share the servers and clients out among who knows how much code, I guess like many benchmarks the results will still be useful in comparison with one another ...
- b) http://en.wikipedia.org/wiki/Atm decodes ATM to At The Moment, I guess that's what we mean.
- c) I don't immediately understand "loop cost". My own guess of fastest would be to unroll the loop: 32-bit ints never contain more than 8 nybbles.
- d) To reproduce the "LSO Size" results I figure I'll add more than one copy of the functions into a script, negligibly changing the spelling but never the lengths of the names (e.g., by ending the global constant and function names with a digit chosen from "0123456789"). llGetFreeMemory should then report me eating away perfectly consistent byte counts of code space every time I add a copy of the function. Once I have multiple copies, I can begin to show whether calling the function makes a difference in how much code space it eats.
- I don't always exactly reproduce the article's new claim of "LSO Size" of 351 for the Correct At A Glance code. I count 347 bytes disappearing when I edit the 2 or 3 version out of the following 1 2 3 copy. I count 14983 bytes free with the code as shown, rising by 347 to 15330 when I delete copy 3, rising by 347 to 15677 when I delete copy 2. I do see a difference of 351 if I delete the last copy. I see 15821 bytes free with one copy and no calls, rising by 351 to 16172 if I delete the last copy.
- I don't yet understand how the first copy occupies 351 bytes and subsequent copies occupy 347 bytes. Do you?
- Ah another clue. I see deleting even the first copy frees 347 bytes, not 351 bytes, when I add the first copy to some other code, such as moving by 347 between 16045 and 15698 free by adding/ deleting copy 1 to a script such as:
- string callable(integer passed)
- {
- return (string) passed;
- }
- default
- {
- state_entry()
- {
- llOwnerSay((string) llGetFreeMemory());
- llOwnerSay(callable(-1));
- llOwnerSay(callable(-1));
- }
- }
- string callable(integer passed)
- And yes consistently now, all of the five llGetFreeMemory LSO sizes reported in the article as 351 341 254 201 204 I now reproduce offset by four -- I see 348 337 250 197 200.
- I still vote for shrinking the article to show just most Correct At A Glance, most Fast, and most Small. -- Ppaatt Lynagh 21:41, 15 October 2007 (PDT)
// http://wiki.secondlife.com/wiki/hex string XDIGITS1 = "0123456789abcdef"; // could be "0123456789ABCDEF" string bits2nybbles1(integer bits) { string nybbles = ""; while (bits) { integer lsbs = bits & 0xF; string nybble = llGetSubString(XDIGITS1, 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 hex1(integer value) { if (value < 0) { return "-0x" + bits2nybbles1(-value); } else if (value == 0) { return "0x0"; // bits2nybbles(value) == "" when (value == 0) } else // if (value > 0) { return "0x" + bits2nybbles1(value); } } string XDIGITS2 = "0123456789abcdef"; // could be "0123456789ABCDEF" string bits2nybbles2(integer bits) { string nybbles = ""; while (bits) { integer lsbs = bits & 0xF; string nybble = llGetSubString(XDIGITS1, 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 hex2(integer value) { if (value < 0) { return "-0x" + bits2nybbles2(-value); } else if (value == 0) { return "0x0"; // bits2nybbles(value) == "" when (value == 0) } else // if (value > 0) { return "0x" + bits2nybbles2(value); } } string XDIGITS3 = "0123456789abcdef"; // could be "0123456789ABCDEF" string bits2nybbles3(integer bits) { string nybbles = ""; while (bits) { integer lsbs = bits & 0xF; string nybble = llGetSubString(XDIGITS3, 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 hex3(integer value) { if (value < 0) { return "-0x" + bits2nybbles3(-value); } else if (value == 0) { return "0x0"; // bits2nybbles(value) == "" when (value == 0) } else // if (value > 0) { return "0x" + bits2nybbles3(value); } } default { state_entry() { llOwnerSay((string) llGetFreeMemory()); llOwnerSay(hex1(-1)); llOwnerSay(hex1(-1)); llOwnerSay(hex1(-1)); } }
Correct At A Glance
Strife,
I see you say "your opinions have helped clarify and shape my own opinions". Your talk has had the same effect on my talk. Thank you, for me that's great fun.
I do find marketing, journalism, popular science, etc. to be useful & worthwhile human activities with relevance to the community effort of making wikipedias maximally encyclopaedic, yes. So far as I know, that bias of mine is a difference between us.
I see you say "the article" "lacked" "a neutral point of view". I hope you know I emphatically agree. I hope you know I could not see this truth until after you pointed this truth out. For example, I did not understand the truth that "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" until after you explained. You explained that for you the implementations tuned to the point of not being correct at a glance were, for you, still easy to call. I see that now, but I didn't see that until after you showed me.
I agree that encyclopaedias should substitute a generic phrase in place of an equivalent trademarked phrase. I think "correct at a glance" is not a trademarked phrase. I think "correct at a glance" has a Google history of being used ~14,000 times or more, and says significantly more than "readable". I watched with interest as you pushing against me taught me to fill out the else clauses of the if-else-if of the hex routine, rather than letting hex shortcut them. I watched with interest as you pushing against me taught me to find my way to bits2nybbles as the least work core of this, rather than hexu. These are the experiences that taught me my bias is "correct at a glance", when contrasted with your "fast" and "small" bias. Over in User:Ppaatt_Lynagh I long ago said "Thanks to Strife Onizuka for helping to verbalise ... the "correct at a glance" distinctive of separateWords, etc."
I see you say 'if you do a Google search for '"Correct At A Glance"' my userpage comes up as hit #2'. I'm unable to reproduce this result? I checked the first few of the ~14,000 hits of http://www.google.com/search?q=%22correct+at+a+glance%22 and I checked the first few of the ~12,000,000 hits of http://www.google.com/search?q=correct+at+a+glance. Please can you describe your experiment in more detail? I agree my pro bono work to date has given me an unfair share of Google attention, and therefore gives my favourite catchphrases unusually many hits.
-- Ppaatt Lynagh 09:03, 14 October 2007 (PDT)
- I was wondering if those other hits were you (but decided it would be too much like stalking to ask). I didn't think it was a TM or it would have come up as one... just sounded like it should be one. It's probably google learning that I do a lot of SL related searches and elevating those. screen-shot. I'd like to say the reason I didn't give reasons before was that I didn't have anything nice to say but really I'm just not in the habit of writing explanations. I feel I was a bit harsh with you. -- Strife Onizuka 09:33, 14 October 2007 (PDT)
- Now that we've discarded the ad hominem idea that any of us here hold the "Correct At A Glance" trademark ... we can return from a more neutral point of view to the issue.
- Q: Is that phrase the best choice of words to communicate that meaning?
- A: Maybe not, it's awfully long.
- How about we talk of "clear", "small", and "fast", as the qualities we desire to find in politely concise code examples? -- Ppaatt Lynagh 16:24, 16 October 2007 (PDT)
Talk:Hex Archives
See http://wiki.secondlife.com/w/index.php?title=Talk:Hex&oldid=35999 to read back into the history of four topics:
3 Principle Of Least Astonishment
5 Second Talk
6 First Talk
7 Our Growing Consensus
Note: Our talk did link with http://en.wikipedia.org/wiki/Principle_of_least_astonishment