Version 3 of base conversion

Updated 2006-07-18 15:31:58

A general base-conversion procedure for arbitrary length string representations of numbers with integer and/or fraction.

rvb

 #=============================================================================
 # 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 $lfra*int(1.0*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:

 #=============================================================================
 # 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]"
 }

See Also: Converting an integer to a base 2 string, Binary representation of numbers,


Category Algorithm | Category Mathematics