Monday, April 18, 2011

CS: Loops and conditionals, pt. 2

Sorry this post is coming a bit later than I originally intended. Let's briefly review what we talked about last time before diving into the new material.

Loops and conditionals allow us to control which instructions the computer processor is going to execute and when. Loops let us execute some instructions again, even after we already have executed them. Last time we saw the example of a while() loop that executed the code to add 1 to x and store it in x, and this loop executed 10 times.

Today we're talking about using if() statements to decide if we want to skip over a block of code. If the conditional statement inside the if() statement is true, then the block of code that follows the if() statement is executed. If the conditional statement inside the if() statement is false, then the block of code that follows the if() statement is skipped (it is not executed). Look at this code snippet:

x=1
if(x>2)
{
x=0
}

After the execution of this example the value of x will still be 1 (the value that was set at the beginning of the example). Since x>2 is false (because x is 1, and 1 is not greater than 2), we skipped over the assignment statement that would set x to 0 (x=0). Let's look at an example where the conditional statement evaluates to true:

x=4
if(x>2)
{
x=0
}

Here x starts out as 4, but since 4>2 is true, we execute the block following the if() statement. This block tells us to set x to 0. So at the end of this code snippet, x's final value will be 0.

We can see that if() statements allow us to skip blocks of code that we would only want to execute if the conditional statement of the if() statement is true. Let's look at a more complex example that combines a while() loop, an if() statement and a break:

x=0
y=0
while(x+y<10)
{
if(x<5)
{
y=y+2
}
if(y>4)
{
break
}
x=x+1
}

This example has if() statements inside a while loop. Let's walk through what happens here. First of all, both x and y are set to 0, and then we look at the while loop. Since x+y=0 right now, and 0<10, we will execute the while loop at least once, so let's jump into it. The first thing we run into inside the while loop's block is an if() statement, which asks if x is less than 5. This is true right now, so let's execute that if() statement's block, which increases y by 2. At this point, x is still 0 and y is now 2. Now we look at the next if() statement, which asks if y is greater than 4. This is not true, so we'll skip that block for now. Next we add 1 to x and store the result in x. We've now gone through the loop one time, and x is 1 and y is 2.

What do you do when you finish a run through a while() loop? Go back to the top and test to see if you need to do it all over again. We go back to the top and test x+y<10. Right now x+y is 3, which is definitely less than 10, so we should execute the while() loop's block again. Again we run into the if(x<5) statement, and again this is true, so we execute y=y+2, so now y is 4. Next we test to see if(y>4). Since y is exactly equal to 4, it is *not* greater than 4, so this conditional statement is still false, so we skip the contents of that block. Finally we execute x=x+1, and we're done with our second run of that loop. At this point, x=2 and y=4.

We again go back to the top of the loop, x+y is still less than 10, so we execute the loop one more time. if(x<5) is still true, so we execute y=y+2 again, making y equal to 6 now. This time when we execute the if(y>4) statement, y *is* greater than 4, so we execute the break statement. A break statement means "you're done with this loop now, so exit it immediately without doing anything else on your way out." After executing the break we're now outside the loop and we're done with our code snippet. The final score has x=2 and y=6. Notice that if it weren't for the break statement, since x+y<10 is still true we would still be going through our while() loop until such a time as when x+y is greater than 10.

You might need to read through the examples here a few times. It's substantially more complicated than anything I've presented lately, so you should take your time and go slowly. Make sure you get it.

Next time I'm probably going to talk more about consumer advice. Some time in the future I'll talk a little bit about electricity, just because someone was curious, but I remind you that I am not really qualified to explain it. Good luck to me writing that and you reading that.

Tuesday, April 12, 2011

CS: Loops and conditionals, pt. 1

When I set out to write this series of articles, I wanted to help people who use computers, but don't understand what's going on under the hood, understand what's going on under the hood. Before the reset a couple weeks ago I talked about binary math, computer memory, and branching, in that order. This time around I've skipped binary math, I've talked about memory from a high, abstract level, and now I'm going to tackle branching/looping again. Instead of presenting simple programs as short assembly instruction sequences like I did last time, I'm going to take the easy way out and use a format that might resemble a regular programming language. With that out of the way ...

Everything a computer does can be broken up into individual, small and distinct operations called "instructions." Instructions are simple units of work, and a single instruction might say "load the variable at this memory address into the processor," or "add these two variables together and store the result in this other variable." These instructions are stored in memory and the processor tackles these in the order they appear in memory (for example, it executes the instruction at memory address 200 before it executes the instruction at address 201, and both of these are done before the address at 202, &c.).

Performing instructions in order is useful because it lets the programmer have guarantees about what the processor will do when it executes the program (he knows it won't just randomly execute whatever it feels like). The immediate downside is that if the computer keeps executing instructions in a straight line, there's no way to re-execute old instructions again, or to skip instructions maybe you don't want to execute right now. Both of these problems are solved via looping and conditional execution.

First a bit of vocabulary. I'm going to refer to the endless, ordered list of instructions the processor can execute as the "instruction stream." In this context, "looping" means to repeat an earlier part of the instruction stream (perhaps many times) and "conditional execution" means that you *maybe* will execute the next part of the instruction stream, or you might skip it.

Next we need to be familiar with some computer language jargon and notation relating to loops and conditionals. Here are some more vocabulary words to remember:

conditional statement - This is a question that you can ask about the current state of the program and its variables that you can either answer with "true" or "false." For example, you can ask "is variable X is greater than 10?" As a conditional statement that would be in a real program, this would appear as "X>10" (note there is no question mark, and we're using the "greater than" symbol). If X is greater than 10, this will mean "true," and if X is 9 or less, then this will mean "false." It's conditional.

while() - Yes, the parentheses are included in this vocabulary word. Inside the parentheses goes a "conditional statement." If the conditional statement is true, then you perform some loop as long as the conditional remains true. If the conditional was never true (i.e., always false), then you skip over the while-loop altogether.

if() - Yes, again the parentheses are included, and there's another conditional statement in there. This is really similar to a while-loop, except instead of repeating what comes after this over and over as long as the condition is true, you execute it only once if the condition is true, or zero times if it is false.

{} - These braces let you know that all of the instructions between them are grouped together. This is called a "code block" ("block" as in a block of a street, where all of the houses on that block are neighbors). This group of instructions is what gets repeatedly executed in a loop, or what might skipped over entirely if an if-statement evaluates to false.

break - this special command lets you get out of a while loop early. It usually shows up right after an if-statement. We'll see one of these in action in the next article.

Before I end this article I want to show one example of a simple while loop that is executed 10 times (I parenthetically explain each line. Don't get confused by too many parentheses):

x=0 (this means we're making the variable x hold the value 0)
while(x<10) (execute this loop as long as x is less than 10)
{
x=x+1 (this means we're taking whatever x currently holds, adding one, and making x hold that new value. Essentially we're increasing the vale of x by 1)
}

Variable x starts out at 0, and 1 is added to it 10 times. This is a while-loop that loops around 10 times (or 9 if you don't count the first time through as a "loop"). Notice the braces, also. This time there was only one instruction inside the braces, but there could have been more. If there were more, they would each be on their own line, and each would get executed in the order it appears. When we loop, we go back to the very beginning of the loop, to the very first instruction if there is more than one in the code block.

That's it for this time. Next time, I'll show an example using if-statements, and then one big example that incorporates a while-loop, if-statement, a code block that's bigger than 1, and a break command.

Friday, April 8, 2011

CONSUMER ADVICE: How much RAM?

When buying a new computer, the single most important thing for the average consumer to consider is how much RAM their computer will have. RAM is short for Random Access Memory, but that is neither here nor there--most people don't need to know/care about that. What RAM means to the typical consumer is that more of it lets your computer "feel faster." Well, up to a point.

I suppose this requires a little bit more explanation. In computers there are two types of data storage that make the biggest difference to consumers--hard drive space and RAM. The hard drive holds your permanent data that will stick around long after you've turned your computer off (it will still be there when you turn it on the next time, too). The hard drive holds your photos, music, movies and programs, any and all of which you *can* use whenever you want. The more hard drive capacity you have, the more stuff your computer can permanently store. Hard drives have incredible capacity but they are very, very, very slow. They are slow because they have mechanical moving parts that have to physically spin around to access your data. It's a tradeoff.

RAM, on the other hand, contains what your computer *is* working on *right now*. It's like temporary storage for your computer's current needs. Unlike a hard drive, RAM has no moving parts and its speed is only limited by the speed that electricity can flow through wires and that logic chips can act fast enough to control it. In other words, it's way faster than a hard drive. Unfortunately, it also has much less capacity than a hard drive. This low capacity can be a problem.

If you are running a heavy workload on your computer, it's possible that not everything you're working on will fit inside your RAM. If this happens, then some of what you're working on will spill over to your hard drive (which will definitely have enough space). This spilling over effect makes your computer *feel* very, very, very slow because your hard drive *is* very, very, very slow. This is what is going on when most people say their computer "feels slow." It feels slow because it *is* slow.

So what's the solution? The solution is to buy *enough* RAM. "Enough" is the key word here. You need to buy enough RAM to fit all of the programs and movies and photos you want to work on at the same time without spilling over into the hard drive. Buying any more than just "enough" RAM will probably be a waste of money, because that extra RAM will go unused. But how much is "enough?" Well, I can't tell you exactly how much you personally will need, but I can give you some good general guidelines that should suit the Average User.

If you are buying a new computer right now (April 2011) I would recommend to not get less than 3GB (giga bytes) of RAM. Any less than this and you will probably run into that "slow feeling" occasionally during normal use. 4GB of RAM would be even better, but if you are buying a system that you want to last more than 2 years, I would recommend getting a computer with 6GB or 8GB of RAM. The good thing about buying more RAM is that it's a pretty cheap upgrade that can go a long way toward making your computer "feel fast." Buying 12GB or more is probably overkill at this point in time, but if the price is right or you expect you will use it (like if you are a graphics or movie editing professional) then it's probably worth it.

Of course there are many aspects to a computer that consumers need to be aware of when choosing what to buy, and I've only scratched the surface here. I feel like I did start with the most important aspect, though. Buying "enough" RAM (whatever that means) is the best thing you can do for making your computer feel fast, and is honestly the first thing you should look at on a specifications sheet when shopping for a new computer. Don't skimp!

Monday, April 4, 2011

CS THEORY: Variables and memory

The last time I used the tag "CS THEORY" I didn't really talk about CS theory at all, did I? All I talked about is that there are memory cells and they have numbers in them. That's fine, but it didn't quite make it into the realm of CS theory. In order to do that, we need to talk about what a memory can DO, not just what it is.

As far as "what it is" goes, it's just as I've already said. It's a giant list of cells, each of which can each hold a number. That's not very interesting. What's more interesting is how the numbers get there, and what happens to them once they are there. There are two interesting aspects of memory cells that I'm going to talk about today.

First, memory cells are useful because they each have a unique identifier, and that makes it possible to not get mixed up about what numbers you're storing where. In the memory of a computer, each memory cell has a unique number associated with it called an "address." In a typical computer today its memory will have addresses 0 through about 4 billion. This means there are 4 billion different memory cells where you could store a number. Every time you talk about memory cell 2,361 you're going to be talking about the same memory cell. It didn't go anywhere since the last time you used it.

Second, memory cells in a computer are useful because they are reliable. If you put a number into a memory cell, it will stay there forever, or until you put a different number there. You don't need to worry about the contents of the memory cell accidentally disappearing. That doesn't happen. If it did randomly happen that your data could just disappear, then you wouldn't have a very reliable or useful computer. You couldn't trust it to do anything correctly. Computers are built upon the assumption that this doesn't happen, and that you can always get out of a memory what you put in earlier.

These two properties of computer memory allow us to do real work with our computers. In programming languages that are used to program computers, we often use variables to represent memory cells. Instead of talking about "memory cell 2,361" the programmer will just type "X" (or any other name he dreams up) and it means the same thing. I just pulled the number 2,361 out of the air. It doesn't matter what the address is.

In fact, the programmer doesn't even need to ever know what real address variable X refers to. The programmer can just logically reason about made up variables like X and Y and Z, and while ultimately in the computer these variables will stand for memory cell addresses, the programmer doesn't ever need to think about that. The programmer can type "Add X and Y and store the result in Z," and that might get translated by the computer into "add the contents of memory cell 2,361 and memory cell 7,841 and store the result in memory cell 451." This is called abstraction. The programmer thinks about pretend variables and lets the computer worry about how it will physically carry out the math the programmer has asked it to do by manipulating real memory cells that are physically somewhere in the computer.

Today we talked more about computer memory, how every cell in a computer memory has an address, and how what you put into a memory will stay there and won't just disappear on you. These properties make it very convenient to write computer programs, even without having to know how memory cells really work. Programmers can just abstract away all those complicated details and play with raw, abstract variables instead.

I think for my next post I will give some consumer advice. Next time we talk about CS theory I think I will talk about C-like assignment statements, conditional statements and loops.