Shorter Rot13 Pure-C Implementation

A

Agent Spikes

I just improved upon the 64-byte implementation of Rot13 as listed
here and got it down 2 more characters:

http://hea-www.harvard.edu/~fine/Tech/rot13.html

The updated line is:
main(a){while(a=getchar())putchar(a-1/((a&~32)/13*2-11)*13);}

The improvements were achieved by:
- Get the NOT off of the getchar() and adjust throughout the equation
[1 byte]
- Apply De Morgan's laws newly created "~(~a|32)", leaving us with "(a|
~32)" [1 byte]

Feel free to rip it apart and let me know what you think. :)
 
A

Agent Spikes

Quick summary of changes correction:

"(a|~32)" is actually ""(a&~32)"

I'm only human after all :)
 
J

James Dow Allen

I just improved upon the 64-byte implementation of Rot13 as listed
here and got it down 2 more characters:
...
The updated line is:
main(a){while(a=getchar())putchar(a-1/((a&~32)/13*2-11)*13);}
...
Feel free to rip it apart and let me know what you think. :)

Well, that's what we're here for, critiquing code.
Did you profile your code first to see if greater efficiency
were needed?

I'll mention a few errors; get yourself a better
compiler if it didn't point these out to you.
(I use something like
gcc -W{,a,e,i,o,u}{,b,c,d,f,g,h,j,k,l,x}{,l,m,s,t,v,w,z}
)

You've failed to include the stdio.h header;
your definition of main is non-compliant, deprecable,
and probably guarantees undefined behavior, and main's
return should be explicit.

We'd better avoid discussing your placement of white
space (although you did find a clever way to finesse
the entire issue). My own preference is One True Style,
but I'll admit to finding your approach superior
to some alternates espoused in a recent thread.
We all agree descriptive variable numbers are
appropriate; I'd have chosen 'b' or perhaps 't'
over your 'a'.

Finally, your code won't work on Ebcdic machines,
though that doesn't bother *me*.
(For my own programming I'm no more interested in
support for Ebcdic than I am in support for Windows.
Anyway, some people say that IBM'ers are overly
sober with no sense of whimsy: do they really use
rot13?)

Hope this helps,
James
 
A

Agent Spikes

Hi James,

My compiler actually does show me the warnings, however, I chose to
ignore them as it was against the goal set forth in undertaking this
project: make the "worlds shortest C Implementation of Rot13" even
shorter. (By Pure-C, I mean to say no cheap hacks like exec'ing an
external application like "tr" to do the translation for you.) In
light of this, the warnings and inability to build on some obscure
systems is most definitely a side effect I considered, but in the end,
the small rarity that they are (except for maybe Microsoft compilers,
don't know on that one) was against the goals of the undertaking.

Being that the raw source size (including the final LF) was the
biggest concern of this challenge, I wasn't too worried about speed --
in all reality, the obfuscated and small version posted very likely
can be done quicker with alternate methods, at the cost of a larger
source size.

The variable naming thing is generally something I adhere very
strongly to, but with only one variable, I'm not sure that there would
be much benefit to changing the variable name from Michael Schroeder's
work (after all, I merely made his works even smaller).

In any case, I really do appreciate that you've taken the time to
provide your insights. I generally hate just about every warning in a
"real" project and any code I release other than this has 0 warnings
left in it. (Even though some are fine to leave there -- I'm just a
bit OCD about that.)

Thanks!

Wesley S.
 
B

Ben Bacarisse

Interleaved posting is preferred here so I've kept some context and
re-order your post.
My compiler actually does show me the warnings, however, I chose to
ignore them as it was against the goal set forth in undertaking this
project: make the "worlds shortest C Implementation of Rot13" even
shorter. (By Pure-C, I mean to say no cheap hacks like exec'ing an
external application like "tr" to do the translation for you.)

So the rules seem to be that you can't use anything other than
standard C but you don't have to use standard C.

| main(a){while(a=getchar())putchar(a-1/((a&~32)/13*2-11)*13);}

It would seem that the program does not even have to terminate. Are
there any formal conditions the program must meet?

<snip>
 
P

Peter Nilsson

Agent Spikes said:
I just improved upon the 64-byte implementation of Rot13
as listed here and got it down 2 more characters:

http://hea-www.harvard.edu/~fine/Tech/rot13.html

The rules for IOCCC are somewhat nebulous.
The updated line is:
main(a){while(a=getchar())putchar(a-1/((a&~32)/13*2-11)*13);} ....
Feel free to rip it apart and let me know what you think. :)

Even assuming C90...
Wrong implicit declaration for main.
Terminates on 0 not EOF.
Assumes ASCII.
Relies on devision of 1/-ve to round towards 0.

Since this is clc, why don't you have a crack at a strictly
conforming version? Here's a C90 program to get you started...

char*strchr();main(){int a;while((a=getchar())>=0){char*s=
strchr("abcdefghijklmnopqrstuvwxyzabcdefghijklmABCDEFGHIJ"
"KLMNOPQRSTUVWXYZABCDEFGHIJKLM",a);putchar(s?s[13]:a);}}
 
M

Michael Foukarakis

The rules for IOCCC are somewhat nebulous.

Actually, the IOCCC rules are pretty concise for someone who wants to
understand them.
Even assuming C90...
  Wrong implicit declaration for main.

Is it really 'wrong' if a C89/C90 conforming compiler compiles it?
(hint: it's rhetorical)
  Terminates on 0 not EOF.
  Assumes ASCII.
  Relies on devision of 1/-ve to round towards 0.

All valid assumptions under IOCCC rules. Under reality, also. The OP
probably wanted to deal with actually implementing the shortest ROT13
instead of porting it on every machine that ever existed.
Since this is clc, why don't you have a crack at a strictly
conforming version?

Why don't you let him have a crack at whatever he wants?
 
I

Ike Naar

Is it really 'wrong' if a C89/C90 conforming compiler compiles it?
(hint: it's rhetorical)


All valid assumptions under IOCCC rules. Under reality, also. The OP
probably wanted to deal with actually implementing the shortest ROT13
instead of porting it on every machine that ever existed.

Not under reality, alas.
Here are four "real" environments where the program does not work:
gcc 4.1.2 / alpha / NetBSD 4.0.1
Sun C 5.9 / sparc / Solaris 10
gcc 2.95 / x386 / OpenBSD 3.3
gcc 4.1.2 / x386 / Fedora Core 6

In all cases, the program loops forever when given as input a data file
containing the five characters 'o', 'o', 'p', 's', '\n'.
 
J

James Dow Allen

Hi James,
My compiler actually does show me the warnings,...

I *did* admire your code, Agent Spikes, and, since I now
seem to be in the vanguard of a thread "attacking" it,
let me state that my response was *intended* to be humorous.

I omitted any smiley-face, thinking that excerpts like
.... would make my post's tongue-in-cheek nature clear!

James
 
M

Michael Foukarakis

Is it really 'wrong' if a C89/C90 conforming compiler compiles it?
(hint: it's rhetorical)
All valid assumptions under IOCCC rules. Under reality, also. The OP
probably wanted to deal with actually implementing the shortest ROT13
instead of porting it on every machine that ever existed.

Not under reality, alas.
Here are four "real" environments where the program does not work:
gcc 4.1.2 / alpha / NetBSD 4.0.1
Sun C 5.9 / sparc / Solaris 10
gcc 2.95 / x386 / OpenBSD 3.3
gcc 4.1.2 / x386 / Fedora Core 6

In all cases, the program loops forever when given as input a data file
containing the five characters 'o', 'o', 'p', 's', '\n'.[/QUOTE]

You have not understood what the program does.

It will not terminate unless it receives '\0' on input.
 
I

Ike Naar

Michael Foukarakis   said:
The updated line is:
main(a){while(a=getchar())putchar(a-1/((a&~32)/13*2-11)*13);}
Is it really 'wrong' if a C89/C90 conforming compiler compiles it?
(hint: it's rhetorical)

Terminates on 0 not EOF.
Assumes ASCII.
Relies on devision of 1/-ve to round towards 0.
All valid assumptions under IOCCC rules. Under reality, also. The OP
probably wanted to deal with actually implementing the shortest ROT13
instead of porting it on every machine that ever existed.

Not under reality, alas.
Here are four "real" environments where the program does not work:
[...]

You have not understood what the program does.

Why do you think so?
I think I do understand what the program does, and I also think the
OP's program is wrong. Why?
Well, every obfuscated program on the page mentioned by the OP,

http://hea-www.harvard.edu/~fine/Tech/rot13.html

terminates on EOF, not 0.
An obfuscated rot13 is (I think) supposed to emulate the 'regular'
rot13 program. The one regular version that I tried (the version that
comes with NetBSD) terminates on EOF, not on 0. It just passes a
0 character unchanged.

You are saying termination on 0 is a valid assumption under the IOCCC
rules and under "reality". Can you cite the relevant IOCCC rule? (I could
not find such a rule). And in reality it's pretty unusual for a program
that reads from stdin to terminate on 0 instead of EOF. Do you know
real programs that show such behaviour?

All in all, I think that the OP did not succeed in constructing a
correct obfuscated rot13 program.
A correct rot13 program would, when fed the five-byte input file

oops

(that is, 'o', 'o', 'p', 's', \n'),
produce the five-byte output

bbcf

(that is, 'b', 'b', 'c', 'f', '\n'), and then stop.
It should not, as the OP's program does, continue to
loop forever, producing an infinite amount of garbage.
 
I

Ike Naar

[ main(a){while(a=getchar())putchar(a-1/((a&~32)/13*2-11)*13);} ]
You have not understood what the program does.
It will not terminate unless it receives '\0' on input.

Perhaps you could be less cryptic?
If you feed the program a file that does not contain a '\0',
the program will never receive an '\0' on input, and it will
loop forever on the end of the input file. What am I missing?
 
A

Agent Spikes

Hi James,

I *did* admire your code, Agent Spikes, and, since I now
seem to be in the vanguard of a thread "attacking" it,
let me state that my response was *intended* to be humorous.

I omitted any smiley-face, thinking that excerpts like [snip]
... would make my post's tongue-in-cheek nature clear!

Thank you. Yup, it was pretty clear, but you did have some valid
points that I felt others would no doubt try to raise later on, so I
felt it wise to cover the grounds early.

-Wesley S.
 
A

Agent Spikes

In regards to multiple responses in this thread:

The sole goal was to improve upon the smallest possible "complete"
Rot13. In perusing this goal, I started out with Michael Schroeder
<[email protected]>'s implementation of a
micro Rot13 and aimed solely to shrink it.

The key points this was built upon were
- First and foremost, a challenge.
- Use Only C code (even if it's "loose" or against standards!)
+ The primary reason for this consideration was that the "tr" hack
just bugged me.

Little to no consideration was taken into account for
- EOF marker (instead it breaks on a 0 input)
- C-Standards Compliance
- Wide Cross-Platform Compatibility

To quote Michael Foukarakis:
The OP probably wanted to deal with actually implementing the
shortest ROT13 instead of porting it on every machine that ever
existed.

This assumption was pretty much spot-on to the goals of this
undertaking.

While I understand that some of you may consider the challenge's
simple goals a sort of shortsightedness, you're missing the bigger
picture here which was quite a simple one: a fun challenge to force me
to think in ways well outside the box.
 
I

Ike Naar

In regards to multiple responses in this thread:

The sole goal was to improve upon the smallest possible "complete"
Rot13. In perusing this goal, I started out with Michael Schroeder
<[email protected]>'s implementation of a
micro Rot13 and aimed solely to shrink it.

The key points this was built upon were
- First and foremost, a challenge.
- Use Only C code (even if it's "loose" or against standards!)
+ The primary reason for this consideration was that the "tr" hack
just bugged me.

Little to no consideration was taken into account for
- EOF marker (instead it breaks on a 0 input)
- C-Standards Compliance
- Wide Cross-Platform Compatibility

To quote Michael Foukarakis:

This assumption was pretty much spot-on to the goals of this
undertaking.

While I understand that some of you may consider the challenge's
simple goals a sort of shortsightedness, you're missing the bigger
picture here which was quite a simple one: a fun challenge to force me
to think in ways well outside the box.

Perhaps you are also missing a bigger picture: if you are allowed to
change the requirements, where does it end? You've stretched the
requirements very far, in that your program no longer implements ROT13
for a large class of input files.
If you find that acceptable, then why not stretch it a bit further?
"main(){}" implements ROT13 as well, as long as the input is short enough.
 
D

Dann Corbit

Perhaps you are also missing a bigger picture: if you are allowed to
change the requirements, where does it end? You've stretched the
requirements very far, in that your program no longer implements ROT13
for a large class of input files.
If you find that acceptable, then why not stretch it a bit further?
"main(){}" implements ROT13 as well, as long as the input is short enough.

Rot13 is only supposed to run against letters. Any symbol that is not
in the set (A-Z, a-z) should be left alone.

Here is a readable rot13() that ought to be obvious to anyone exactly
what it is doing {I did not test using EBCDIC, but it seems to work fine
on ASCII}:

#include <ctype.h>
#include <string.h>
#include <stdio.h>

/* rot13() processes a single character {reversible change.} */
/* We assume both A-Z and a-z are continuous and ascending. */
int rot13(int c)
{
int base = 'a';
if (isalpha(c)) {
if (isupper(c))
base = 'A';
c = (c - base + 13) % 26 + base;
}
return c;
}

/* Process a line of characters: */
void rotate(char *s)
{
for ( ; *s ; ) {
*s = (char) rot13(*s);
s++;
}
}

#ifdef UNIT_TEST
/* Some scratch space: */
char string[32767];

/* Test driver: */
int main(void)
{
while (fgets(string, sizeof string, stdin)) {
char *where = strchr(string, '\n');
if (where) *where = 0;
printf("Original string: [%s]\n", string);
rotate(string);
printf("Transformed string: [%s]\n", string);
rotate(string);
printf("Transformed back: [%s]\n", string);
}
return 0;
}
#endif
 
R

Richard Bos

Agent Spikes said:
In regards to multiple responses in this thread:

The sole goal was to improve upon the smallest possible "complete"
Rot13. In perusing this goal, I started out with Michael Schroeder
<[email protected]>'s implementation of a
micro Rot13 and aimed solely to shrink it.

The key points this was built upon were
- First and foremost, a challenge.
- Use Only C code (even if it's "loose" or against standards!)
Little to no consideration was taken into account for
- EOF marker (instead it breaks on a 0 input)
- C-Standards Compliance
- Wide Cross-Platform Compatibility

Oh, in that case...

main(a){return rot13(a);}

Looks like C, compiles with no warnings if you set the warning level to
sub-zero, and given the right "C-ish" environment it does what you want.
And there was much rejoicing.

Richard
 
M

Michael Foukarakis

Michael Foukarakis   said:
[ main(a){while(a=getchar())putchar(a-1/((a&~32)/13*2-11)*13);} ]
You have not understood what the program does.
It will not terminate unless it receives '\0' on input.

Perhaps you could be less cryptic?
If you feed the program a file that does not contain a '\0',
the program will never receive an '\0' on input, and it will
loop forever on the end of the input file. What am I missing?

You are missing the fact that the IOCCC rules don't specify the form
of the input, as well as the fact that when someone hands you a piece
of machinery that operates correctly around 220V and you put it in a
40V socket, you will not get the expected results.
Perhaps you are also missing a bigger picture: if you are allowed to
change the requirements, where does it end? You've stretched the
requirements very far, in that your program no longer implements ROT13
for a large class of input files.

He did not alter or stretch the requirements. He introduced an
additional constraint. Making your input files compatible is that much
easy:

echo -ne "0x00" >> input

I don't see how this is so hard to comprehend.
If you find that acceptable, then why not stretch it a bit further?
"main(){}" implements ROT13 as well, as long as the input is short enough..

No, since it doesn't process input at all, it doesn't implement ROT13
for ANY input.
 
I

Ike Naar

He did not alter or stretch the requirements. He introduced an
additional constraint.

Introducing additional constraints is not changing the requirements?
Making your input files compatible is that much easy:

echo -ne "0x00" >> input

I don't see how this is so hard to comprehend.

ROT13 has the nice property that when you apply it twice to
any input text, it will produce the original input.
Actually this is an essential property, because ROT13 is often used
as a (very simple) text encrypter/decrypter.

Let's see what true ROT13 does to the eight-byte text "foo\0bar\n",
that is: 'f', 'o', 'o', '\0', 'b', 'a', 'r', '\n'

"foo\0bar\n"
---ROT13--->
"sbb\0one\n"
---ROT13--->
"foo\0bar\n"

Nice! Michael Schroeder's solution (on which OP's code is based)
behaves exactly like that.

Now take OP's program (extended with your preprocessor):

"foo\0bar\n"
---preproces--->
"foo\0bar\n\0"
---OP--->
"sbb"
---preprocess--->
"sbb\0"
---OP--->
"foo"

Whoops, we lost five bytes. Not so nice.
No, since it doesn't process input at all, it doesn't implement ROT13
for ANY input.

"main(){}" works perfectly okay for zero-sized input.
Imposing zero size is just an additional constraint ;-)
 
M

Michael Foukarakis

Introducing additional constraints is not changing the requirements?




ROT13 has the nice property that when you apply it twice to
any input text, it will produce the original input.
Actually this is an essential property, because ROT13 is often used
as a (very simple) text encrypter/decrypter.

Let's see what true ROT13 does to the eight-byte text "foo\0bar\n",
that is: 'f', 'o', 'o', '\0', 'b', 'a', 'r', '\n'

                "foo\0bar\n"
  ---ROT13--->
                "sbb\0one\n"
  ---ROT13--->
                "foo\0bar\n"

Nice!  Michael Schroeder's solution (on which OP's code is based)
behaves exactly like that.

Now take OP's program (extended with your preprocessor):

                "foo\0bar\n"
  ---preproces--->
                "foo\0bar\n\0"
  ---OP--->
                "sbb"
  ---preprocess--->
                "sbb\0"
  ---OP--->
                "foo"

Whoops, we lost five bytes. Not so nice.



"main(){}" works perfectly okay for zero-sized input.
Imposing zero size is just an additional constraint ;-)

If you don't wish to understand my arguments, please refrain from
addressing me. I've only got so much time to waste.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,051
Latest member
CarleyMcCr

Latest Threads

Top