sidmuchrock has asked for the wisdom of the Perl Monks concerning the following question:

I'm wondering how to do this better than my 4 line method. Feels like I'm missing something obvious. But example code below works Basically I want to show weight * price = total but allow a minimum weight but if it's a negative weight it should be the reverse of the above Expected results: 2.3 = $23 .3 = $10 0 = $10 -.3 = -$10 -2.3 = -$23
$wt = $ARGV[0]; $min = 1; $price = 10; while ($wt ne '') { $nwt = abs($wt); $nwt = $min if $nwt<$min; $total = $nwt*$price; $total = -$total if $wt<0; print "Price: $total\n"; print "Next Weight: "; chomp($wt = <stdin>); }

Replies are listed 'Best First'.
Re: Some simple math and absolute values (updated)
by haukex (Archbishop) on May 23, 2020 at 07:56 UTC

    TIMTOWTDI...

    use warnings; use strict; our $MIN = 1; our $PFACT = 10; sub price { my $weight = shift; return abs $weight < $MIN ? ( $weight < 0 ? -$PFACT : $PFACT ) : $PFACT * $weight; } use Test::More; is price($$_[0]), $$_[1] for [ 5.0, 50],[ 2.3, 23],[ 1.1, 11],[ 1, 10],[ 0.3, 10],[0,10], [-5.0,-50],[-2.3,-23],[-1.1,-11],[-1,-10],[-0.3,-10]; { local $MIN = 3; is price($$_[0]), $$_[1] for [ 5.0, 50],[ 2.3, 10],[ 1.1, 10],[ 1, 10],[ 0.3, 10],[0,10], [-5.0,-50],[-2.3,-10],[-1.1,-10],[-1,-10],[-0.3,-10]; } { local $PFACT = 5; is price($$_[0]), $$_[1] for [ 5.0, 25],[ 2.3, 11.5],[ 1.1, 5.5],[ 1, 5],[ 0.3, 5],[0,5], [-5.0,-25],[-2.3,-11.5],[-1.1,-5.5],[-1,-5],[-0.3,-5]; } { local ($MIN,$PFACT) = (3,5); is price($$_[0]), $$_[1] for [ 5.0, 25],[ 2.3, 5],[ 1.1, 5],[ 1, 5],[ 0.3, 5],[0,5], [-5.0,-25],[-2.3,-5],[-1.1,-5],[-1,-5],[-0.3,-5]; } done_testing;

    Update: Expanded test cases. Please check if this is what you want, keeping in mind the caveat that jo37 mentioned!

      Which can be "golfed" to
      $PFACT * ($weight, ($weight >= 0) * 2 - 1)[abs $weight < $MIN]

      map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
Re: Some simple math and absolute values
by jo37 (Curate) on May 23, 2020 at 12:03 UTC

    The values in the given example have one small flaw:
    As $min is one, some code would pass a test even if it didn't calculate $min * $price but used $price instead.

    Greetings,
    -jo

    $gryYup$d0ylprbpriprrYpkJl2xyl~rzg??P~5lp2hyl0p$
Re: Some simple math and absolute values
by parv (Parson) on May 23, 2020 at 06:48 UTC

    Could reduce to 2 statements, does not seem any better ...

    $nwt = abs( $wt ); $total = ( $nwt < $min ? $min : $nwt ) * $price * ( $wt < 0 ? -1 : 1 ) ;
Re: Some simple math and absolute values
by BillKSmith (Monsignor) on May 23, 2020 at 23:37 UTC
    The following code may not be any shorter than yours, but I find it much easier to understand. The tests demonstrate that it produces the same total as yours for a variety of weights.
    use strict; use warnings; use Test::More tests => 11; my $min = 1; my $price = 10; sub total { my $wt = $_[0]; my $Total = ($wt < -$min) ? $price * $wt : ($wt < 0 ) ? $price * (-$min) : ($wt < $min ) ? $price * $min : $price * $wt ; return $Total; } sub refrence { my $wt = $_[0]; my $nwt = abs($wt); $nwt = $min if $nwt<$min; my $total = $nwt*$price; $total = -$total if $wt<0; return $total; } for (0..10) { my $trial_wt = .3 * ($_ -5); is( total($trial_wt), refrence($trial_wt), "Weight: $trial_wt"); }

    OUTPUT:

    1..11 ok 1 - Weight: -1.5 ok 2 - Weight: -1.2 ok 3 - Weight: -0.9 ok 4 - Weight: -0.6 ok 5 - Weight: -0.3 ok 6 - Weight: 0 ok 7 - Weight: 0.3 ok 8 - Weight: 0.6 ok 9 - Weight: 0.9 ok 10 - Weight: 1.2 ok 11 - Weight: 1.5
    Bill
Re: Some simple math and absolute values
by syphilis (Archbishop) on May 23, 2020 at 02:19 UTC
    Hi,

    I think this will do the same:
    Update: No, it fails to do the right thing for negative $wt values greater than -1.
    $wt = $ARGV[0]; $min = 1; $price = 10; while ($wt ne '') { $wt = $min if abs($wt)< $min; print "Price: " $wt * $price, "\n"; print "Next Weight: "; chomp($wt = <stdin>); }
    Cheers,
    Rob
Re: Some simple math and absolute values
by 1nickt (Canon) on May 23, 2020 at 03:20 UTC

    Hi,

    I am not a math expert nor an algorithm expert nor a golfer, Perl or otherwise, but maybe something like this?

    my $price = ($wt || 1) * 10; $price = 10 * $price/abs($price) if abs($price) < 10;

    Output:

    perl blrg.pl 2.3 Price: 23 Next Weight: .3 Price: 10 Next Weight: 0 Price: 10 Next Weight: -.3 Price: -10 Next Weight: -2.3 Price: -23 Next Weight:

    Hope this helps!


    The way forward always starts with a minimal test.
      This was what I was missing last night! I kept trying to say if $wt/abs($wt) and it was dying in the 0 case, but by turning the 0 to $min in the possible total and then checking $total/abs($total) that solved. it. Thank you.
      $total = ($wt || $min) * $price; $total = $total/abs($total) * $price * $min if abs($wt) < $min +;