romannumerals.tcl

Go to the documentation of this file.
00001 /* ==========================================================================*/
00002 /*  Roman Numeral Utility Functions*/
00003 /* ==========================================================================*/
00004 /*  Description*/
00005 /* */
00006 /*    A set of utility routines for handling and manipulating*/
00007 /*    roman numerals.*/
00008 /* -------------------------------------------------------------------------*/
00009 /*  Copyright/License*/
00010 /* */
00011 /*    This code was originally harvested from the Tcler's*/
00012 /*    wiki at http://wiki.tcl.tk/1823 and as such is free*/
00013 /*    for any use for any purpose.*/
00014 /* -------------------------------------------------------------------------*/
00015 /*  Modification history*/
00016 /* */
00017 /*    27 Sep 2005 Kenneth Green*/
00018 /*        Original version derived from wiki code*/
00019 /* -------------------------------------------------------------------------*/
00020 
00021 package provide math::roman 1.0
00022 
00023 /* ==========================================================================*/
00024 /*  Namespace*/
00025 /* ==========================================================================*/
00026 namespace ::math::roman {
00027     namespace export tointeger toroman
00028 
00029     /*  We dont export 'sort' or 'expr' to prevent collision*/
00030     /*  with existing commands. These functions are less likely to be*/
00031     /*  commonly used and have to be accessed as fully-scoped names.*/
00032 
00033     /*  romanvalues - array that maps roman letters to integer values.*/
00034     /* */
00035     variable romanvalues
00036 
00037     /*  i2r - list of integer-roman tuples*/
00038     variable i2r {1000 M 900 CM 500 D 400 CD 100 C 90 XC 50 L 40 XL 10 X 9 IX 5 V 4 IV 1 I}
00039 
00040     /*  sortkey - list of patterns to supporting sorting of roman numerals*/
00041     variable sortkey {IX VIIII L Y XC YXXXX C Z D {\^} ZM {\^ZZZZ} M _}
00042     variable rsortkey {_ M {\^ZZZZ} ZM {\^} D Z C YXXXX XC Y L VIIII IX}
00043 
00044     /*  Initialise array variables*/
00045     array  romanvalues =  {M 1000 D 500 C 100 L 50 X 10 V 5 I 1}
00046 }
00047 
00048 /* ==========================================================================*/
00049 /*  Public Functions*/
00050 /* ==========================================================================*/
00051 
00052 /* ----------------------------------------------------------*/
00053 /*  Roman numerals sorted*/
00054 /* */
00055 ret  ::math::roman::sort list (
00056     type variable , type sortkey
00057     , type variable , type rsortkey
00058 
00059     , type foreach , optional from =to $, type sortkey , optional 
00060         regsub =-all $from =$list $to =list
00061     
00062     , type set , type list [, type lsort $, type list]
00063     , type foreach , optional from =to $, type rsortkey , optional 
00064         regsub =-all $from =$list $to =list
00065     
00066     , type return $, type list
00067 )
00068 
00069 #----------------------------------------------------------
00070 # Roman numerals from integer
00071 #
00072 proc ::math::roman::toroman {i} {
00073     variable i2r
00074 
00075      res =  ""
00076     foreach {value roman} $i2r {
00077         while {$i>=$value} {
00078             append res $roman
00079             incr i -$value
00080         }
00081     }
00082     return $res
00083 }
00084 
00085 /* ----------------------------------------------------------*/
00086 /*  Roman numerals parsed into integer:*/
00087 /* */
00088 ret  ::math::roman::tointeger (type s) {
00089     variable romanvalues
00090 
00091     set last 99999
00092     set res  0
00093     foreach i [split [string toupper $s] ""] {
00094         if { [catch {set val $romanvalues($i)}] } {
00095             return -code error "roman::tointeger - un-Roman digit $i in $s"
00096         }
00097         incr res $val
00098         if { $val > $last } {
00099             incr res [::expr -2*$last]
00100         }
00101         set last $val
00102     }
00103     return $res
00104 }
00105 
00106 /* ----------------------------------------------------------*/
00107 /*  Roman numeral arithmetic*/
00108 /* */
00109 ret  ::math::roman::expr args (
00110 
00111     type if , optional [string =first \$ =$args] >= =0  , optional 
00112         set =args [uplevel =subst $args]
00113     
00114 
00115     , type regsub -, type all , optional [^IVXLCDM] $, type args , optional &  , type args
00116     , type foreach , type i $, type args , optional 
00117         catch ={set i =[tointeger $i]
00118         , type lappend , type res $, type i
00119     )
00120     return [toroman [::expr $res]]
00121 }
00122 
00123 #==========================================================
00124 # Developer test code
00125 #
00126 if { 0 } {
00127 
00128     puts "Basic int-to-roman-to-int conversion test"
00129     for { set i 0 } {$i < 50} {incr i} {
00130          r =  [::math::roman::toroman   $i]
00131          j =  [::math::roman::tointeger $r]
00132         puts [format "%5d   %-15s %s" $i $r $j]
00133         if { $i != $j } {
00134             error "Invalid conversion: $i -> $r -> $j"
00135         }
00136     }
00137 
00138     puts ""
00139     puts "roman arithmetic test"
00140      x =  23
00141      xr =  [::math::roman::toroman $x]
00142      y =  77
00143      yr =  [::math::roman::toroman $y]
00144      xr = +yr [::math::roman::expr $xr + $yr]
00145      yr = -xr [::math::roman::expr $yr - $xr]
00146      xr = *yr [::math::roman::expr $xr * $yr]
00147      yr = /xr [::math::roman::expr $yr / $xr]
00148      yr = /xr2 [::math::roman::expr {$yr / $xr}]
00149     puts "$x + $y\t\t= [expr $x + $y]"
00150     puts "$x * $y\t\t= [expr $x * $y]"
00151     puts "$y - $x\t\t= [expr $y - $x]"
00152     puts "$y / $x\t\t= [expr $y / $x]"
00153     puts "$xr + $yr\t= ${xr+yr} = [::math::roman::tointeger ${xr+yr}]"
00154     puts "$xr * $yr\t= ${xr*yr} = [::math::roman::tointeger ${xr*yr}]"
00155     puts "$yr - $xr\t= ${yr-xr} = [::math::roman::tointeger ${yr-xr}]"
00156     puts "$yr / $xr\t= ${yr/xr} = [::math::roman::tointeger ${yr/xr}]"
00157     puts "$yr / $xr\t= ${yr/xr2} = [::math::roman::tointeger ${yr/xr2}]"
00158 
00159     puts ""
00160     puts "roman sorting test"
00161      l =  {X III IV I V}
00162     puts "IN : $l"
00163     puts "OUT: [::math::roman::sort $l]"
00164 }
00165 

Generated on 21 Sep 2010 for Gui by  doxygen 1.6.1