** See Also ** [Converting numbers from arbitrary bases]: an earlier approach at the same topic [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 ======none 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], ======none 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: ======none % 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: ======none % 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?'' ======none Number['r'|'R'][digits or letters] 0r16 ;# == 0x0 0r1 ;# == 0b0 0R8 ;# == 00 0r10 ;# == 0 0rf ;# == 0x0 0r27 ====== That's e.g. how [Icon Programming Language%|%Icon] does it, not 100% sure about the 'r', but [lisp] does it that way, too. [escargo] 2005-08-22: That's not ''quite'' the way it works in [Icon]. It's really ''digit-literal radix-specification digit-specification'', where ''radix-specification'' is '''r''' or '''R'''. The number specifying the radix comes first: ====== 16rff == 0xff 8r17 == 017 2r11 == 0b11 ====== ---- [escargo] 2003-08-11: 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. <> Mathematics | Arts and crafts of Tcl-Tk programming