Thursday, May 22, 2008
Adding 1 to a binary number in sed
I have an odd fascination with binary clocks. I just recently built my own, based on an AVR microcontroller, which I will post more about soon. I also have a binary watch that was a present from Ceal a few years ago. During a particular boring meeting yesterday, I was watching it count the seconds, and I realized that to increment a binary number by 1, you are really looking for the pattern: 01*$ (the last part of the number consisting of 0 followed by only 1s to the end of the line). When you find that pattern, you just invert the bits.
For example, to add 1 to 10011 (19 decimal), you are only interested in the 011 at the end. You invert that part and get 10100 (20 decimal). The only time the 01*$ pattern doesn't work is when the number is all 1s. In that case, you can insert a leading 0 and again just invert the bits. For example, 1111 (15 decimal) first becomes 01111, then inverted becomes 10000 (16 decimal).
So, after that little epiphany, I began to wonder if I could write a sed script that functioned as a binary adder. At first I didn't think it could be done, because I was thinking purely in terms of doing substitutions. I have since learned much more about the capabilities of sed and found it was possible. Here is the script, along with an explanation of what each line does:
To test this, I wrote a little script that starts with 0, runs it through the adder, prints the result, and the runs the result through the adder. This is the script (caution, it loops forever):
And here is a snippet of the results:
For example, to add 1 to 10011 (19 decimal), you are only interested in the 011 at the end. You invert that part and get 10100 (20 decimal). The only time the 01*$ pattern doesn't work is when the number is all 1s. In that case, you can insert a leading 0 and again just invert the bits. For example, 1111 (15 decimal) first becomes 01111, then inverted becomes 10000 (16 decimal).
So, after that little epiphany, I began to wonder if I could write a sed script that functioned as a binary adder. At first I didn't think it could be done, because I was thinking purely in terms of doing substitutions. I have since learned much more about the capabilities of sed and found it was possible. Here is the script, along with an explanation of what each line does:
s/^1*$/0&/
h
s/\(.*\)01*$/\1/
x
s/^.*\(01*\)$/\1/
y/01/10/
x
G
s/\n//
s/^1*$/0&/ | If the number is all 1s, insert a leading 0 |
h | Copy the current line to the hold buffer |
s/\(.*\)01*$/\1/ | Strip off the 01*$ pattern from the end |
x | Exchange the current pattern with the hold buffer |
s/^.*\(01*\)$/\1/ | Strip off everything but the 01*$ pattern |
y/01/10/ | Invert the bits in the current line |
x | Exchange the current pattern with the hold buffer (go back to the prefix bits) |
G | Join the hold buffer (the end bits that were just inverted) to the current pattern (sed puts it on a separate line) |
s/\n// | Join the two lines |
To test this, I wrote a little script that starts with 0, runs it through the adder, prints the result, and the runs the result through the adder. This is the script (caution, it loops forever):
#!/bin/sh
NUM=0
while true; do
NUM=`echo $NUM | sed -f adder.sed`
echo $NUM
done
And here is a snippet of the results:
1
10
11
100
101
110
111
1000
1001
1010
1011
1100
1101
1110
1111
10000
10001
10010
10011
10100
Comments:
<< Home
# bash binary ripple counter
NUM=0
while [ $NUM -lt 1000 ]
do
NUM=$NUM^
while echo $NUM | fgrep -q '^'
do
echo; echo -n $NUM
NUM=`echo $NUM | sed -e '
s/1^/^0/
t
s/^^/1/
t
s/0^/1/'`
done; echo; echo -n $NUM = $((2#$NUM)).
done; echo
Post a Comment
NUM=0
while [ $NUM -lt 1000 ]
do
NUM=$NUM^
while echo $NUM | fgrep -q '^'
do
echo; echo -n $NUM
NUM=`echo $NUM | sed -e '
s/1^/^0/
t
s/^^/1/
t
s/0^/1/'`
done; echo; echo -n $NUM = $((2#$NUM)).
done; echo
<< Home