[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. ---- [Converting numbers from arbitrary bases] is an earlier approach at the same topic. ---- 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. ---- A number to base 11 is very frequently used - the [check digits] in ISBN book numbers, but they use X for 10, instead of A as the code above would do. ---- [MSW] responds to: ''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?'' Number['r'|'R'][digits or letters] 0r16 ;# == 0x0 0r1 ;# == 0b0 0R8 ;# == 00 0r10 ;# == 0 0rf ;# == 0x0 0r27 That's e.g. how [Icon] does it, not 100% sure about the 'r', but lisp doesn it that way, too. ---- ''[escargo] 11 Aug 2003'' - It is worth noting that base does not have to be a '''positive''' integer. I did some work (for a high school extra credit assignment) for base '''-2'''. These numbers did not have a sign bit in their representations, yet could still represent both positive and negative numbers. The logic for the math operations look funny, but it does work. [Category Mathematics] - [Arts and crafts of Tcl-Tk programming]