Base Converting and Binary Operators

This article discusses PHP’s binary operators and how to convert between different counting systems. Most programming books and articles only dedicate a page or two to such topics, and although using the operators is really quite simple, there’s a fair amount of background knowledge one must have to use them correctly.

Instead of giving the same bare-bones treatment that every other reference gives, I’ll first provide you the necessary background in number theory. Armed with that knowledge, you’ll be able to understand the binary counting system and base conversions… and familiarity with binary digits is the key to successful use of the binary operators! So without further delay, let’s get started!

Number Theory

The counting system with which we’re all familiar can be thought of as a series of packages and containers. Each package is worth one unit and is bundled together with other packages and placed in an appropriate container. Each container can only hold a certain amount of units and the units must be packaged into proper packages for that container.

In our Base-10 counting system, units are bound together in multiples of 10. That means we can have up to nine single units, but once a 10th unit is added they all must be packaged together to make a single bundle.

Base Converting and Binary Operators 1

There are no surprises there, but the magic lies within the containers. Let’s place a series of buckets side by side and restrict ourselves to filling only the right-most containers. Once one bucket is full, its units are bundled up and moved to the neighboring container. That is, the right-most container can only hold nine single units. A 10th unit would be bundled with the first nine and the whole bundle is moved to the container to its left.

Base Converting and Binary Operators 2

Each container can only hold nine of whatever size packages it holds. The right-most container can only hold nine units before they get bundled. The container to its left can only hold 9 bundles. A 10th bundle gets rebundled together and moved the neighboring container. As the containers continue to fill up, the cycle repeats itself; the container to the left can always hold nine bundles of whatever the right container can hold.

The base-10 counting system we’re most familiar with is called decimal, but other counting systems exist. The key is that the limit of each container is one less that of the base. For example, the limit of each container in an octal counting system (base-8) is 7. In hexadecimal (base-16), each container holds 15 units. In hexadecimal, the letters A through F are often used to represent the quantities 10 through 15.

In binary (base-2) each container is limited to one unit or bundle.

Base Converting and Binary Operators 3

Since each container is limited to one unit or bundle, a value that makes up a binary number can only be a one or a zero. It is either full (a value of one) or empty (a value of zero). When the string of container values is written out it can resemble a series of checkmarks as if on a list: 1 can be considered a checkmark and 0 is the absence of a check.

Base Converting and Binary Operators 4

Conversion Functions

Converting values from one base to another can be tedious if done manually depending on the size of the value. To help make life easier, PHP has several built-in functions which can be used for the conversion of numbers from one base to another: decbin(), bindec(), decoct(), octdec(), dechex(), hexdec(), and base_convert().

The decbin() function accepts a decimal format number and returns a string representing the binary equivalent. The counterpart function bindec() accepts a string representing a binary number and returns the decimal value.

The decoct() function accepts a decimal format number and returns a string representing its octal equivalent. Its counterpart octdec() accepts the string representation of an octal value and returns the decimal number.

dechex() accepts a decimal value and returns a string representation of the hexadecimal value; hexdec() accepts a string representing a hexadecimal number and returns the decimal equivalent.

<?php
$num = 21;

echo "Decimal value: $numn";

echo "Binary value: " . decbin($num) . "n";
echo "Octal value: " . decoct($num) . "n";
echo "Hexadecimal value: " . dechex($num) . "n";

In the code above, a decimal value of 21 is stored in the variable $num. The functions decbin(), decoct(), and dechex() are used to display the binary, octal, and hexadecimal equivalents; the binary value is 10101, the octal value is 25, and the hexadecimal value is 15.

The base_convert() function is used to convert between arbitrary bases. It accepts two arguments, the first is the original base and the second is the desired base. Let’s assume a particular program needs to convert base-7 and base-11 values; there are no convenience functions to perform these tasks, so base_convert() is used.

<?php
$num = 21;

echo "Decimal value: $numn";

echo "Base-7 value: " . base_convert($num, 10, 7) . "n";
echo "Base-11 value: " . base_convert($num, 10, 11) . "n";

The base-7 value of decimal 21 is 30, and base-11 is 1A.

Granted, base-7 and base-11 certainly seem strange, but they do illustrate how base_convert() works. Perhaps more realistically you’ll find yourself using base_convert() to convert directly between binary, octal, and hexadecimal values when a convenience function isn’t available.

<?php
$octNum = 25;

echo "Octal value: $octNumn";
echo "Binary value: " . base_convert($octNum, 8, 2) . "n";

Bitwise Operators

Back in the number theory section you saw that each binary container could either be full (have a value of one) or empty (a value of zero). Each package that fills a container we call a “bit”.

Bitwise-And

The bitwise-and operator is an ampersand (&). It accepts two values and logically ands their binary values. Consider the following example:

Base Converting and Binary Operators 5

The bitwise-and operation takes the binary representation of two numbers and returns a number constructed based on which fields both hav a value of 1. 5 & 3 = 1 since both binary representations only have a 1 value in the right most location.

Bitwise-Or

The bitwise-or operator is a pipe (|). It accepts two values and logically ors their binary values.

Base Converting and Binary Operators 6

The bitwise-or operation takes the binary representation of two number and returns a number constructed based on which fields at least one of have a value of 1. 5 | 3 = 7 since between the two binary representations have a 1 value in each location.

Bitwise-Exclusive Or (XOR)

The bitwise-xor operator is a caret (^). In contrast to the bitwise-or where a 1 is returned for a particular bit so long as at least one of the bits is set, the bitwise-xor will only return one if only one of the bits are set.

Base Converting and Binary Operators 7

The bitwise-xor will only return one if only one of the bits are set. If neither of the bits are set, or if both bits are set, zero will be returned. 5 ^ 3 = 6.

Bitwise Compliment

The compliment operator is a tilde (~). It flips the bits in a value so that positions that were 1 would then be 0, and positions that were zero would then be 1.

Base Converting and Binary Operators 8

Since the compliment switches the values of bits from 1 to 0 and from 0 to 1 in the binary representation of a value, ~5 = 2.

Masking with Binary Operators

We also briefly saw earlier how binary numbers can be used as a type of checklist; PHP’s bitwise operators can prove helpful in manipulating and masking these tallies by working with each bit.

<?php
// people and values from previous chart
$people = array(
    "Joe" => 3,
    "Ned" => 20,
    "Sally" => 14
);

// mask values if person has certain animal
$mask = array(
    "rabbit" => bindec("00001"),
    "dog" => bindec("00010"),
    "cat" => bindec("00100"),
    "bird" => bindec("01000"),
    "snake" => bindec("10000")
);

foreach ($people as $person => $value) {
    // who has a pet dog?
    if (($value & $mask["dog"]) == $mask["dog"]) {
        echo "$person has a dog.n";
    }
    // who has a snake
    if (($value & $mask["snake"]) == $mask["snake"]) {
        echo "$person has a snake.n";
    }
    // who does NOT have a cat?
    if ((~$value & $mask["cat"] ) == $mask["cat"]) {
        echo "$person does not have a cat.n";
    }
    // who has both a cat and a bird?
    if (($value & $mask["cat"] + $mask["bird"]) == $mask["cat"] + $mask["bird"]) {
        echo "$person has both a cat and a bird.n";
    }
}

The example assigns the data from the pet survey chart you saw earlier into an array with the name $people. A mask value is then assigned for each animal based on its position in the survey chart. The resulting binary string is converted to a decimal number using bindec(). The values are stored in the array $mask.

A foreach loop cycles through each element person and tests for various conditions we’ve set. Each condition uses binary operators to mask out the values we don’t want. If the isolated value matches the value of the mask, it means the survey results matches the criteria we’re looking for. It’s important watch the order of operations though and use parenthesis to ensure the operators work on the correct data.

Summary

This article definitely covered a lot of material! I provided you with a look at how counting systems are structured, showed you how to convert between various number system, and then how to use binary operators. The article concluded with a simple bit-masking example to pull everything together. Hopefully now you’ll be able to successfully incorporate these seemingly tricky concepts in your scripts with ease!

Image via Fotolia

Win an Annual Membership to Learnable,

SitePoint's Learning Platform

  • robh

    When I was first programming (about 1978) memory (32KB), disk (1MB 8 inch floppy disk) and processing power were all very limited and there were a lot of simple but fast and powerful things we could do at bit twiddling level. I miss them in more recent languages. In addition to the bitwise ops you describe we would use bit shift right or left as a crude but fast multiply/divide by 2. Also the language allowed us to remap a byte into bits or groups of bits each with its own variable name allowing for compact storage: need a loop counter to handle value of 0-31? Remap a byte to counter=5 bits and you’ve got 3 bits “spare” you can use as maybe binary flags.
    I used something like this fairly recently…
    if ($icons & 128) echo “Google”;
    if ($icons & 64) echo “Twitter”;
    if ($icons & 32) echo “Facebook”;

  • Luis Cunha

    This is madness..

  • http://www.olivertwistor.nu Johan Nilsson

    I understand that one needs bitwise operators in low level programming, e.g. when doing hardware programming. But why would one dabble with them in a high level language like PHP, other than just for fun? I don’t get it.

    • Chris

      Bitwise operators are very useful when it comes to a complex rights management… assume dog, cat etc. are different user levels like moderator, administrator etc. or just access to page types. In this case you can easily check if a user is allowed to view or better… has the needed rights.

  • rocky

    this is FABULOUS…work …great work work guys..kept on.