briandfoy/PerlPowerTools

units script produces incorrect results for definitions that include a fractional factor

Closed this issue · 1 comments

The units script incorrectly handles fractional multipliers in both entry and in definitions. For example, the documentation (in the DESCRIPTION section) offers this usage example:

    You have: 1|2 inch
    You want: cm
        * 1.27
        / 0.78740157

Those numbers are correct. However, the actual output when you enter this example is:

You have: 1|2 inch
You want: cm
        * 0.635
        / 1.5748

Note that the values are squares of the correct values. Upon investigation I discovered that the lex subroutine is capturing fractions twice, causing the fraction to be multiplied by itself during reduction. This problem also occurs when the definition includes a fraction, not just on entry of a fractional unit. For example, the conversion from year to month (where month is defined in the DATA section as "1|12 year") yields this result:

You have: month
You want: year
        * 0.00694444
        / 144

The problem traces to this bit of code in the lex subroutine:

my $N = '(?:\d+\.\d+|\d+|\.\d+)(?:[eE][-+]?\d+)?';

 my @t = split /(
                  (?: \*.\* | !.! ) # Special 'new unit' symbol
               |  [()*-]                    # Symbol
               |  \s*(?:\/|\bper\b)\s*      # Division
               |  ($N\|$N)                  # Fraction
               |  $N                        # Decimal number
               |  \d+                       # Integer
               |  [A-Za-z_][A-Za-z_.]*      # identifier
               |  \s+                       # White space
               )/ox, $s;

Note that the $N regex includes ?: to disable group capturing. However, this does not carry through to the Fraction alternative within the split pattern. Changing the subpattern to (?:$N|$N) seems to completely resolve the issue.

I will attempt to clone the repo, fix this bug, and then push the fix.

Thanks for looking into this.