Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine
 
PerlMonks  

Conversion engine

by delirium (Chaplain)
on Jun 29, 2004 at 18:45 UTC ( [id://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

Replies are listed 'Best First'.
•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
Domain Nodelet?
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?Last hourOther CB clients
Other Users?
Others examining the Monastery: (5)
As of 2024-03-29 12:15 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found