Your instinct to avoid a cascade of if statements is correct. That leads to hard to maintain code. There are some subtleties for a general solution however and in a production context you would want to write a test suite before you start implementing a solution - not least so that you have a good idea of where all the edge cases are.
The following code uses a couple of functions to change to and from float values:
use strict; use warnings; while (<DATA>) { my ($first, $second) = split; next if !$second; my $diff = ToUnit(ToFloat($first) - ToFloat($second)); print "$first - $second = $diff\n"; } sub ToUnit { my ($value) = @_; my $unitIndex = 0; my @units = ('', qw( k M G T)); my $neg = $value < 0; $value = -$value if $neg; while ($value >= 1000 && $unitIndex < $#units) { $value /= 1000; ++$unitIndex; } $value = -$value if $neg; return "$value$units[$unitIndex]"; } sub ToFloat { my ($str) = @_; my ($value, $unit) = $str =~ /([\d.+-]+)\s*([kMGT]?)/; my %mul = (k => 1e3, M => 1e6, G => 1e9, T => 1e12); my $neg = $value < 0; $value = -$value if $neg; $value *= $mul{$unit} if $unit && exists $mul{$unit}; $value = -$value if $neg; return $value; } __DATA__ 324k 324k 440k 533k 23T 224G 42G 42G 1.9T 709G 294k 294k 684k 684k 492k 492k 62M 64M 48k 41M 34M 433k 317k 812k
Prints:
324k - 324k = 0 440k - 533k = -93k 23T - 224G = 22.776T 42G - 42G = 0 1.9T - 709G = 1.191T 294k - 294k = 0 684k - 684k = 0 492k - 492k = 0 62M - 64M = -2M 48k - 41M = -40.952M 34M - 433k = 33.567M 317k - 812k = -495k
Note that K got changed to k. This code would be fairly easy to extend to handle standard SI suffixes, but that is left as an exercise for the learner.
In reply to Re: More elegant way than multiple "if"?
by GrandFather
in thread More elegant way than multiple "if"?
by Anonymous Monk
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |