No such thing as "decimal to binary" or "binary to decimal" conversion

There is no such thing as converting binary to decimal, or vice versa.

First, a couple of definitions.

A number is, you know, how much or how many of something. Three bananas, or three computers, or three Snap! projects: all of those are part of what three means.

A numeral is the representation of a number as text. Usually that means positional notation in some base: decimal or binary or hexadecimal or something else. But it can also be Roman numerals, or Cuneiform, or whatever.

Now we have to talk about levels of abstraction. Namely, as far as we are concerned as programmers, what's inside the computer are numbers. Below the hardware abstraction, there are voltages on wires, and so on. But only electrical engineers know about those things. For us, the hardware has numbers inside it. Don't object yet, bear with me and see where this takes us. You can object later if you still want to.

There are only two relevant kinds of conversion: numeral to number, and number to numeral. The first of those is how the computer deals with input from the user. The user types in a string of characters, namely, digits in some base or other, 0-9 or 0-1 or 0-9a-f, or if we're converting a base three numeral to a number, digits 0-2. The other direction is used for output to the user. There's a number inside the computer, and it wants to show it to a human being, so it has to convert the number into a text string full of digits in the appropriate base.

This simple, lucid, perfect understanding -- computers understand numbers, human beings understand numerals -- is complicated (in people's minds; the computer understands it perfectly) by the fact that computers have to show numbers to human beings, and computers have to allow people to tell it numbers. But human beings don't understand numbers, so the computer has to translate to and from numerals. And in particular, a programming language has to do that.

So, in your favorite programming language, when you see
that doesn't mean that inside the computer, in the variable FOO, there's an "8" and a "7." No, what's in that variable is the number eighty-seven. Actually, what's inside the computer is a bag with eighty-seven marbles in it (really tiny marbles), in a cubbyhole with a piece of paper saying "foo" taped to it. But you, a mere human being, wouldn't understand if the variable watcher had a bag of eighty-seven marbles in it. Snap! has to show you an "8" and a "7"; that is, it has to convert the number (a bag of marbles) into a numeral (a text string).

Because of this, when I tell you that Snap! has to convert the value of FOO from number to base-10 numeral, you think, "it's already a base-10 numeral! See, there it is, on the stage." Yes, but in a sense the variable watcher is lying to you; there's no string of digits in FOO.

Furthermore, like some other programming languages but not most of them, Snap! does automatic conversion between numbers and numerals, depending on the domain of the function you call. So, FOO is a number. You're expected to say something like untitled script pic (2), in which case the computer will count out another bag of eighty-seven marbles, then put in four more marbles, producing a bag of ninety-one marbles. But Snap! also lets you say untitled script pic (3). JOIN expects text strings as inputs, and concatenates them. But it can't concatenate the string "th" to a bag of marbles. First, implicitly, it has to construct the string "87" to represent the number in human-readable form, then it can do what you asked for, namely, concatenate "th" to that string. This automatic conversion is super convenient, but it doesn't help you understand that there's a difference between a number and a string of digits.

As an exercise to help you understand this, try defining the following procedure:
untitled script pic (7)

untitled script pic (8)

untitled script pic (9)


Now it should be clear to you that the variable BAR contains a string of characters, not a number. You can sensibly write a procedure to translate that string of digits to a number, ignoring the "x" at the beginning and at the end. (I put them at both ends because it makes it equally easy to write procedures that read the digits from left to right or from right to left.)

Okay, I'm going to write procedures
untitled script pic (2)

untitled script pic (11)

If you want to write them yourself, stop reading here!

To take care of a minor detail first, if we happen to be using a base larger than ten, we have to deal with using letters as digits, a=ten, b=eleven, and so on. So, here are helper procedures for that:

And in the other direction:

Note that I'm bending over backward not to use implicit conversion between small integers and digit characters. That is, I could have said
untitled script pic (17)
relying on Snap! to convert the value three into the numeral "3" when needed. But I'm trying to keep crystal clear what the computer actually has to do in order to accomplish that conversion. In the old days, those of us who implemented programming languages or operating systems had the ASCII codes for "0" (0o60), "A" (0o101), and "a" (0o141) memorized. (We thought in octal, not hex, because our computers were 36 bits wide.) So we didn't have to call untitled script pic (18) and so on.

Okay, that took up enough space to give the people who want to write the conversion procedures time to look away. Here we go:

Don't forget:
untitled script pic (8)

This version of NUMERAL➞NUMBER is implemented the cool way, which involves peeling off the rightmost digit of the numeral, and sending the rest of the numeral (all but the last digit) to NUMERAL➞NUMBER recursively, multiplying the result by the base, whatever it is, to account for the fact that that smaller numeral is shifted left one place in the overall numeral.

The math ed experts at EDC tell me, unanimously, that kids, even teenagers, find this recursive algorithm hard to understand. So, feel free to write a version that multiplies each digit by a power of the base corresponding to its position in the numeral.

But please note that this procedure rigorously respects the domain and range of every subprocedure it uses. For example, since NUMERAL➞NUMBER reports a number, it's okay to multiply the result of the recursive call by BASE, an arithmetic operation. But since functions such as ALL BUT LAST LETTER take a text string as input, it's okay to use NUMERAL, which is a text string, as input to them. It wouldn't be okay, for example, to multiply NUMERAL by BASE.

Time for the inverse function.

I used 5+7 as the input to make it clear that the input is a number, the result of an arithmetic operation, not a string of digits. What the procedure reports, though, is a string of digits (as you can tell by the nondigit Xs in it).

There's a non-recursive way to do this, also, but it's too horrible to contemplate. Try it if you like.

So, what would "decimal to binary" actually mean? This:

Take a base ten numeral (a string of digits), convert it to a number (which has no base; it's a bag of marbles), then convert that number to a numeral in base two. Binary to decimal would be the same code but with the 10 and the 2 swapped.

People think that "decimal to binary" and "binary to decimal" are two different algorithms because Snap! lets them think that a number is the same thing as a decimal numeral. So they write

Compare this with the correct version above. Similarly, for binary to decimal, they leave out the step of converting the number to a decimal numeral.