Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

Conversion engine

by delirium (Chaplain)
on Jun 29, 2004 at 18:45 UTC ( #370573=CUFP: print w/ replies, xml ) Need Help??

I wrote this after I made a major mistake converting miles-per-hour to meters-per-second with a calculator. The "while(<DATA>)" can be replaced with "while(<>)" to accept command-line input.

Give the script input in the format:
Item1 = ## Item2
(e.g., inch = 2.54 cm)

Query conversions with either:
Item1 = ? Item2
(inch = ? cm)
..or..
N1/D1 = ? N2/D2
(meters/second = ? miles/hour)

#!/usr/bin/perl use strict; use warnings; # All primes less than 4096, used in factorization functions my @primes = (2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,9 +7,101, 103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,19 +3,197, 199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,30 +7,311, 313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,42 +1,431, 433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541,54 +7,557, 563,569,571,577,587,593,599,601,607,613,617,619,631,641,643,647,653,65 +9,661, 673,677,683,691,701,709,719,727,733,739,743,751,757,761,769,773,787,79 +7,809, 811,821,823,827,829,839,853,857,859,863,877,881,883,887,907,911,919,92 +9,937, 941,947,953,967,971,977,983,991,997,1009,1013,1019,1021,1031,1033,1039 +,1049, 1051,1061,1063,1069,1087,1091,1093,1097,1103,1109,1117,1123,1129,1151, +1153, 1163,1171,1181,1187,1193,1201,1213,1217,1223,1229,1231,1237,1249,1259, +1277, 1279,1283,1289,1291,1297,1301,1303,1307,1319,1321,1327,1361,1367,1373, +1381, 1399,1409,1423,1427,1429,1433,1439,1447,1451,1453,1459,1471,1481,1483, +1487, 1489,1493,1499,1511,1523,1531,1543,1549,1553,1559,1567,1571,1579,1583, +1597, 1601,1607,1609,1613,1619,1621,1627,1637,1657,1663,1667,1669,1693,1697, +1699, 1709,1721,1723,1733,1741,1747,1753,1759,1777,1783,1787,1789,1801,1811, +1823, 1831,1847,1861,1867,1871,1873,1877,1879,1889,1901,1907,1913,1931,1933, +1949, 1951,1973,1979,1987,1993,1997,1999,2003,2011,2017,2027,2029,2039,2053, +2063, 2069,2081,2083,2087,2089,2099,2111,2113,2129,2131,2137,2141,2143,2153, +2161, 2179,2203,2207,2213,2221,2237,2239,2243,2251,2267,2269,2273,2281,2287, +2293, 2297,2309,2311,2333,2339,2341,2347,2351,2357,2371,2377,2381,2383,2389, +2393, 2399,2411,2417,2423,2437,2441,2447,2459,2467,2473,2477,2503,2521,2531, +2539, 2543,2549,2551,2557,2579,2591,2593,2609,2617,2621,2633,2647,2657,2659, +2663, 2671,2677,2683,2687,2689,2693,2699,2707,2711,2713,2719,2729,2731,2741, +2749, 2753,2767,2777,2789,2791,2797,2801,2803,2819,2833,2837,2843,2851,2857, +2861, 2879,2887,2897,2903,2909,2917,2927,2939,2953,2957,2963,2969,2971,2999, +3001, 3011,3019,3023,3037,3041,3049,3061,3067,3079,3083,3089,3109,3119,3121, +3137, 3163,3167,3169,3181,3187,3191,3203,3209,3217,3221,3229,3251,3253,3257, +3259, 3271,3299,3301,3307,3313,3319,3323,3329,3331,3343,3347,3359,3361,3371, +3373, 3389,3391,3407,3413,3433,3449,3457,3461,3463,3467,3469,3491,3499,3511, +3517, 3527,3529,3533,3539,3541,3547,3557,3559,3571,3581,3583,3593,3607,3613, +3617, 3623,3631,3637,3643,3659,3671,3673,3677,3691,3697,3701,3709,3719,3727, +3733, 3739,3761,3767,3769,3779,3793,3797,3803,3821,3823,3833,3847,3851,3853, +3863, 3877,3881,3889,3907,3911,3917,3919,3923,3929,3931,3943,3947,3967,3989, +4001, 4003,4007,4013,4019,4021,4027,4049,4051,4057,4073,4079,4091,4093); my %definitions = (); my $define_re = qr!^(\w+)=([\d./]+)(\w+)$!; my $find_re = qr/^(\w+)=\?(\w+)$/; my $ratio_re = qr!^(\w+)/(\w+)=\?(\w+)/(\w+)$!; sub shrink { my ($num,$den) = @_; while ($num != int($num) || $den != int($den)) { $num *= 10; $den +*= 10; } for my $p (@primes) { my $lim = $num > $den ? int(sqrt($num)) : int(sqrt($den)); last if $p > $lim; while ($num % $p == 0 && $den % $p == 0) { $num /= $p; $den /= + $p; } } return ($num,$den); } sub num_den { my $value = shift; return ($value,1) unless $value =~ m!^([^/]+)/([^/]+)!; return ($1,$2); } sub list_definitions { for (keys %definitions) { print "Unit : $_\n"; my $tmp = $definitions{$_}; for (keys %$tmp) { my $num = $$tmp{$_}{num}; my $den = $$tmp{$_}{den}; print "= $num/$den $_ (" . $num/$den . ")\n"; } print "\n"; } } sub add_item { my ($unit1,$unit2,$num,$den) = @_; ($num,$den) = shrink ($num,$den); $definitions{$unit1}{$unit2}{num} ||= $num; $definitions{$unit1}{$unit2}{den} ||= $den; $definitions{$unit2}{$unit1}{num} ||= $den; $definitions{$unit2}{$unit1}{den} ||= $num; } sub add_definition { my ($unit1, $multiple, $unit2) = @_; my ($num,$den) = num_den($multiple); add_item($unit1,$unit2,$num,$den); my $growth = 1; while ($growth) { $growth = 0; for $unit1 (keys %definitions) { for $unit2 (keys %{$definitions{$unit1}}) { $num = $definitions{$unit1}{$unit2}{num}; $den = $definitions{$unit1}{$unit2}{den}; for my $key (keys %{$definitions{$unit2}}) { next if ($definitions{$key}{$unit1} || $key eq $un +it1); $growth++; my $n = $definitions{$unit2}{$key}{num}; my $d = $definitions{$unit2}{$key}{den}; add_item($key, $unit1, $den*$d, $num*$n); } } } } print "$unit1/$unit2 conversion added\n"; } sub seek_definition { my ($unit1, $unit2) = @_; if ($definitions{$unit1}{$unit2}) { my $num = $definitions{$unit1}{$unit2}{num}; my $den = $definitions{$unit1}{$unit2}{den}; print "$unit1 = $num/$den $unit2 (" . $num/$den . ")\n"; } else { print "Not enough information\n"; } } sub seek_ratio { my ($num1, $den1, $num2, $den2) = @_; if ($definitions{$num1}{$num2} && $definitions{$den1}{$den2}) { my $num = $definitions{$num1}{$num2}{num} * $definitions{$den1 +}{$den2}{den}; my $den = $definitions{$num1}{$num2}{den} * $definitions{$den1 +}{$den2}{num}; ($num, $den) = shrink($num, $den); print "$num1/$den1 = $num/$den $num2/$den2 (" . $num/$den . ") +\n"; } else { print "Not enough information\n"; } } print ': '; while(<DATA>) { $_ = lc $_; s/\s+//g; add_definition ($1, $2, $3) if (/$define_re/); seek_definition($1, $2) if /$find_re/; seek_ratio($1, $2, $3, $4) if /$ratio_re/; list_definitions if /^list$/; %definitions = () if /^clear$/; print ': '; } __DATA__ inch = 2.54 cm foot = 12 inch list mile = 5280 foot meter = 100 cm km = 1000 meter hour = 60 minute minute = 60 second mile = ? km meter/second = ? mile/hour

Comment on Conversion engine
Download Code
•Re: Conversion engine
by merlyn (Sage) on Jun 29, 2004 at 19:19 UTC
      I did, but I wouldn't have looked for it anyway. This was one of those fun problem solving excursions to kill some time.

      The fun things I had to figure out included playing with least common denominators, creating a data structure that included everything I needed but which wasn't too complex, and fleshing out the measurements table properly after new user input.

      Lots more fun than searching for a module would have been. And furthermore, how could someone build up coding mojo without retackling a problem that has already been solved? If I ever decide to contribute something completely unique and useful to the CPAN library, it will be because I have built up my skills solving things that have already been solved before.

Re: Conversion engine
by kelan (Deacon) on Jun 30, 2004 at 17:58 UTC

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: CUFP [id://370573]
Approved by grinder
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others pondering the Monastery: (5)
As of 2014-10-23 06:00 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    For retirement, I am banking on:










    Results (124 votes), past polls