|
Best ones?
Last post 05-26-2007 5:55 PM by asuffield. 57 replies.
-
05-17-2007 5:27 AM
|
|
-
Massimo


- Joined on 04-25-2007
- Posts 84
|
I've seen lots of wonderful and/or horrible things here, both on the main site and in this contest, and I think WTFs can be divided in two main categories, at least when talink about code: things that are just so utterly complicated and/or convoluted they could easily win an Obfuscated <Put Your Language Here> Contest, and things that are just simple, neat, to the point, and leave you screaming in horror and wanting to use some really heavy and/or really sharp tool on the programmer who created them.
I personally prefer the latter ones, and all my entries follow this pattern; I think a Real WTF(TM) should slam you in the face with the uttermost violence, instead of making you look, search and try to understand what at all is it all about. Also, simple (but powerful) WTFs have two added benefits: they can easily be understood by someone who doesn't even know the language they're written in, and they can be quickly shared with your friends; something like "hey, this guy's deleting an object from inside it, WTF?!?" or in "patching in-memory ASM code at runtime, now *that*'s crazy!", or even "wow, the calculator is executed on a network server to which the GUI connects and submits operations using XML, what had the programmer smoked?"; as opposed to "what the heck's going on in this 500-lines function who returns the sum of two numbers? Let's see... oh, that's a bitshift... ok, recursion... damn, what was that variable for? Argh, headache!".
What do you think about this? :-)
|
|
-
-
Einsidler


- Joined on 11-15-2006
- Posts 99
|
I went for sort-of a WTF onion approach. Many layers of WTFs. From the basic concept of the methods and the way they are written though to the final compiled program that does weird things that even a novice user would be annoyed or amused by.
Download my OMGWTF entry, Romanorum Computus
|
|
-
-
wacco


- Joined on 05-13-2007
- Posts 11
|
I went for the very clear approach, by putting the data in so many different data structures (which could've been all used for calculating the end result, but aren't) for all kinds of different intermediate checks (A complete binary tree for getting the entered equasion from infix to postfix, but not using said binary tree to simply calculate the result for example). So yeah, it's all very readable, but definately WTFy. I don't like the IOCCC entries here at all, the rules clearly states that " I’ve decided to exclude Ugly Code as an option altogether. In other words, entries for this contest will need to focus on clean and human-readable code that is, first and foremost, Clever and, if desired, Buggy.". Which makes those gigantic "I don't use the / operator" functions really missing the point of the competition, if I read the rules correctly.
On a slightly related note, a friend of mine just pointed at some serious bugs in my code which I didn't see until a minute ago. Unintentional bugs in an intentionally WTF program are ehm, somewhat embarrasing. Or bonuspoints. Idunno, just don't try calculating things like 90 - 9 / 9, the precedence of / over - makes it swap the values, causing 9 / 9 - 90, or -89 as a result.
|
|
-
-
burntfuse


- Joined on 05-16-2007
- Posts 133
|
or even "wow, the calculator is executed on a network server to which
the GUI connects and submits operations using XML, what had the
programmer smoked?"
How did you see my entry? ;-)
But yeah, I prefer the second type too, although throwing in some memory leaks, random crashes, and really bad error checking is always fun.
|
|
-
-
Massimo


- Joined on 04-25-2007
- Posts 84
|
burntfuse:or even "wow, the calculator is executed on a network server to which the GUI connects and submits operations using XML, what had the programmer smoked?"
How did you see my entry? ;-)
I had the same idea, and I would indeed have used it if the contest was .NET based... but I just hate C-based Win32 APIs.
But yeah, I prefer the second type too, although throwing in some memory leaks, random crashes, and really bad error checking is always fun.
My fist entry shouts something along the lines of "you're not allowed to do this!" if you try to use decimal or negative numbers... it's just too much pain to handle those when your calculator is based on manipulating strings.
|
|
-
-
macavenger


- Joined on 05-15-2007
- Fairbanks, AK
- Posts 7
|
Massimo:My first entry shouts something along the lines of "you're not allowed to do this!" if you try to use decimal or negative numbers... it's just too much pain to handle those when your calculator is based on manipulating strings.
Tell me about it...I never realized just how hard subtraction actually is until I tried to break it down to work on strings, character-by-character. In my code, I managed to eliminate ints entierly... makes for some fun lines like char buffer[`~']; :p
Aluminum iMac 20" C2D 2.4 GHz/300 GB/3 GB
|
|
-
-
TheFeshy


- Joined on 05-04-2007
- Posts 12
|
My fist entry shouts something along the lines of "you're not allowed
to do this!" if you try to use decimal or negative numbers... it's
just too much pain to handle those when your calculator is based on
manipulating strings.
I handled them easily. I just pass the number through the string-to-float and float-to-string functions I wrote (which did about 30 times more calculations than the calculator itself) until I've got numbers I can work with. Basically, I just ignored problem characters. 0.6 * 5 = 30. Negative numbers work for addition. For multiplication, though... well... an hour wasn't enough for it to complete on a Core 2 Duo system. Oh, when you said "handle" them you meant handle them correctly. My bad.
|
|
-
-
Massimo


- Joined on 04-25-2007
- Posts 84
|
macavenger:Tell me about it...I never realized just how hard subtraction actually is until I tried to break it down to work on strings, character-by-character.
This is mine:
char* DoSub(char* op1,char* op2) { static char result[256]; // Return zero if operands are the same if(IsGreater(op1,op2) == Undefined) return(zero);
char buf1[256]; char buf2[256]; // Prepare buffers // Can't trust memset() here for(int i = 0;i < 256;i++) { buf1[i] = '0'; buf2[i] = '0'; } // Copy operands in buffers with right alignment for(int x = strlen(op1),y = 255;x >= 0;x--,y--) buf1[y] = op1[x]; for(int x = strlen(op2),y = 255;x >= 0;x--,y--) buf2[y] = op2[x]; //Find greater operand char *greater = NULL; char *lesser = NULL; if(IsGreater(op1,op2) == True) { greater = buf1; lesser = buf2; } else { greater = buf2; lesser = buf1; } // Prepare result result[255] = '\0'; int borrow = 0; // Will be used to handle borrow
// Standard right-to-left, subtract-with-borrow algorithm for(int i = 254;i >= 0;i--) { int c1 = (int) (greater[i] - '0'); int c2 = (int) (lesser[i] - '0');
int r = c1 - c2 - borrow;
if(r >= 0) { result[i] = ((char) r) + '0'; borrow = 0; } else { result[i] = ((char) r + 10) + '0'; borrow = 1; } } // Insert leading minus sign if needed if(IsGreater(op2,op1) == True) { int i = 0;
while(result[i] == '0') i++; result[i - 1] = '-'; }
// Remove leading zeroes while(result[0] == '0') { for(int i = 0;i < 255;i++) result[i] = result[i + 1]; }
// Return result return(result); }
|
|
-
-
macavenger


- Joined on 05-15-2007
- Fairbanks, AK
- Posts 7
|
TheFeshy:I handled them easily. I just pass the number through the string-to-float and float-to-string functions I wrote...
That's cheating. For my case, at least, manipulating strings means manipulating ONLY strings...no converting to floats allowed, however self-written and WTF'y the conversion is :)
Aluminum iMac 20" C2D 2.4 GHz/300 GB/3 GB
|
|
-
-
Massimo


- Joined on 04-25-2007
- Posts 84
|
macavenger:For my case, at least, manipulating strings means manipulating ONLY strings...no converting to floats allowed, however self-written and WTF'y the conversion is :)
You're absolutely right.
I take them from the calculator's display, operate on them and print the result out without ever using any "true" number.
|
|
-
-
macavenger


- Joined on 05-15-2007
- Fairbanks, AK
- Posts 7
|
Massimo: macavenger:Tell me about it...I never realized just how hard subtraction actually is until I tried to break it down to work on strings, character-by-character.
This is mine: [snip...]
yeah, I have mine posted over at http://forums.worsethanfailure.com/forums/post/121242.aspx, or at least the guts of mine. That function is called from another that swaps the numbers if needed...at least for some cases :) Actually, for most subtractions returning a negative number, you'll get an incorrect result, but it does work on the test cases for this contest :)
Aluminum iMac 20" C2D 2.4 GHz/300 GB/3 GB
|
|
-
-
Chicken Little


- Joined on 04-29-2007
- North of 49
- Posts 16
|
Here is mine: char *DoSub(char *op1, char *op2) { //TODO return the difference between op1 and op2
static char TheResult[BUFFERSIZE]; Move(TheResult, &Zero);
char Sign = Compare(op1, op2) == Less ? Subtraction : Addition; if (Compare(op1, op2) == Less) *(long*)&op1 ^= *(long*)&op2 ^= *(long*)&op1 ^= *(long*)&op2;
char *PointerTo_op1 = EndOf(op1); char *PointerTo_op2 = EndOf(op2); char *PointerToTheResult = TheResult; bool BorrowTheOne = false;
while (PointerTo_op1 >= op1) { char *RightOp = PointerTo_op2 >= op2 ? PointerTo_op2-- : &Zero;
if (*PointerTo_op1 == Nine && *RightOp == *PointerTo_op1) *PointerToTheResult++ = BorrowTheOne == true ? *PointerTo_op1 : Zero; if (*PointerTo_op1 == Nine && *RightOp == Eight) { *PointerToTheResult++ = BorrowTheOne == true ? Zero : One; BorrowTheOne = false; } if (*PointerTo_op1 == Nine && *RightOp == Seven) { *PointerToTheResult++ = BorrowTheOne == true ? One : Two; BorrowTheOne = false; } ... Snipped a couple hundred lines of similiar code if (*PointerTo_op1 == Zero && *RightOp == Two) { *PointerToTheResult++ = BorrowTheOne == true ? Seven : Eight; BorrowTheOne = true; } if (*PointerTo_op1 == Zero && *RightOp == *PointerTo_op1) *PointerToTheResult++ = BorrowTheOne == true ? Nine : *PointerTo_op1; if (*PointerTo_op1-- == Zero && *RightOp == One) { *PointerToTheResult++ = BorrowTheOne == true ? Eight : Nine; BorrowTheOne = true; } }
*PointerToTheResult = End; PointerToTheResult = Reverse(TheResult); while (*PointerToTheResult++ == Zero && *PointerToTheResult != End); --PointerToTheResult; if (Sign == Subtraction) *Move(PointerToTheResult + 1, PointerToTheResult) = Sign;
return PointerToTheResult; }
|
|
-
-
gustavderdrache


- Joined on 05-15-2007
- Posts 3
|
I picked a faux client-server approach. I drew a lot of inspiration from the front page WTFs on this fine website. Here are the steps to calculating 1 + 1 in my calculator.
- The Front End is a text widget that does not allow interaction (you can only talk to it via an input palette). The Front End retains a string in memory instead of reading off of the text widget, so using the text box is a futile affair. Entering "1+1=", at this point, causes the string "1+1" to be created.
- When the user presses '=', the Middle End (part 1) is forked off by the Front End. The Front End then prints the string to a pipe, where the middle end (part 1) redirects stdin and stdout to files. They would have been pipes, but that never worked. So the middle end copies the pipe to a file, opens an output end, and executes bison parser #1. The parser's only job is to transform "1+1" into something the Back End will understand: a string of the form 'it = "1"+"1"; print it;". This is, of course, sent off on to a pipe to Middle End (part 2).
- The Middle End (part 2) used to be an experiment in piping to bison, but once it started working, I found it easier to interact with that than the Back End. So its sole purpose in life is to talk to the Back End in a way it understands. It does nothing but move what's printed on its pipe to a different file, and fork & exec the Back End.
- The Back End parses the string expressions, passing them to libGMP in a leaky and useless manner, and then prints to what it believes is stdout.
- Instead of trying to simulate a reply, I got lazy and used the Front End to open up the last file in the chain and read it, appending the contents to the text widget.
Now, I thought that this was pretty bad, but my chances at that JPEG seem shot after seeing some nearly Lovecraftian horrors spawned from the deeps...
|
|
-
-
phaedrus


- Joined on 03-20-2007
- Seattle Ex-Pat living in the Bay Area
- Posts 111
|
Massimo:I've seen lots of wonderful and/or horrible things here, both on the main site and in this contest, and I think WTFs can be divided in two main categories, at least when talink about code: things that are just so utterly complicated and/or convoluted they could easily win an Obfuscated <Put Your Language Here> Contest, and things that are just simple, neat, to the point, and leave you screaming in horror and wanting to use some really heavy and/or really sharp tool on the programmer who created them.
I personally prefer the latter ones, and all my entries follow this pattern; I think a Real WTF(TM) should slam you in the face with the uttermost violence, instead of making you look, search and try to understand what at all is it all about. Also, simple (but powerful) WTFs have two added benefits: they can easily be understood by someone who doesn't even know the language they're written in, and they can be quickly shared with your friends; something like "hey, this guy's deleting an object from inside it, WTF?!?" or in "patching in-memory ASM code at runtime, now *that*'s crazy!", or even "wow, the calculator is executed on a network server to which the GUI connects and submits operations using XML, what had the programmer smoked?"; as opposed to "what the heck's going on in this 500-lines function who returns the sum of two numbers? Let's see... oh, that's a bitshift... ok, recursion... damn, what was that variable for? Argh, headache!".
What do you think about this? :-)
I think you're right about the Ugly Code rule. I think it's going to disqualify a significant number of entries. I'm hoping mine is not one of those, although I went and abused the Ugly Code rule, as my entry is kind of a hybrid. There's Ugly Code in there, but that's not the Real WTF. The Real WTF is the clean code I wrote to make the Ugly Code work. Hmm, I think I just gave everything away. That little tidbit combined with the my other recent posts probably gives away what I did. I'm still not going to be explicit.
All men are frauds. The only difference between them is that some admit it. I myself deny it. -- H. L. Mencken
|
|
-
-
Chicken Little


- Joined on 04-29-2007
- North of 49
- Posts 16
|
Massimo: macavenger:For my case, at least, manipulating strings means manipulating ONLY strings...no converting to floats allowed, however self-written and WTF'y the conversion is :)
You're absolutely right.
I take them from the calculator's display, operate on them and print the result out without ever using any "true" number.
But looking at your DoSub() code I noticed you are using ints in your for loops. In my code I do not use any numbers, not even for counting loops. It is all done with text strings.
|
|
-
-
burntfuse


- Joined on 05-16-2007
- Posts 133
|
In my code I do not use any numbers, not even for counting loops. It is all done with text strings.
for (char i = 'a', i < 'a' + NUM_ITERATIONS; i++) ? Or is it something worse?
|
|
-
-
Carnildo


- Joined on 03-30-2005
- Posts 651
|
Massimo:I've seen lots of wonderful and/or horrible things here, both on the main site and in this contest, and I think WTFs can be divided in two main categories, at least when talink about code: things that are just so utterly complicated and/or convoluted they could easily win an Obfuscated <Put Your Language Here> Contest, and things that are just simple, neat, to the point, and leave you screaming in horror and wanting to use some really heavy and/or really sharp tool on the programmer who created them.
Two of my entries follow the second philosophy: they are simple, well-coded, and present a single, major algorithmic WTF in less than 200 lines of code. The third is something else entirely.
|
|
-
-
Chicken Little


- Joined on 04-29-2007
- North of 49
- Posts 16
|
burntfuse:In my code I do not use any numbers, not even for counting loops. It is all done with text strings.
for (char i = 'a', i < 'a' + NUM_ITERATIONS; i++) ? Or is it something worse?
This is my DoMul() function. LoopCounter is the loop controller: char *DoMul(char *op1, char *op2) { //TODO return the product of op1 and op2
static char TheResult[BUFFERSIZE]; Move(TheResult, &Zero);
char LoopCounter[BUFFERSIZE]; Move(LoopCounter, &Zero); while (Compare(LoopCounter, op2) == Less) { Move(LoopCounter, DoAdd(LoopCounter, &One)); Move(TheResult, DoAdd(TheResult, op1)); }
return TheResult; } I used only while loops in my code, there are no for loops at all.
|
|
-
-
macavenger


- Joined on 05-15-2007
- Fairbanks, AK
- Posts 7
|
Chicken Little: burntfuse:In my code I do not use any numbers, not even for counting loops. It is all done with text strings.
for (char i = 'a', i < 'a' + NUM_ITERATIONS; i++) ? Or is it something worse?
This is my DoMul() function. LoopCounter is the loop controller: [snip..] I used only while loops in my code, there are no for loops at all.
I used no loops-any looping I needed I implemented with a recursive function :) My "counters" are implemented similarly to the above example for numbers that I know will fit in a char - some of my recursions can end up being hundreds (or thousands) of levels deep, and for those I used a char string, which I incremented using a function I write that makes it act like a regular number (rolling over to the next digit when it reches '9' or '0'. I'll admit, however, that things got somewhat more boring once I discovered that a char is perfectly happy to work as a one-byte int, even without being explicitly cast as such.
Aluminum iMac 20" C2D 2.4 GHz/300 GB/3 GB
|
|
-
-
BsAtHome


- Joined on 05-15-2007
- Posts 15
|
macavenger: Massimo:My first entry shouts something along the lines of "you're not allowed to do this!" if you try to use decimal or negative numbers... it's just too much pain to handle those when your calculator is based on manipulating strings.
Tell me about it...I never realized just how hard subtraction actually is until I tried to break it down to work on strings, character-by-character. In my code, I managed to eliminate ints entierly... makes for some fun lines like char buffer[`~']; :p
But subtraction is so simple in ASCII BigEndian BCD as in O(n) for positive results and O(2n+1) for negative results: static void minus(node_t *l, node_t *r)
{
int n, i, b = 0;
char *res;
/* Recursive reduction of parsetree to values */
reduce(l);
reduce(r);
/* Degenerate cases */
if(l->e || r->e)
{
l->e = 1;
zap(r);
return;
}
if(r->s)
{
r->s = 0;
plus(l, r);
return;
}
n = fixsize(l, r); /* Need same sized operands */
res = (char *)xmalloc(n+2);
for(i = 0; i < n; i++) /* Subtract */
{
int ch = l->v[i] - r->v[i] + '0' - b;
b = 0;
if(ch < '0')
{
ch += 10;
b++;
}
res[i] = ch;
}
if(b) /* 2's complement if borrowed (negative) */
{
node_t *o = (node_t *)xmalloc(sizeof(*o));
node_t *p = (node_t *)xmalloc(sizeof(*p));
node_t *q = (node_t *)xmalloc(sizeof(*q));
char *c = (char *)xmalloc(n+2);
memset(c, '0', n);
c[i] = '1';
p->v = c;
q->v = res;
minus(p, q);
res = p->v;
xfree(p);
}
else
while(i > 1 && res[i-1] == '0')
res[--i] = 0;
l->s = b;
zap(r);
xfree(l->v);
l->v = res;
}
|
|
-
-
asuffield


- Joined on 05-31-2006
- Posts 2,137
|
BsAtHome:But subtraction is so simple in ASCII BigEndian BCD as in O(n) for positive results and O(2n+1) for negative results:
O(n) and O(2n+1) are the same thing.
|
|
-
-
Massimo


- Joined on 04-25-2007
- Posts 84
|
asuffield:O(n) and O(2n+1) are the same thing.
They are, because their durations both depend linearly on N.
At the same time, they are not, because O(2n) will always take two times the time of O(n).
|
|
-
-
asuffield


- Joined on 05-31-2006
- Posts 2,137
|
Massimo: asuffield:O(n) and O(2n+1) are the same thing.
They are, because their durations both depend linearly on N.
At the same time, they are not, because O(2n) will always take two times the time of O(n).
No, you have to understand what O() actually means. It's not just a rough measurement of the algorithm's performance, nor is it a measurement of how many steps the algorithm actually takes, it has a specific definition. Informally:
An algorithm is O(f(x)) if and only if there exists two constant values C and x0 such that the time/steps/whatever taken to complete the algorithm is always less than C * f(x) for all x > x0. Note that this means | | |
|