Parent Directory
|
Revision Log
initial import
1 #!/usr/math/bin/perl -w 2 3 4 # This is the "exported" subroutine. Use this to evaluate the units given in an answer. 5 6 sub evaluate_units { 7 &Units::evaluate_units; 8 } 9 10 # Methods for evaluating units in answers 11 package Units; 12 13 #require Exporter; 14 #@ISA = qw(Exporter); 15 #@EXPORT = qw(evaluate_units); 16 17 18 # compound units are entered such as m/sec^2 or kg*m/sec^2 19 # the format is unit[^power]*unit^[*power].../ unit^power*unit^power.... 20 # there can be only one / in a unit. 21 # powers can be negative integers as well as positive integers. 22 23 # These subroutines return a unit hash. 24 # A unit hash has the entries 25 # factor => number number can be any real number 26 # m => power power is a signed integer 27 # kg => power 28 # s => power 29 # rad => power 30 # degC => power 31 # degF => power 32 # degK => power 33 # perhaps other fundamental units will added later as well. 34 35 36 my %fundamental_units = ('factor' => 1, 37 'm' => 0, 38 'kg' => 0, 39 's' => 0, 40 'rad' => 0, 41 'degC' => 0, 42 'degF' => 0, 43 'degK' => 0 44 ); 45 46 # This hash contains all of the units which will be accepted. These must 47 #be defined in terms of the 48 # fundamental units given above. If the power of the fundamental unit is 49 #not included it is assumed to 50 # be zero. 51 52 my $PI = 4*atan2(1,1); 53 54 my %known_units = ('m' => { 55 'factor' => 1, 56 'm' => 1 57 }, 58 'kg' => { 59 'factor' => 1, 60 'kg' => 1 61 }, 62 's' => { 63 'factor' => 1, 64 's' => 1 65 }, 66 'rad' => { 67 'factor' => 1, 68 'rad' => 1 69 }, 70 'degC' => { 71 'factor' => 1, 72 'degC' => 1 73 }, 74 'degF' => { 75 'factor' => 1, 76 'degF' => 1 77 }, 78 'degK' => { 79 'factor' => 1, 80 'degK' => 1 81 }, 82 # ANGLES 83 # deg -- degrees 84 # 85 'deg' => { 86 'factor' => 0.0174532925, 87 'rad' => 1 88 }, 89 # TIME 90 # s -- seconds 91 # ms -- miliseconds 92 # min -- minutes 93 # hr -- hours 94 # day -- days 95 # yr -- years -- 365 days in a year 96 # 97 'ms' => { 98 'factor' => 0.001, 99 's' => 1 100 }, 101 'min' => { 102 'factor' => 60, 103 's' => 1 104 }, 105 'hr' => { 106 'factor' => 3600, 107 's' => 1 108 }, 109 'day' => { 110 'factor' => 86400, 111 's' => 1 112 }, 113 'yr' => { 114 'factor' => 31557600, 115 's' => 1 116 }, 117 118 # LENGTHS 119 # m -- meters 120 # cm -- centimeters 121 # km -- kilometers 122 # mm -- millimeters 123 # micron -- micrometer 124 # um -- micrometer 125 # nm -- nanometer 126 # A -- Angstrom 127 # 128 'km' => { 129 'factor' => 1000, 130 'm' => 1 131 }, 132 'cm' => { 133 'factor' => 0.01, 134 'm' => 1 135 }, 136 'mm' => { 137 'factor' => 0.001, 138 'm' => 1 139 }, 140 'micron' => { 141 'factor' => 10**(-6), 142 'm' => 1 143 }, 144 'um' => { 145 'factor' => 10**(-6), 146 'm' => 1 147 }, 148 'nm' => { 149 'factor' => 10**(-9), 150 'm' => 1 151 }, 152 'A' => { 153 'factor' => 10**(-10), 154 'm' => 1 155 }, 156 # ENGLISH LENGTHS 157 # in -- inch 158 # ft -- feet 159 # mi -- mile 160 # light-year 161 # 162 'in' => { 163 'factor' => 0.0254, 164 'm' => 1 165 }, 166 'ft' => { 167 'factor' => 0.3048, 168 'm' => 1 169 }, 170 'mi' => { 171 'factor' => 1609.344, 172 'm' => 1 173 }, 174 'light-year' => { 175 'factor' => 9.46E15, 176 'm' => 1 177 }, 178 # VOLUME 179 # L -- liter 180 # ml -- milliliters 181 # cc -- cubic centermeters 182 # 183 'L' => { 184 'factor' => 0.001, 185 'm' => 3 186 }, 187 'cc' => { 188 'factor' => 10**(-6), 189 'm' => 3, 190 }, 191 'ml' => { 192 'factor' => 10**(-6), 193 'm' => 3, 194 }, 195 # VELOCITY 196 # knots -- nautical miles per hour 197 # 198 'knots' => { 199 'factor' => 0.5144444444, 200 'm' => 1, 201 's' => -1 202 }, 203 # MASS 204 # g -- grams 205 # kg -- kilograms 206 # 207 'g' => { 208 'factor' => 0.001, 209 'kg' => 1 210 }, 211 # ENGLISH MASS 212 # slug -- slug 213 # 214 'slug' => { 215 'factor' => 14.6, 216 'kg' => 1 217 }, 218 # FREQUENCY 219 # Hz -- Hertz 220 # kHz -- kilo Hertz 221 # MHz -- mega Herta 222 # 223 'Hz' => { 224 'factor' => 2*$PI, #2pi 225 's' => -1, 226 'rad' => 1 227 }, 228 'kHz' => { 229 'factor' => 1000*2*$PI, #1000*2pi, 230 's' => -1, 231 'rad' => 1 232 }, 233 'MHz' => { 234 'factor' => (10**6)*2*$PI, #10^6 * 2pi, 235 's' => -1, 236 'rad' => 1 237 }, 238 'rev' => { 239 'factor' => 2*$PI, 240 'rad' => 1 241 }, 242 'cycles' => { 243 'factor' => 2*$PI, 244 'rad' => 1 245 }, 246 247 # COMPOUND UNITS 248 # 249 # FORCE 250 # N -- Newton 251 # microN -- micro Newton 252 # uN -- micro Newton 253 # dyne -- dyne 254 # lb -- pound 255 # ton -- ton 256 # 257 'N' => { 258 'factor' => 1, 259 'm' => 1, 260 'kg' => 1, 261 's' => -2 262 }, 263 'microN' => { 264 'factor' => 10**(-6), 265 'm' => 1, 266 'kg' => 1, 267 's' => -2 268 }, 269 'uN' => { 270 'factor' => 10**(-6), 271 'm' => 1, 272 'kg' => 1, 273 's' => -2 274 }, 275 'dyne' => { 276 'factor' => 10**(-5), 277 'm' => 1, 278 'kg' => 1, 279 's' => -2 280 }, 281 'lb' => { 282 'factor' => 4.45, 283 'm' => 1, 284 'kg' => 1, 285 's' => -2 286 }, 287 'ton' => { 288 'factor' => 8900, 289 'm' => 1, 290 'kg' => 1, 291 's' => -2 292 }, 293 # ENERGY 294 # J -- Joule 295 # kJ -- kilo Joule 296 # erg -- erg 297 # lbf -- foot pound 298 # cal -- calorie 299 # kcal -- kilocalorie 300 # eV -- electron volt 301 # kWh -- kilo Watt hour 302 # 303 'J' => { 304 'factor' => 1, 305 'm' => 2, 306 'kg' => 1, 307 's' => -2 308 }, 309 'kJ' => { 310 'factor' => 1000, 311 'm' => 2, 312 'kg' => 1, 313 's' => -2 314 }, 315 'erg' => { 316 'factor' => 10**(-7), 317 'm' => 2, 318 'kg' => 1, 319 's' => -2 320 }, 321 'lbf' => { 322 'factor' => 1.355, 323 'm' => 2, 324 'kg' => 1, 325 's' => -2 326 }, 327 'cal' => { 328 'factor' => 4.19, 329 'm' => 2, 330 'kg' => 1, 331 's' => -2 332 }, 333 'kcal' => { 334 'factor' => 4190, 335 'm' => 2, 336 'kg' => 1, 337 's' => -2 338 }, 339 'eV' => { 340 'factor' => 1.60E-9, 341 'm' => 2, 342 'kg' => 1, 343 's' => -2 344 }, 345 'kWh' => { 346 'factor' => 3.6E6, 347 'm' => 2, 348 'kg' => 1, 349 's' => -2 350 }, 351 # POWER 352 # W -- Watt 353 # kW -- kilo Watt 354 # 355 'W' => { 356 'factor' => 1, 357 'm' => 2, 358 'kg' => 1, 359 's' => -3 360 }, 361 'kW' => { 362 'factor' => 1000, 363 'm' => 2, 364 'kg' => 1, 365 's' => -3 366 }, 367 # PRESSURE 368 # Pa -- Pascal 369 # kPa -- kilo Pascal 370 # atm -- atmosphere 371 'Pa' => { 372 'factor' => 1, 373 'm' => -1, 374 'kg' => 1, 375 's' => -2 376 }, 377 'kPa' => { 378 'factor' => 1000, 379 'm' => -1, 380 'kg' => 1, 381 's' => -2 382 }, 383 'atm' => { 384 'factor' => 1.01E5, 385 'm' => -1, 386 'kg' => 1, 387 's' => -2 388 }, 389 390 ); 391 392 393 394 sub process_unit { 395 396 my $string = shift; 397 die ("UNIT ERROR: No units were defined.") unless defined($string); # 398 #split the string into numerator and denominator --- the separator is / 399 my ($numerator,$denominator) = split( m{/}, $string ); 400 401 402 403 $denominator = "" unless defined($denominator); 404 my %numerator_hash = process_term($numerator); 405 my %denominator_hash = process_term($denominator); 406 407 408 my %unit_hash = %fundamental_units; 409 my $u; 410 foreach $u (keys %unit_hash) { 411 if ( $u eq 'factor' ) { 412 $unit_hash{$u} = $numerator_hash{$u}/$denominator_hash{$u}; # calculate the correction factor for the unit 413 } else { 414 415 $unit_hash{$u} = $numerator_hash{$u} - $denominator_hash{$u}; # calculate the power of the fundamental unit in the unit 416 } 417 } 418 # return a unit hash. 419 return(%unit_hash); 420 } 421 422 sub process_term { 423 my $string = shift; 424 my %unit_hash = %fundamental_units; 425 if ($string) { 426 427 #split the numerator or denominator into factors -- the separators are * 428 429 my @factors = split(/\*/, $string); 430 431 my $f; 432 foreach $f (@factors) { 433 my %factor_hash = process_factor($f); 434 435 my $u; 436 foreach $u (keys %unit_hash) { 437 if ( $u eq 'factor' ) { 438 $unit_hash{$u} = $unit_hash{$u} * $factor_hash{$u}; # calculate the correction factor for the unit 439 } else { 440 441 $unit_hash{$u} = $unit_hash{$u} + $factor_hash{$u}; # calculate the power of the fundamental unit in the unit 442 } 443 } 444 } 445 } 446 #returns a unit hash. 447 #print "process_term returns", %unit_hash, "\n"; 448 return(%unit_hash); 449 } 450 451 452 sub process_factor { 453 my $string = shift; 454 #split the factor into unit and powers 455 456 my ($unit_name,$power) = split(/\^/, $string); 457 $power = 1 unless defined($power); 458 my %unit_hash = %fundamental_units; 459 460 if ( defined( $known_units{$unit_name} ) ) { 461 my %unit_name_hash = %{$known_units{$unit_name}}; # $reference_units contains all of the known units. 462 my $u; 463 foreach $u (keys %unit_hash) { 464 if ( $u eq 'factor' ) { 465 $unit_hash{$u} = $unit_name_hash{$u}**$power; # calculate the correction factor for the unit 466 } else { 467 my $fundamental_unit = $unit_name_hash{$u}; 468 $fundamental_unit = 0 unless defined($fundamental_unit); # a fundamental unit which doesn't appear in the unit need not be defined explicitly 469 $unit_hash{$u} = $fundamental_unit*$power; # calculate the power of the fundamental unit in the unit 470 } 471 } 472 } else { 473 die "UNIT ERROR Unrecognizable unit: |$unit_name|"; 474 } 475 %unit_hash; 476 } 477 478 # This is the "exported" subroutine. Use this to evaluate the units given in an answer. 479 sub evaluate_units { 480 my $unit = shift; 481 my %output = eval(q{process_unit( $unit)}); 482 %output = %fundamental_units if $@; # this is what you get if there is an error. 483 $output{'ERROR'}=$@ if $@; 484 %output; 485 } 486 #################
| aubreyja at gmail dot com | ViewVC Help |
| Powered by ViewVC 1.0.9 |