''Problem:'' how to convert numbers between their decimal and binary representation. I.e., we are looking for a pair of procs {int2bits, bits2int} such that * int2bits 6 -> {1 1 0} * bits2int {1 1 0} -> 6 ---- [Richard Suchenwirth] suggested in c.l.t. proc int2bits {i} { #returns a bitslist, e.g. int2bits 10 => {1 0 1 0} set res "" while {$i>0} { set res [expr {$i%2}]$res set i [expr {$i/2}] } if {$res==""} {set res 0} split $res "" } proc bits2int {bits} { #returns integer equivalent of a bitlist set res 0 foreach i $bits { set res [expr {$res*2+$i}] } set res } ---- Joseph Collard added optional field width: proc int2bits {i {digits {} } } { #returns a bitslist, e.g. int2bits 10 => {1 0 1 0} # digits determines the length of the returned list (left truncated or added left 0 ) # use of digits allows concatenation of bits sub-fields set res "" while {$i>0} { set res [expr {$i%2}]$res set i [expr {$i/2}] } if {$res==""} {set res 0} if {$digits != {} } { append d [string repeat 0 $digits ] $res set res [string range $d [string length $res ] end ] } split $res "" } ---- [MS]: Another approach is using the [binary] command: proc int2bits {i} { #returns a bitslist, e.g. int2bits 10 => {1 0 1 0} binary scan [binary format I1 $i] B* x split [string trimleft $x 0] {} } proc bits2int {bits} { #returns integer equivalent of a bitlist set bits [format %032s [join $bits {}]] binary scan [binary format B* $bits] I1 x set x } [Cameron Laird] rightly noted the platform dependence of the "%032s" part. To correct that, do instead proc int2bits {i} { #returns a bitslist, e.g. int2bits 10 => {1 0 1 0} binary scan [binary format I1 $i] B* x split [string trimleft $x 0] {} } set tmp [llength [int2bits -1]] regsub @ { #returns integer equivalent of a bitlist set bits [format %0@s [join $bits {}]] binary scan [binary format B* $bits] I1 x set x } $tmp tmp proc bits2int {bits} $tmp unset tmp '''Note''': I'm leaving this for now, as an illustration. But it is *not* correct, the 32-bit dependence is still there, implicit in the "I" format specification. A correct approach needs to wait until there are 64 bit format specs for [binary] ---- 'Nother variation: use [format] to convert to octal (or hexadecimal, for that matter), and "[string] map ..." to transform octal digits to bit patterns. proc int2bits x { string map { 0 {0 0 0} 1 {0 0 1} 2 {0 1 0} 3 {0 1 1} 4 {1 0 0} 5 {1 0 1} 6 {1 1 0} 7 {1 1 1} } [split [format %o $x] ""] } ;#RS - note however that the bit sequence is multiples of 3 long: % int2bits 9 0 0 1 0 0 1 % int2bits 255 0 1 1 1 1 1 1 1 1 ---- Helmut Giese in c.l.t: proc val2Bin val { set binRep [binary format c $val] binary scan $binRep B* binStr return $binStr } # some tests puts [val2Bin 10] puts [val2Bin 129] puts [val2Bin 0x7F] ---- [Arjen Markus] The following fragment converts a hexadecimal representation to a floating-point number: # Convert between float and hex # set hex "f3080000" set bin [binary format h8 $hex] binary scan $bin f float puts "$float" On a big-endian machine the result is "1.0" (on a little-endian machine it is bizarre: 4.6006..e-041, but that is simply because the bytes are reversed.) ---- For extracting "unsigned" floating-point values from very long (>32 bits) integers in hex, [MS] has this recommendation on c.l.t.: proc conv {largeHex} { set res 0.0 foreach hexDigit [split $largeHex {}] { set new 0x$hexDigit set res [expr {16.0*$res + $new}] } return $res } ---- [Arjen Markus] Suppose you have a sequence of bytes that are read from a file. Two of these, say at position 6 and 7 (counting from 0), make up an integer number. Then: set two_bytes [string range $str 6 7] binary scan "\0\0$two_bytes" I intvalue will turn these two bytes into an integer (consisting of 4 bytes, hence the two leading nulls), if the original data are in big-endian order. If they are in little-endian order, use: set two_bytes [string range $str 6 7] binary scan "${two_bytes}\0\0" i intvalue (Note: trailing nulls and a different format) ---- Eric Amundsen - Here's a solution that seems to work fine for 64-bit 2's compliment integer math. proc bin2int {binString} { set result 0 for {set j 0} {$j < [string length $binString]} {incr j} { set bit [string range $binString $j $j] set result [expr $result << 1] set result [expr $result | $bit] } return $result } set binaryString 11001 puts [bin2int $binaryString] ---- [Arts and crafts of Tcl-Tk programming] - [Category Mathematics]