36

My coworkers and I have been bending our minds to figuring out why anyone would go out of their way to program numbers in a base other than base 10.

I suggested that perhaps you could optimize longer equations by putting the variables in the correct base you are working with (for instance, if you have only sets of 5 of something with no remainders you could use base 5), but I'm not sure if that's true.

Any thoughts?

15
  • 6
    Do you have a specific example that raised this question? Things that are in base-2 or base-16 obviously have their benefits since it's easier for a computer to understand.
    – KDiTraglia
    Oct 18, 2012 at 15:47
  • 4
    What's "programming numbers in base ..." supposed to mean? There are numbers. Period. They're internally represented in some base but that mostly doesn't matter, and does not change any arithmetic rules.
    – user7043
    Oct 18, 2012 at 15:47
  • 12
    @JMD - please work with the moderators to to remove one of your two cross-postings and have one placed here in P.SE. Cross-posting across sites is frowned upon. The mods can migrate questions for you instead.
    – user53019
    Oct 18, 2012 at 19:11
  • 10
    @JMD - Cross posting is still not something you should do. There is a migration process for such questions, if needed.
    – Oded
    Oct 18, 2012 at 19:17
  • 2
    @JMD Do not cross post, a question being suitable for more than one site is extremely rare. This time for example, your question was off topic on Stack Overflow. But even if your question was suitable for both sites, shopping your question around sites is generally frowned upon. We are all volunteering our time here, you could have at least waited for a while to evaluate the answers you were getting on Stack Overflow before cross posting.
    – yannis
    Oct 18, 2012 at 19:26

16 Answers 16

59

The usual reason for writing numbers, in code, in other than base 10, is because you're bit-twiddling.

To pick an example in C (because if C is good for anything, it's good for bit-twiddling), say some low-level format encodes a 2-bit and a 6-bit number in a byte: xx yyyyyy:

main() {
    unsigned char codevalue = 0x94; // 10 010100
    printf("x=%d, y=%d\n", (codevalue & 0xc0) >> 6, (codevalue & 0x3f));
}

produces

x=2, y=20

In such a circumstance, writing the constants in hex is less confusing than writing them in decimal, because one hex digit corresponds neatly to four bits (half a byte; one 'nibble'), and two to one byte: the number 0x3f has all bits set in the low nibble, and two bits set in the high nibble.

You could also write that second line in octal:

printf("x=%d, y=%d\n", (codevalue & 0300) >> 6, (codevalue & 077));

Here, each digit corresponds to a block of three bits. Some people find that easier to think with, though I think it's fairly rare these days.

1
45

The main reason I use different bases is when I care about bits.

It's much easier to read

int mask=0xFF;
byte bottom_byte = value & mask;

than

int mask=255;
byte bottom_byte = value & mask;

Or image something more complex

int mask=0xFF00FF00;
int top_bytes_by_word = value & mask;

compared to

int mask=4278255360; //can you say magic number!? 
int top_bytes_by_word = value & mask;

It's very clear here what the intent is with the hex examples because hex is basically just a more compact form of binary... In contrast, base-10 (what we use) doesn't map nearly as well to binary.

0xFF = b11111111 = 255
0xFFFF = b1111111111111111 = 65536
0xF0F0 = b1111000011110000 = 61680

There are also other bases you can use in some languages. You will find very little use of bases other than binary, hex and decimal.. Some odd people still use octal, but that's about the most esoteric you'll see in a sane program.

12
  • 2
    Octal is not rare at all, 0 is octal :) (saw that somewhere on the Stack Exchange network, can't find it now).
    – gerrit
    Oct 18, 2012 at 20:42
  • 2
    @Earlz: people with a lot of fingers. :-) Oct 18, 2012 at 20:43
  • 3
    26 x 2 + 10 = All capital and lower-case letters and all numbers. Not really that unusual. I've also seen Base 36 used, which is just the non-case-sensitive version of same. Oct 18, 2012 at 21:46
  • 3
    @vasile: There is 60 minutes in an hour and 60 seconds in a minute because people were using base-60 systems, not the other way around. I hope you don't believe that there is something in nature that says there must be 60 minutes in an hour!
    – Joren
    Oct 19, 2012 at 7:57
  • 1
    yes, they read it in the stars and they used base-60 because the measuring of time. with 360 days (=6x60) a year it's not that crazy to measure time in base-60.
    – ytg
    Oct 19, 2012 at 9:50
8

As you probably know, computers are based on binary - this is base 2.

It is easy to convert between base 2 and 4, 8 and 16 (and similar multiples of 2), and keeping this translation in the source code can make working with numbers a lot easier for to reason about.

For low level languages such as Assembly and C, this can translate directly to processor operations (bit shifting for division and multiplication, for example), meaning that using these number bases ends up with much faster code.

Additionally, not all operations are numeric operations - there are bit maps where you do need to fiddle with the bits directly - using a base 2 or one of the multiples of it to do so makes the operations much easier.

If you wish to learn more, I recommend reading Code by Charles Petzold.

4
  • 3
    The compiler doesn't give a damn. While it is indeed easier to convert between the bases you list, a simple (slow-ish) conversion for base 10 specifically isn't hard either, and most languages useful for compiler construction (you don't use assembly for that) have that conversion available in their standard library, so it's effectively free for compilers.
    – user7043
    Oct 18, 2012 at 19:14
  • 1
    Using hexadecimal in C doesn't translate to faster programs. The compiler doesn't care what base you use. Oct 18, 2012 at 19:21
  • 5
    No matter what base the program is written in, the compiler translates it to binary at compile time. The assembly instructions are identical. Oct 18, 2012 at 22:03
  • 2
    Enterprise computers are in fact based on a tri-enery bool: true, false and "file not found" Oct 19, 2012 at 3:20
6

Perhaps if you were writing a game which simulates the economy of some ancient civilization that uses a base 12 system.

0
4

Outside of highly specialized programs, it's pretty rare to use bases other than 10, 16 or 2.

Base 16 (hexadecimal) is useful simply because the full range of a byte (0-255) can be represented in two digits (0x00-0xFF), which can make working with raw hex-dumps or binary data a lot easier. Hexadecimal is also useful when using bit masks with bitwise operators, because the two-digits to a byte correspondence helps with readability.

More rarely, base 2 (binary) can also be used with bitwise operations, but many programming languages don't support base-2 literals, and anyway hexadecimal is much more concise and readable.

Base-8 (octal) is also sometimes used because of UNIX file permissions. Other than that, it's pretty rare to use bases other than 10 outside of highly specialized mathematical contexts.

1
  • Octal is often used to specify character values and sometimes to dump binary data.
    – Caleb
    Oct 19, 2012 at 13:58
3

The most common valid reason to use other bases has to do with ease of conversion to base 2: it is trivial to convert a base-8 or a base-16 number to binary without using a calculator by memorizing a short table of eight or sixteen numbers:

 0000 0     0001 1     0010 2     0011 3
 0100 4     0101 5     0110 6     0111 7

 1000 8     1001 9     1010 A     1011 B
 1100 C     1101 D     1110 E     1111 F

This opens up multiple possibilities:

  • When a number represents a composition of meaningful binary numbers, you can determine the individual components without a computer. For example, if a 24-bit number represents a color in RGB, it is trivial to tell that 0xFF00FF is magenta (Red+Blue); the task is much harder when you are presented with 16711935
  • When a number represents a bit mask, it is more practical to write it down as a compact hex number, rather than a much longer binary number
  • Certain architectures went out of their way to make their binary code easy to read when printed as octal numbers. PDP-11 was one such system: the most significant bit would let you tell 8-bit operations from 16-bit ones; the last two octal groups would let you tell the two registers involved in the operation, and so on. I knew several people who could read PDP-11 binary code off the screen without a disassembler, but they needed the machine code to be printed in octal system.
2

The computer (or more accurately the compiler) doesn't really care at all what number base you use in your source code. Most commonly used programming languages support bases 8 (octal), 10 (decimal) and 16 (hexadecimal) directly. Some also sport direct support for base 2 (binary) numbers. Specialized languages may support other number bases as well. (By "directly support", I mean that they allow entry of numerals in that base without resorting to mathematical tricks such as bitshifting, multiplication, division etc. in the source code itself. For example, C directly supports base-16 with its 0x number prefix and the regular hexadecimal digit set of 0123456789ABCDEF. Now, such tricks may be useful to make the number easier to understand in context, but as long as you can express the same number without them, doing so - or not - is only a convenience.)

In the end, however, that is inconsequential. Let's say you have a statement like this following:

int n = 10;

The intent is to create an integer variable and initialize it with the decimal number 10. What does the computer see?

i  n  t     n     =     1  0  ;
69 6e 74 20 6e 20 3d 20 31 30 3b (ASCII, hex)

The compiler will tokenize this, and realize that you are declaring a variable of type int with the name n, and assign it some initial value. But what is that value?

To the computer, and ignoring byte ordering and alignment issues, the input for the variable's initial value is 0x31 0x30. Does this mean that the initial value is 0x3130 (12592 in base 10)? Of course not. The language parser must keep reading the file in the character encoding used, so it reads 1 0 followed by a statement terminator. Since in this language base 10 is assumed, this reads (backwards) as "0 ones, 1 tens, end". That is, a value of 10 decimal.

If we specified a value in hexadecimal, and our language uses 0x to specify that the following value is in hexadecimal, then we get the following:

i  n  t     n     =     0  x  1  0  ;
69 6e 74 20 6e 20 3d 20 30 78 31 30 3b (ASCII, hex)

The compiler sees 0x (0x30 0x78) and recognizes that as the base-16 prefix, so looks for a valid base-16 number following it. Up until the statement terminator, it reads 10. This translates to 0 "ones", 1 "sixteens", which works out to 16 in base 10. Or 00010000 in base 2. Or however else you like to represent it.

In either case, and ignoring optimizations for simplicity's sake, the compiler allots enough storage to hold the value of an int type variable, and places there the value it read from the source code into some sort of temporary holding variable. It then (likely much later) writes the resulting binary values to the object code file.

As you see, the way you write numerical values in the source code is completely inconsequential. It may have a very slight effect on compile times, but I would imagine that (again, ignoring such optimizations such as disk caching by the operating system) things like random turbulence around the rotating platters of the disk, disk access times, data bus collisions, etc., have a much greater effect.

Bottom line: don't worry about it. Write numbers in a base that your programming language of choice supports and which makes sense for how the number will be used and/or read. You spent far more time reading this answer than you will ever recover in compilation times by being clever about which number base to use in source code. ;)

1

why anyone would go out of their way to program numbers in a base other than base 10.

Here are some reasons that did not already appear...

x00 - Some OSs and hardware devices' APIs expect the arguments to be in hex/binary. When you code for such APIs, it is easier to use the numbers in the same format as the API is expecting instead of converting it between different bases. For example, to send an end of message byte to a server or to send a message to close a connection to a communication channel.

x01 - You may want your application to represent characters not available at certain keyboards such as the copyright sign (\u00a9).

x02 - To have some constants/literals persist (visually) across different culture settings, specially when the source code/files be moved across developers with different local settings.

x03 - To make their code look confusing and complex - Good thing is that C# does not support octal constants!

1

The key issue is representing a single word of computer size in a reasonable way. The 6502 was an 8 bit processor. The 4004 was a 4 bit processor.

When dealing with a 4 or 8 bit number works nicely. A 4 bit number is a single hexadecimal character. A 8 bit number (a byte) is two hex digits. Systems that have a power of 2 sized word are the commonly seen standard today - 16 bit, 32 bit, 64 bit. All of these divide by 4 nicely for representation as hexadecimal.

Octal (base 8) was used in systems where the word size was 12, 24, or 36. The PDP8, IBM Mainframe, and ICL 1900 of days of old used these. These words were more easily represented using octets rather than a limited range of hexadecimal (yes, they also divide into 4 too).

Apparently there was also a cost savings with using base 8 numbering. Representing 12 bits in BCD, the first digit can only be 0-4 but the second, third, and fourth may be 0-9. If this was done as hex, one has 3 hex characters, but each one has 16 possible values. It was cheaper to produce a nixie tube that only had 0-7 than one that had 0-9 (with additional logic for BCD) or 0-F for hexadecimal.

One still sees octal today with unix file permissions (755, 644) where owner, group and world each have 3 bits representing the permissions.


In the mathematics world, one occasionally does some odd things with different bases. For example, a weak Goodstein sequence from project euler 396... or something simpler with palindromic numbers. There is the property of a number in base N that a number which is a multiple of N - 1 will have its digits sum up to a multiple of N - 1. Furtermore, if N - 1 is a perfect square, this property also exists for sqrt(N - 1). This has some applications in certain mathematical problems.

3
  • 1
    Octal was because the PDP had 9/18bit bytes, an octal number represents 3bits so if you byte is divisible by 3 it makes a lot of sense Oct 19, 2012 at 3:21
  • 1
    Octal was also used on some 16-bit systems (most notably the PDP-11), because 15 - the number of bits except the sign bit - divides nicely into 3. It was broadly used across the original UNIX operating system (for example, "od" is the standard tool to dump binary files, and its default format is 16-bit octal rather than 8-bit hex), not just for permissions. It also may be relevant that the PDP-11 instruction set had two 6-bit operand fields.
    – Random832
    Oct 19, 2012 at 12:13
  • Octal was also used because it could displayed on the technology at the times. Nexi tubes, anyone? Or other 0-9 displays? It took awhile for A-F displays to show up. Oct 19, 2012 at 23:45
1

In the financial industry, there is an identifier scheme that is effectively base 36. It uses the numbers 0-9 and letters B-Z to represent digits valued 0-35. It skips the vowels to prevent any obnoxious names from being generated.

It's not perfect, however. There was a time when one unfortunate company had the id B000BZ.

1

Reason #1: because all numbers at the circuit level are represented in base-2 (electrical switch is on or off). Reason #2: because at one level higher than the actual circuits, bits are grouped into bytes, and bytes can be easily represented as two hexadecimal digits, when it would take 3 decimal digits (and some validation) to represent all possible values of the byte.

So, if you are working at these levels (or approximating them, in some managed environment), it is easier to work in binary or hexadecimal than decimal. The situations in which you would do this are varied, but are typically never situations where you just need basic arithmetic.

1

One area where base 16 (hexadecimal) numbers are used very frequently is in specifying color, especially when using HTML/CSS for the web. The colors we use on digital displays are specified using a combination of 3 intensity values for 3 "base" colors (RGB - red, green, blue) that are blended together to create any of the 16 million displayable colors (using 24-bit color).

For example, full intensity green in hex would be 0x00ff00 and 65280 in decimal. Now imagine trying to "manually" mix a color in your head that has equal parts red and blue, say at half intensity, to create a nice purple :) In hex this would be written simply as 0x800080 while the decimal value for this would be 8388736. It gets even easier when working with shades of grey - 50% grey is 0x808080 (hex) and 8421504 (decimal), 75% is 0xC0C0C0 and 12632256, and so on.

Using hex is much more intuitive and anyone familiar with this use of color will immediately be able to "guess" the color just by looking at the hex value. It is also a lot less error prone to use if you need to use the same color multiple times (which is usually the case).

Check out any web page (and in particular the CSS) for a crazy amount of hex usage :D

NOTE: In CSS the hex values are written using a # prefix, for example: #00ff00 for green, and is also sometimes shortened to just three digits, such as #0f0 for green.

0

For some algorithms, base 2 makes more sense than anything else. For example, would you rather write a function to traverse a binary tree, or a 10-ary tree?

But, more frequently, base 2 is used because that's how computers almost universally represent their numbers. This means that:

  • many operations are more efficient in base 2:
    • multiplication, division, and modulo powers of 2 are much faster than general division
    • flags and small values can be stored, retrieved, and manipulated more efficiently as binary digits of a larger number.
  • operations that read, write, and manipulate data files and network data streams must deal directly with the fact that they are represented as binary numbers.

Also, there is always the rare application that inherently requires an odd base which may be neither 2 or 10.

1
  • 2
    Of course I'd use a 10-ary tree. What's this weird 2 character you're using? Oct 19, 2012 at 12:32
0

It's honestly preference, if for some reason you've got polydactyly and have 11 fingers or like counting with your toes so you like working in base 20 it's honestly up to you. But realize that on a universality topic that most of us that have to deal with bits and bytes on a daily basis will be really ticked if we get something that's doing bit manipulation in base 19.

REASONS FOR BASE x

Base 10 - Model of all of our stuff because we've got 10 counting digits (feet are weird and smelly so we don't use those).

Base 2 - Computers use this for bits (on/off) this is related to readable voltage levels being propagated by gates/transistors/capacitors.

Base 8 - Old, back when computers weren't super huge (or back when they were space wise) this was good for something or other (i don't like it one bit)

Base 16 - Good for showing upper and lower nibbles of a byte for bit manipulation. This is super useful in the embedded/fpga/hardware world.

NORMAL BASES IN COMPUTERS

To go with preference, I could tell you exactly how "on" a color is in a hex RGB value that's given to me is, this consequently can be represented in a single int in hardware and then with some shifts can be given back to me easy-peasy, 1 complex color = 1 data point that's nice for large image processing with limited memory. Compare that to a base 10 representation, you could add them all and store them in a number, but which number is which, or maybe R is time 10000, G is 100, and B is its own space, that's a lot of math operations, usually multiplications cost more cycles than a shift, so your next data piece is already in queue before your done with your last piece being processed, whoops, that's gone now.

Sometimes it's just better to work in base 2, 8 or 16. With most machines a multiply by 2 is just a bit shift, those are super speedy, same with a divide by 2.

To expound even further on the idea of bit twiddling. There are a large number of times when working in an embedded environment that I've needed to access some array of lights, switches, or some other register mapped items.

In this case assigning an entire char, byte, or int to each switch would be both inefficient and silly, a switch or light has 2 positions - on and off - why would I assign something that has up to 256 positions, or 2^16 positions etc. Each light in an array could be 1 bit fitting 8 or 16 or 32 or 64 or 128 (width of your datatype) on a single word/register. The space efficiency is needed and rather welcome.

Using anything that's base 2^n in programming for things like handling RGB data, lots of signal data - GPS's, audio, ascii, etc - is much simpler in hex, binary, and octal since that's how it's represented in the machine and one can more easily discern what's being presented and how to manipulate it.

USING STRANGE BASES

There is no efficiency unless you code for it. You want base 11, you've gotta set up a data-type for it and overload any operators to handle its representation to the user. I see no reason why a system holding 5 items, and only ever holding multiples of 5 items would need to be converted to the five item math. And further, you'd better pray that whomever decided to write their code for base 271 documented it well or you could spend more time understanding it than is worth in creating base 271 because all of the items are a multiple of 271.

0

Back in the ancient days of computers, we had a number of displays that could show the digits 0-9, but we didn't have A-F yet.

http://ad7zj.net/kd7lmo/images/ground_nixie_front.jpg is one such example...

Octal fit real nicely on these displays and was easier than binary or decimal.

0

I'm surprised all of the other answers haven't mentioned two very common uses in computing for alternate bases:

  1. Encoding: Base64 encoding for example is extremely common. Encoding simply interprets a series of bytes as a large binary (base-2) number and converts that number into a Base64 number represented by ASCII digits.
  2. Compression: It's often desirable to represent a binary, decimal or hex number in a larger base in order to shorten the representation. For example, all the bit shorteners like bit.ly are doing this. Or you might do it to shorten a GUID for use in a URL.

    - 821F6321-881B-4492-8F84-942186DF059B (base-16 guid) 
    becomes
    - RRIDHW463YD8YXX7MIDI (base-36)
    - 3UFmaWDjj9lifYyuT0 (base-62)
    

Not the answer you're looking for? Browse other questions tagged or ask your own question.