romannumerals.tcl
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 package provide math::roman 1.0
00022
00023
00024
00025
00026 namespace ::math::roman {
00027 namespace export tointeger toroman
00028
00029
00030
00031
00032
00033
00034
00035 variable romanvalues
00036
00037
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
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
00045 array romanvalues = {M 1000 D 500 C 100 L 50 X 10 V 5 I 1}
00046 }
00047
00048
00049
00050
00051
00052
00053
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
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
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