return @mve;
};
+my @mv_names= qw(mass volume);
+my $canon_numeric= $h->{'canon_numeric'}= sub {
+ print STDERR "CANNUM @_\n";
+ my $sep= '';
+ my $out= '';
+ foreach my $ix (qw(0 1)) {
+ next unless defined $_[$ix];
+ $out .= $sep; $sep= ' ';
+ $out .= sprintf "%g%s", $_[$ix], (qw(kg l))[$ix];
+ }
+ return $out;
+};
+
$h->{'deltas'}= [ ];
print STDERR "NDELTA0 $#{ $h->{'deltas'} }\n";
print STDERR "TERM L=\`$1' M=\`$2' R=\`$''\n";
my ($signum,$signopstr)=
$2 =~ m/^p|^\+/ ? (+1,'plus') : (-1,'minus');
- my (@mve)= $parse_numeric->($rhs, 0);
- ${ $h->{Emsg} }= $mve[2] if defined $mve[2];
- unshift @{ $h->{'deltas'} }, [ @mve,$signum,$signopstr ];
+ my @mveco;
+ if ($rhs =~ m/^\s*(\d{1,2}(?:\.\d{0,4})?)\%\s*$/) {
+ my $pct= 100.0 + $signum * $1;
+ @mveco= ($pct,$pct,undef);
+ push @mveco, sprintf "%s %g%%", $signopstr, $1;
+ push @mveco, sub {
+ return undef unless defined $_[0];
+ $_[0] * $_[1] / 100.0
+ };
+ } else {
+ @mveco= $parse_numeric->($rhs, 0);
+ if (!defined $mveco[2]) {
+ push @mveco, $signopstr.' '.$canon_numeric->(@mveco);
+ push @mveco, sub {
+ ${ $h->{Emsg} }= "Cannot add or subtract".
+ " mass to/from volume"
+ unless defined $_[0];
+ $_[0] + $_[1] * $signum
+ };
+ }
+ }
+ ${ $h->{Emsg} }= $mveco[2] if defined $mveco[2];
+ unshift @{ $h->{'deltas'} }, [ @mveco ];
print STDERR "NDELTA $#{ $h->{'deltas'} }\n";
$_= $lhs;
}
</%args>
<%perl>
-return if length ${ $h->{Emsg} };
-
-my @mv_names= qw(mass volume);
+my $canon_numeric= $h->{'canon_numeric'};
-my $canon_numeric= sub {
- print STDERR "CANNUM @_\n";
- my $sep= '';
- my $out= '';
- foreach my $ix (qw(0 1)) {
- next unless defined $_[$ix];
- $out .= $sep; $sep= ' ';
- $out .= sprintf "%g%s", $_[$ix], (qw(kg l))[$ix];
- }
- return $out;
-};
+return if length ${ $h->{Emsg} };
my @mv;
+my @mv_names= qw(mass volume);
if (@{ $h->{Specs} }) {
@mv= @{ $h->{Results}[0] }[1,2];
- print STDERR "INITIAL VESSEL @mv\n";
} else {
@mv= @{ $h->{'initial'} };
${ $h->{Canon} }= $canon_numeric->(@mv);
}
+print STDERR "INITIAL @mv\n";
print STDERR "NDELTAE $#{ $h->{'deltas'} }\n";
foreach my $delta (@{ $h->{'deltas'} }) {
foreach my $ix (qw(0 1)) {
next unless defined $delta->[$ix];
print STDERR "DELTA I $ix\n";
- if (!defined $mv[$ix]) {
- ${ $h->{Emsg} }= "Cannot add or subtract".
- " $mv_names[$ix] to/from $mv_names[!$ix]";
- return;
- }
- $mv[$ix] += $delta->[$ix] * $delta->[3];
+ $mv[$ix] = $delta->[4]->($mv[$ix], $delta->[$ix]);
+ return if length ${ $h->{Emsg} };
}
- ${ $h->{Canon} }.= " $delta->[4] ". $canon_numeric->(@$delta);
+ ${ $h->{Canon} }.= ' '.$delta->[3];
}
if (@{ $h->{Specs} } || @{ $h->{'deltas'} }) {
like:
<dl>
<dt>sloop
-<dd>The capacity of a sloop, exactly
+<dd>The capacity of a sloop, leaving no allowance for rum and shot
+<dt>sloop - 1%
+<dd>The capacity of a sloop minus 1%
<dt>20t 13kl
-<dd>20 tonnes (20,000kg), 13 kilolitres (13,000l)
+<dd>13 tonnes (13,000kg), 20 kilolitres (20,000l)
<dt>sloop - 100l 100kg
<dd>The capacity of a sloop minus 100l, minus 100kg
<dt>2t plus 500kg minus 200kg
<dd>2300kg, with no limit on volume
</dl>
+Evaluation is strictly from left to right.
+
+<p>
Formally, the capacity is a list of terms, all but the first preceded
by one of <kbd>-</kbd>, <kbd>minus</kbd>, <kbd>+</kbd>,
<kbd>plus</kbd>. Each term may specify a mass and/or a volume
(separated by a space), as a number followed (without an intervening
space) by a unit (<kbd>t</kbd>, <kbd>kg</kbd>, <kbd>kl</kbd> or
-<kbd>l</kbd>). The first term may be a ship name or abbrevation
-instead. If the first term specifies only one of mass or volume, all
-the subsequent terms may only adjust that same value.
+<kbd>l</kbd>). Alternatively each term except the first may specify a
+percentage, which is applied as a percentage change to the answer from
+all the preceding terms. The first term may be a ship name or
+abbrevation instead. If the first term specifies only one of mass or
+volume, all the subsequent terms may only adjust that same value.
<h3>Expected losses</h3>