## Binary representation of numbers

Binary representation of numbers presents various methods for converting numbers between non-negative decimal and binary (we're talking about the printable textual representation of binary numbers here, e.g., 6 -> 110, and the inverse 110 -> 6).

Big bitstring operations
Converting an integer to a base 2 string
to.binary
Math on binary strings
To little endian
two's complement

## Converting Decimal to Binary

```proc dec2bin i {
#returns a string, e.g. dec2bin 10 => 1010
set res {}
while {\$i>0} {
set res [expr {\$i%2}]\$res
set i [expr {\$i/2}]
}
if {\$res == {}} {set res 0}
return \$res
}```

The following example, which requires Tcl 8.6 or later, uses %llb instead of %lb or %b, because those latter two are subject to overflow: A result could be nonsensical in the case of a large number, since a truncated version of the machine representation of a negative integer would be returned.

```package require Tcl 8.6
proc dec2bin int {
return [format %llb \$int]
}```

The following example includes a "width" option to set the width of the resulting string

```proc dec2bin {i {width {}}} {
#returns the binary representation of \$i
# width determines the length of the returned string (left truncated or added left 0)
# use of width allows concatenation of bits sub-fields

set res {}
if {\$i<0} {
set sign -
set i [expr {abs(\$i)}]
} else {
set sign {}
}
while {\$i>0} {
set res [expr {\$i%2}]\$res
set i [expr {\$i/2}]
}
if {\$res eq {}} {set res 0}

if {\$width ne {}} {
append d [string repeat 0 \$width] \$res
set res [string range \$d [string length \$res] end]
}
return \$sign\$res
}```

Another variation: use format to convert to octal (or hexadecimal, for

that matter), and string map to transform octal digits to bit patterns.

```proc dec2bin x {
if {[string index \$x 0] eq {-}} {
set sign -
set x [string range \$x 1 end]
} else {
set sign {}
}
return \$sign[string trimleft [string map {
0 {000} 1 {001} 2 {010} 3 {011} 4 {100} 5 {101} 6 {110} 7 {111}
} [format %o \$x]] 0]
}```

And some examples:

```% dec2bin 9
1001
% dec2bin 255
11111111```

Only slightly different from the previous example, by Lars H:

```proc dec2bin dec {
if {[string match -* \$dec]} {
set sign -
set dec [expr {abs(\$dec)}]
} else {
set sign {}
}
return \$sign[string map {
+0 0 +1 1 +2 {10} +3 {11} +4 {100} +5 {101} +6 {110} +7 {111}
0 {000} 1 {001} 2 {010} 3 {011} 4 {100} 5 {101} 6 {110} 7 {111}
} [format +%o \$dec]]
}```

The following example, which came from Googol magnitude is similar in spirit, but much slower:

```proc dec2bin dec {
while {[regexp {[0-9]} \$dec]} {
set dec\
[string map {o0 0 o1 1 o2 2 o3 3 o4 4 i0 5 i1 6 i2 7 i3 8 i4 9 0 {}}\
[string map {0 0o 1 0i 2 1o 3 1i 4 2o 5 2i 6 3o 7 3i 8 4o 9 4i} \$dec]]
}
string map {i 1 o 0} \$dec
}```

The idea of dec2bin is to alternate between a normal decimal notation and an a bi-quinary [L1 ] or "abacistic" notation where there are separate positions for fives (i = a five, o = no five). It is easy to generate the abacistic notation for half of a number in decimal notation -- just half every digit in place, e.g. 7 -> 3i -- and also easy to convert from abacistic to decimal notation, e.g. i3 -> 8. (Note that this doesn't combine is and os into the same decimal position as they were split off from.) is and os that don't have a digit to their right to recombine with constitute the bits that have been shifted out from the decimal number. bin2dec does the same thing backwards, with an extra h in the leftmost position to discard unnecessary zeroes.

Another alternative is to use binary. The general idea is illustrated in this simple example, followed by a more complete example:

```proc dec2bin int {
set binRep [binary format c \$int]
binary scan \$binRep B* binStr
return [string trimleft \$binStr 0]
}```

In the complete example, the bytes a list of numbers representing the individual bytes of the machine binary representation are built up, in little-ending order. The list is then reversed so that it is in big-endian order, and then scanned:

```proc dec2bin i {
#returns the binary representation of \$i e.g. dec2bin 10 => 1010

#this did not work properly where \$i > [expr {2**32-1}]
#binary scan [binary format I1 \$i] B* x

if {\$i == 0} {
return 0
} elseif  {\$i > 0} {
set sign {}
} else {
set sign -
set i [expr {abs(\$i)}]
}
while {\$i>0} {
set mod [expr {\$i % 256}]
set i [expr {\$i/256}]
lappend mods \$mod
}
binary scan [binary format c* [lreverse \$mods[set mods {}]]] B* x
return \$sign[string trimleft \$x 0]
}```

Comment: In the last two examples, dec2bin 0 would result in an empty string since string trimleft trims also a single 0. You may replace it e.g. with regsub {^0+([01]+?)\$} \$x {\1} b; return \$sign\$b.

## Converting Binary to Decimal

KBK contributed the precursor to this variant in the Tcl chatroom on 2002-11-18:

```proc bin2dec bin {
if {\$bin == 0} {
return 0
} elseif  {[string match -* \$bin]} {
set sign -
set bin [string range \$bin 1 end]
} else {
set sign {}
}
if {[string map [list 1 {} 0 {}] \$bin] ne {}} {
error "argument is not in base 2: \$bin"
}
set r 0
foreach d [split \$bin {}] {
incr r \$r
incr r \$d
}
return \$sign\$r
}```
```proc bin2dec bin {
if {\$bin == 0} {
return 0
} elseif {[string match -* \$bin]} {
set sign -
set bin [string range \$bin[set bin {}] 1 end]
} else {
set sign {}
}
return \$sign[expr 0b\$bin]
}```
```proc bin2dec bin {
#returns integer equivalent of \$bin
set res 0
if {\$bin == 0} {
return 0
} elseif {[string match -* \$bin]} {
set sign -
set bin [string range \$bin[set bin {}] 1 end]
} else {
set sign {}
}
foreach i [split \$bin {}] {
set res [expr {\$res*2+\$i}]
}
return \$sign\$res
}```
```proc bin2dec bin {
if {\$bin == 0} {
return 0
} elseif {[string match -* \$bin]} {
set sign -
set bin [string range \$bin[set bin {}] 1 end]
} else {
set sign {}
}
set res 0
for {set j 0} {\$j < [string length \$bin]} {incr j} {
set bit [string index \$bin \$j]
set res [expr {\$res << 1}]
set res [expr {\$res | \$bit}]
}
return \$sign\$res
}```
```proc bin2dec num {
set num h[string map {1 i 0 o} \$num]
while {[regexp {[io]} \$num]} {
set num\
[string map {0o 0 0i 1 1o 2 1i 3 2o 4 2i 5 3o 6 3i 7 4o 8 4i 9 ho h hi h1}\
[string map {0 o0 1 o1 2 o2 3 o3 4 o4 5 i0 6 i1 7 i2 8 i3 9 i4} \$num]]
}
string range \$num 1 end
}```

binary could also be used:

```proc bin2dec bin {
#returns decimal representation of the binary representation \$bin
if {\$bin == 0} {
return 0
} elseif  {[string match -* \$bin]} {
set sign -
set bin [string range \$bin 1 end]
} else {
set sign {}
}

set mod [expr {[string length \$bin]%8}]
if {\$mod} {
set mod [expr {8-\$mod}]
}
set bin [string repeat 0 \$mod]\$bin
set len [string length \$bin]
set bin [binary format B* \$bin]
#the else block ould do it all, but for illustration...
if {\$len<=8} {
binary scan \$bin cu res
} elseif {\$len <=16} {
binary scan \$bin Su res
} elseif {\$len <=32} {
if {\$len <= 24} {
set bin [binary format B* 0]\$bin
}
binary scan \$bin Iu res
} else {
set res 0
set blen [expr {\$len/8}]
set pos -1
while {\$blen} {
incr blen -1
binary scan \$bin x[incr pos]cu next
set res [expr {\$res + \$next*(2**(\$blen*8))} ]
}
}
return \$sign\$res
}```

## Misc

```##############################################  sigbinfrac2dec.tcl
##
##format Sign(1bit)Integer(8bit).fractional(2bit)
##               X XXXXXXXX.XX

proc sigbinfrac2dec bin {
#puts "Input String to be converted:  \$bin"
if {\$bin == 0} {
return 0
} elseif  {[string match *.* \$bin]} {
#fractional
#set range [string length \$bin]
set flot [string first . \$bin]

set sign [string range \$bin 0 0]
set integer [string range \$bin  1 [expr \$flot - 1] ]
#puts "Integer Part to be converted:  \$integer"
set frac [string range \$bin [expr \$flot + 1] end]
#puts "Fractional Part to be converted:  \$frac"
} else {
# No Fractional
set sign [string range \$bin 0 0]
set integer [string range \$bin  1 end]
}
if {[string map [list 1 {} 0 {} . {}] \$bin] ne {}} {
error "argument is not in base 2 or base 2 fractional: \$bin"
}
#Algo for Integer Part to be executed in both Format
set r 0
foreach d [split \$integer {}] {
incr r \$r
incr r \$d
}
if {\$sign == 1} {
set signd -} else {
set signd +
}
if  {[string match *.* \$bin]} {
#Algo for fractional Part to be executed only in case of flotting point being
set x 0
set flotd 0
foreach d [split \$frac {} ] {
set x [incr x -1]
set flotd [expr \$flotd + [expr {pow(2,\$x)} * \$d ]]
}
set flotdo [string range \$flotd 1 end]
return \$signd\$r\$flotdo } else {
return \$signd\$r
}

}

Expected Output:
% source sigbinfrac2dec.tcl
% sigbinfrac2dec 11.11
-1.75```

Franco Cesari

```# SPEC : Get the 2's complement rappresentation
proc complement2 {binary width} {
if {[string length \$binary] != \$width } {
puts stdout "Error in complement2 string passed does not match with length declared with width parameter."
return -1
} else {
set compl  [string map {0 1 1 0}  \$binary]
set compl_dec [ bin2dec \$compl]
set complement_2dec [expr \$compl_dec  + 1]
set complement_2bin [dec2bin_width \$complement_2dec \$width]
return \$complement_2bin
}
}```

Expected Output:

``` complement2 000001100100        12
111110011100

```

## Contributors

RS
Joseph Collard
Eric Amundsen
PYK
Franco Cesari

 Arts and Crafts of Tcl-Tk Programming Category Mathematics Category Binary Data