0 - 000 1 - 001 3 - 011 2 - 010 6 - 110 7 - 111 5 - 101 4 - 100This type of code is often used when designing [analog to digital convertor]s (ADC). I developed this piece of code in order to map the output of an ADC to regular binary for post-processing.
###############################################################################
#
# proc grayCodeServer
#
# Description
# Use the following equation to generate an n bit gray code.
#
# / 0
# G1 = <
# \ 1
#
# /0 . Gn-1
# Gn = <
# \ 1 . reverse(Gn-1)
#
# where the . operator denotes concatenation, and the reverse function is
# simply denotes the Gray code in revers (i.e. G1 = (0, 1);
# reverse(G1) = (1, 0)).
#
# Arguments
# numBits - the number of bits. The list returned is 2^numBits long
#
# Return value
# A list, where the value at the index of the list is the gray code value
# for that index value
#
###############################################################################
proc grayCodeServer {numBits} {
# return a list 2^numBits long, where [lindex grayValue $list] will
# correspond to the decimal equivalent
# Initialize the previous Gray code to a 1 bit code (0, 1).
set grayCodeMinus1 [list 0 1]
# Set the Gray code equal to a 1 bit Gray code. If the numBits passed in
# is greater than 1, then this will get expanded properly, but the first
# half of the next Gray code is always the same as the previous Gray code.
set grayCode $grayCodeMinus1
# Loop through to the number of bits passed in, each time building the
# Gray code from the previous Gray code according to the function
# outlined above.:
for {set j 1} {$j < $numBits} {incr j} {
# The first half of the list is already valid from the previous pass
# through this loop.
# Keep a counting for going through the previous Gray code in
# reverse.
for {set k [expr {[llength $grayCodeMinus1] - 1}]} \
{$k >= 0} \
{incr k -1} {
# Shift 1 the number of bits that we're currently building the
# Gray code for, and OR this with the reverse of the previous
# Gray code.
lappend grayCode [expr {(1 << $j) | [lindex $grayCodeMinus1 $k]}]
}
# Make the previous gray code equal to the new one.
set grayCodeMinus1 $grayCode
}
return $grayCode
}
# demo code
if 0 {
for {set j 1} {$j <= 8} {incr j} {
puts "$j bit gray code : "
foreach v [grayCodeServer $j] {
puts [format "%0.2X" $v]
}
}
}DKF: Here's a more functional version, through the use of a helper based on lmap and some ideas relating to currying:
proc map {lambda args} {
set result {}
foreach item [lindex $args end] {
lappend result [apply $lambda {*}[lrange $args 0 end-1] $item]
}
return $result
}
proc grayCode bits {
set code {0 1}
set append {{bit item} {append item $bit}}
for {set i 1} {$i < $bits} {incr i} {
set code [concat [map $append 0 $code] [map $append 1 [lreverse $code]]]
}
return $code
}
