Richard Suchenwirth 2002-07-06 - Every string standing for a number in a positional value system (as opposed to e.g. Roman numbers or Hebrew numbers) has to be understood relative to its base. We're most familiar with base 10 (the decimal system), where e.g. 123 stands for
1*10^2 + 2*10^1 + 3*10^0
and in computery the bases 2 (binary), 8 (octal), and 16 (hexadecimal) are also fairly common, but any integer could function as a base as long as we have enough distinct digits. If you want to experiment with other bases, here are two routines that convert a number to and from a different base, up to 62 (base64 uses a very different sequence of digits, so I didn't go that far)
Note also that signs are preserved (unlike computery habit to have octals and hexadecimals as unsigned, resp. sign-extended). You could have that with
base $myBase [format %u $number]
Also, the C/Tcl markup of prefixing 0 to octals and 0x to hexadecimals is not created or recognized - how would e.g. a number to base 3 be marked? Like in Ada,
3#12021#
? So you have to keep track of number bases yourself.
proc base {base number} { set negative [regexp ^-(.+) $number -> number] ;# (1) set digits {0 1 2 3 4 5 6 7 8 9 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z} set res {} while {$number} { set digit [expr {$number % $base}] set res [lindex $digits $digit]$res set number [expr {$number / $base}] } if $negative {set res -$res} set res } proc frombase {base number} { set digits {0 1 2 3 4 5 6 7 8 9 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z} set negative [regexp ^-(.+) $number -> number] set res 0 foreach digit [split $number ""] { set decimalvalue [lsearch $digits $digit] if {$decimalvalue<0 || $decimalvalue >= $base} { error "bad digit $decimalvalue for base $base" } set res [expr {$res*$base + $decimalvalue}] } if $negative [set res -$res] set res }
Examples:
% base 7 1234 3412 % frombase 7 3412 1234 % base 16 255 FF
One might use this to experiment with number palindromes, where the sequence of digits is reverted:
% base 19 42 24 % frombase 19 24 42
# (1): In the Tcl chatroom, Michael Schlenker reported:
set negative [expr {$number != [set number [expr {abs($number)}]]}]
is about five times faster if negative, and a bit faster if positive.
Category Mathematics - Arts and crafts of Tcl-Tk programming