See Also: [Converting an integer to a base 2 string], [Binary representation of numbers], [Based numbers] ---- [rvb] A general base-conversion procedure for arbitrary length string representations of numbers with integer and/or fraction. #============================================================================= # PROC : baseconvert # PURPOSE : convert number in one base to another base # AUTHOR : Richard Booth # DATE : Fri Jul 14 10:40:50 EDT 2006 # --------------------------------------------------------------------------- # ARGUMENTS : # % base_from # original base (expressed in base 10) # % base_to # base to convert number to (expressed in base 10) # % number # number expressed in base_from (must have form int.fra, int, or .fra) # RESULTS : # * returns number expressed in base_to # EXAMPLE-CALL : #{ # set num16 [baseconvert 10 16 3.1415926535] #} #============================================================================= proc baseconvert {base_from base_to number} { set number [string tolower $number] if {![regexp {([0-9a-z]*)\.?([0-9a-z]*)} $number match sint sfra]} { puts "baseconvert error: number \"$number\" is not in correct format" return "" } set map 0123456789abcdefghijklmnopqrstuvwxyz set i -1 foreach c [split $map ""] { incr i set D2I($c) $i set I2D($i) $c } set lint [string length $sint] set lfra [string length $sfra] set converted_number 0 if {$lint > 0} { set i -1 foreach c [split $sint ""] { set B([incr i]) $D2I($c) } set aint "" while {1} { set s 0 set r 0 for {set i 0} {$i < $lint} {incr i} { set v [expr $B($i) + $r*$base_from] set B($i) [expr int($v/$base_to)] set r [expr $v - $base_to*$B($i)] set s [expr $s + $B($i)] } set aint "$I2D($r)$aint" if {$s == 0} {break} } set converted_number $aint } if {$lfra > 0} { set s [expr int(1.0*$lfra*log($base_from)/log($base_to))] set i $lfra foreach c [split $sfra ""] { set B([incr i -1]) $D2I($c) } set afra "" for {set j 0} {$j < $s} {incr j} { set r 0 for {set i 0} {$i < $lfra} {incr i} { set v [expr $base_to*$B($i) + $r] set r [expr int($v/$base_from)] set B($i) [expr $v - $r*$base_from] } set afra "$I2D($r)$afra" } append converted_number .$afra } return $converted_number } a small test script for baseconvert: set fmt "%-10s (base %-2d) => %-10s (base %-2d)" foreach number {12ff.abb 122. 125 .222 0.222 0.22 0.2 0.1} { puts [format $fmt $number 16 [baseconvert 16 10 $number] 10] puts [format $fmt $number 16 [baseconvert 16 8 $number] 8] puts [format $fmt $number 16 [baseconvert 16 2 $number] 2] } ---- [rvb] A related problem is sampling a multi-dimensional grid. ''[Lars H]: Hmm... That's a rather antiquated way to do it, though. If you really want all points in the grid, then it is easier to construct it as the [Cartesian product of a list of lists].'' [rvb] Friendly jabs aside, my point was that counting in any particular base is like climbing a multidimensional grid (or even the geometric analogue, to a lightheaded antiquarian.) However, the [Cartesian product of a list of lists] approach, which I tried with the recursive procedure, is very elegant. #============================================================================= # PROC : gridsample # PURPOSE : uniformly sample a normalized hypercube # AUTHOR : Richard Booth # DATE : Tue Jul 18 11:19:10 EDT 2006 # --------------------------------------------------------------------------- # ARGUMENTS : # % ndiv # number of divisions of the normalized hypercube # (each independent variable range is [-1, 1]) # % nind # number of independent variables # RESULTS : # * returns list of (normalized) samples # EXAMPLE-CALL : #{ # set samples [gridsample 5 2] #} #============================================================================= proc gridsample {ndiv nind} { if {$nind < 1 || $ndiv < 1} { return {} } set samples {} set base [expr $ndiv+1] set npts [expr pow($base, $nind)] for {set i 0} {$i < $npts} {incr i} { set sample {} set v $i for {set j 0} {$j < $nind} {incr j} { set w [expr int($v/$base)] set r [expr $v - $base*$w] set v $w lappend sample [expr {2.0*$r/$ndiv-1}] } lappend samples [join $sample] } return $samples } a test script for gridsample: set nind 3 set ndiv 6 set samples [gridsample $ndiv $nind] puts "sample A B C" set iexpt -1 foreach sample $samples { puts "[incr iexpt] [join $sample]" } ---- [MJ] - for conversion of large integers to hex the above proc is fairly slow (probably because it doesn't take advantage of Tcl 8.5 large integer support). The proc below is much faster. # needs Tcl 8.5 for large integer support proc hex {num} { set res {} set hex_list {0 1 2 3 4 5 6 7 8 9 A B C D E F} while {$num / 16 != 0} { set rest [expr {$num%16}] set res [lindex $hex_list $rest]$res set num [expr {$num/16}] } set res [lindex $hex_list $num]$res } % time {baseconvert 10 16 25543398472347234723447294729472384329374982742984729472347247729472984264726487264284628462846274628462846284628462846284623874623874623784623486248726487642846} 100 879291.28 microseconds per iteration % time {hex 25543398472347234723447294729472384329374982742984729472347247729472984264726487264284628462846274628462846284628462846284623874623874623784623486248726487642846} 100 4507.07 microseconds per iteration ---- !!!!!! %|[Category Algorithm] | [Category Mathematics]|% !!!!!!