Power Koding
by Chuck Homic
What is Power Koding?
Power Koding is a different way of programming; a different way of thinking. All too often we get caught up in habits, find ourselves stuck in a groove,
Koding Tip
Small, helpful hints
can be found in boxes
such as this.
adhering to an often restrictive set of standards. (A great man once said, "Alas, standards make life so dull.") How can we break out of such complacentcy? It takes only a little bit of concentration, to pay attention to what you are doing, and think about what you should be doing.

Currently, this document has little organization. It is merely a list of Power Koding techniques which you can apply immediately to help you get closer to
Kareful!
You can find things
to watch out for in
boxes like this.
becoming a Power Koder yourself. Also, this site is fairly new, so expect new techniques and tips every week or so. Try to choose one technique at a time, and apply it to your everyday coding. It may be difficult at first. Power Koding, like any art, takes concentration, and practice. But after a while, you will no longer have to think of the techniques. It is at that point that you are a true Power Koder.

The Truth About Bugs
It is common among amateur programmers to have a mindset that once you find a bug in a piece of software, you must immediately fix it. It is easy to fall into that trap, since it's a disarmingly innocent-seeming response. But professionals will tell you that a vast majority of bugs can easier be handled in end-user documentation, rather than code. If your program has unpredictable results in a given situation, then simply instruct the user how to avoid that situation. Once you put this more realistic philosophy into practice, you will notice that your coding sessions are much more efficient, and you can complete projects much more quickly, since you can spend less time considering problems that don't require your attention.
Features are your Friends
Modern

"I never met a feature
I didn't like"
-Prof. Steven Taylor

languages, such as C++ and Java, have a myriad of features available to you. Many programmers have a tendency to artificially limit themselves to what they think they need for a particular project. In the end, that is counterproductive. Instead, you should strive to use every feature that the language has to offer. That way, you can make sure you've offered the most options to your users. If you haven't used templates, or virtual functions in your program, find a way to use them, and use them a lot. Your users will thank you.
Unnecessary Whitespace
In a programming language such as C, programmers have a tendency to use a lot of extra whitespace in their programs. The effect? Thousands of bytes of wasted disk space, storing useless 0x09 and 0x20 characters. Take, for example, the following program, which calculates the denominations of change (in US currency) for a transaction entered by the user:

Listing 1
#include <stdio.h>

struct DENOM
  {
    char *NameS, *NameP;
    int value;
  }
denom[] =
  {
    "100 dollar bill", "100 dollar bills", 10000,
    "50 dollar bill", "50 dollar bills", 5000,
    "20 dollar bill", "20 dollar bills", 2000,
    "10 dollar bill", "10 dollar bills", 1000,
    "5 dollar bill", "5 dollar bills", 500,
    "1 dollar bill", "1 dollar bills", 100,
    "quarter", "quarters", 25,
    "dime", "dimes", 10,
    "nickel", "nickels", 5,
    "penny", "pennies", 1,
};

#define denoms (sizeof(denom)/sizeof(DENOM))

int 
main (void)
{
  float cash, price, change;
  int c, num, intchange;

  printf ("Enter cash tendered: ");
  scanf ("%f", &cash);

  printf ("Enter price of item: ");
  scanf ("%f", &price);

  change = cash - price;

  if (change < 0)
    {
      printf ("Not enough money, you idiot!\n");
      return -1;
    }
  else if (change == 0)
    {
      printf ("No change.\n");
      return -1;
    }
  else
    {
      printf ("The change is: $%0.2f\n\n", change);

      intchange = (int) ((change + .005) * 100);
      for (c = 0; c < denoms; c++)
	{
	  num = intchange / denom[c].value;
	  if (num)
	    {
	      printf ("%d %s\n", num, num == 1 ? denom[c].NameS : denom[c].NameP);
	      intchange -= denom[c].value * num;
	    }
	}
      return 0;
    }
}

As you can see this program is several pages long, and uses 1,297 bytes of storage. Now take a look at the more efficient version, which does the exact same thing:

Listing 2
#include<stdio.h>
struct DENOM{char*NameS,*NameP;int value;}denom[]={"100 dollar bill",
"100 dollar bills",10000,"50 dollar bill","50 dollar bills",5000,
"20 dollar bill","20 dollar bills",2000,"10 dollar bill","10 dollar bills",1000,
"5 dollar bill","5 dollar bills",500,"1 dollar bill","1 dollar bills",100,
"quarter","quarters",25,"dime","dimes",10,"nickel","nickels",5,"penny",
"pennies",1,};
#define denoms (sizeof(denom)/sizeof(DENOM))
int main(void){float cash,price,change;int c,num,intchange;printf(
"Enter cash tendered:");scanf("%f",&cash);printf("Enter price of item:");scanf(
"%f",&price);change=cash-price;if(change<0){printf(
"Not enough money, you idiot!\n");return-1;}else if(change==0){printf(
"No change.\n");return-1;}else{printf("The change is: $%0.2f\n\n",change);
intchange=(int)((change+.005)*100);for(c=0;c<denoms;c++){num=intchange/
denom[c].value;if(num){printf("%d %s\n",num,num==1?denom[c].NameS:denom[c].NameP)
;intchange-=denom[c].value*num;}}return 0;}}

The new version of the code is only 986 bytes. That's a significant savings. (And that includes the linefeed at the end of each line to make it fit in an 80 column editor) In fact, there are many advantages to compressing your code in such a fashion (which I will call source-level compressing):
Koding Tip
When using one-character variable
names, remember that variables are
case-sensitive, and the underscore
character is also valid. That gives
you 53 different one-character
variable names to work with!

  • The most obvious reason is to make it take up less disk space. By removing unnecessary spaces, we decreased the file size by 311 bytes. That's about a 24% savings.
  • The resultant code also takes up fewer pages. If you printed out both versions of the code, the latter would waste far less paper than the first.
  • Because the new code fits on a page, it is easier to debug, since you can see the entire program at once. There is no need to page up and down to try to follow the flow of execution to look for bugs.
That's all useful stuff, but we haven't yet made the program optimal. We can make the program take up even less space by using shorter variable names:

Listing 3
#include<stdio.h>
struct D{char*s,*p;int v;}d[]={"100 dollar bill","100 dollar bills",10000,
"50 dollar bill","50 dollar bills",5000,"20 dollar bill","20 dollar bills",2000,
"10 dollar bill","10 dollar bills",1000,"5 dollar bill","5 dollar bills",500,
"1 dollar bill","1 dollar bills",100,"quarter","quarters",25,"dime","dimes",10,
"nickel","nickels",5,"penny","pennies",1,};
#define ds (sizeof(d)/sizeof(D))
int main(void){float m,p,r;int c,n,i;printf("Enter cash tendered:");scanf("%f",
&m);printf("Enter price of item:");scanf("%f",&p);r=m-p;if(r<0){printf(
"Not enough money, you idiot!\n");return-1;}else if(r==0){printf("No change.\n")
;return-1;}else{printf("The change is: $%0.2f\n\n",r);i=(int)((r+.005)*100);for(
c=0;c<ds;c++){n=i/d[c].v;if(n){printf("%d %s\n",n,n==1?d[c].s:d[c].p);i-=d[c].v*
n;}}return 0;}}

And even more can be gained by eliminating the unnecessary repetition of the string "dollar bill" in the section that declares the strings for all the denominations:

Listing 4
#include<stdio.h>
#define B "dollar bill"
struct D{char*s,*p;int v;}d[]={"100 "B,"100 "B"s",10000,"50 "B,"50 "B"s",5000,
"20 "B,"20 "B"s",2000,"10 "B,"10 "B"s",1000,"5 "B,"5 "B"s",500,"1 "B,"1 "B"s",
100,"quarter","quarters",25,"dime","dimes",10,"nickel","nickels",5,"penny",
"pennies",1,};
#define ds (sizeof(d)/sizeof(D))
int main(void){float m,p,r;int c,n,i;printf("Enter cash tendered:");scanf("%f",
&m);printf("Enter price of item:");scanf("%f",&p);r=m-p;if(r<0){printf(
"Not enough money, you idiot!\n");return-1;}else if(r==0){printf("No change.\n")
;return-1;}else{printf("The change is: $%0.2f\n\n",r);i=(int)((r+.005)*100);for(
c=0;c<ds;c++){n=i/d[c].v;if(n){printf("%d %s\n",n,n==1?d[c].s:d[c].p);i-=d[c].v*
n;}}return 0;}}

The final code is only 734 bytes, which is 43% smaller than the original file. And we didn't use any kind of fancy compression algorithm, nor did the program change in operation at all.

Now you might be saying, "I just compress my files using gzip or PKZIP. I don't need to compress my code any other way." Well, I've got some more thoughts for you:
Koding Tip
Save yourself some
typing by doing this:

#define p printf

  • If you use gzip to compress Listing 1 and Listing 4, they are 556 and 448 bytes respectively. So you can still save almost 20% by using the source-level compression technique.
  • Algorithmically compressed files can't be compiled. Programs compressed source-level can still be compiled and edited as-is, without any annoying decompress stage.


homic@wpi.edu
PGP 5.0 Public Key also available at BAL's PGP Public Key Server.

Disclaimer: All information, ideas, and opinions contained in this document are misguided, incorrect, and/or false. Use of the information herein is bound to end only in embarassment, ridicule and/or death. This is true of both the content of this document, and the disclaimer itself. Stop reading this right now. I mean it. No really, if you keep reading you're only asking for trouble. Okay, don't say I didn't warn you.