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

I have a perl newbie question here..

I have a successfull query however I would like it to not display the negative (-) symbol... how do i do this...

my $balance_due = $dbh=$db->prepare("SELECT balance FROM Table1 WHERE username='$authuser' and balance < '-.01'"); $dbh->execute(); ($balance_due) = $dbh->fetchrow_array();

the result ends up being -9.99
that's all fine and dandy but I need it to drop the (-) because I am filling in a payment form... and this has me owing them money!
Cheers,
-Paul

edited: Tue Jul 1 13:43:00 2003 by jeffa - code tags, entity unescaping

Replies are listed 'Best First'.
Re: Chomp Maybe?
by The Mad Hatter (Priest) on Jul 01, 2003 at 04:43 UTC
    A couple points:

    When using DBI and prepare, use placeholders. If you don't know what they are, read the doc. To put it simply, you can put a ? in the prepare statement, pass values for each in the execute, and it will properly quote it for you. In your case, something like this

    my $dbh = $db->prepare("SELECT balance FROM Table1 WHERE username=? an +d balance < '-.01'"); $dbh->execute($authuser); my ($balance_due) = $dbh->fetchrow_array;
    would work. This is good for untrusted data.

    Anyway, the easiest solution to your problem would be to simply negate the value, which would yield a positive. So something like

    $balance_due = -$balance_due # or $balance_due = $balance_due * -1;
    would be good and result in $balance_due being equal to 9.99.

    To answer your question using a different way, you could also use a substitution regex

    $balance_due =~ s/-//;
    to strip out (literally replace it with nothing) the first - it finds. If you don't understand what it going on, read up on perlretut.

    Added Second paragraph.

      Actually, I think it would be better to just get the absolute value:

      $balance_due = abs($balance_due);

      This protects you in the event that $balance_due is a positive number (which shouldn't happen according to the SQL, but I've always beleived that a good programmer is someone who looks both ways on a one way street). It's also close enough in speed to negation that random noise is a factor in execution time. Code:

      #!/usr/bin/perl use strict; use warnings; use Benchmark qw(cmpthese); my $data = -12345; my $count = pop || 500000; cmpthese($count, { negate => sub { my $i = -$data }, absolute => sub { my $i = abs($data) }, regex => sub { my ($i) = $data =~ s/-// }, });

      Results:

      Benchmark: timing 500000 iterations of absolute, negate, regex... absolute: 1 wallclock secs ( 1.24 usr + 0.00 sys = 1.24 CPU) @ 40 +4858.30/s (n=500000) negate: 1 wallclock secs ( 1.15 usr + 0.00 sys = 1.15 CPU) @ 43 +3275.56/s (n=500000) regex: 3 wallclock secs ( 3.16 usr + 0.00 sys = 3.16 CPU) @ 15 +8328.06/s (n=500000) Rate regex absolute negate regex 158328/s -- -61% -63% absolute 404858/s 156% -- -7% negate 433276/s 174% 7% --

      ----
      I wanted to explore how Perl's closures can be manipulated, and ended up creating an object system by accident.
      -- Schemer

      Note: All code is untested, unless otherwise stated

        ++, you're absolutely right. When writing up my node, I forgot all about just getting the absolute value. ; )
      Works like a charm! You guys are awesome! Thanks for your prompt reply! Regards, -Paul
Re: Chomp Maybe?
by hossman (Prior) on Jul 01, 2003 at 04:48 UTC
    I can think of three ways to get what you want...
    • You can take the negative of the value in the sql...
      $dbh=$db->prepare("SELECT -balance FROM Table1 WHERE username='$authuser' and balance < '-.01'"); $dbh->execute(); ($balance_due) = $dbh->fetchrow_array();
    • You can take the negative of the value in the perl...
      $dbh=$db->prepare("SELECT -balance FROM Table1 WHERE username='$authuser' and balance < '-.01'"); $dbh->execute(); ($tmp) = $dbh->fetchrow_array(); $balance_due = 0 - $tmp;
    • You can use substr to strip out the first character...
      $dbh=$db->prepare("SELECT -balance FROM Table1 WHERE username='$authuser' and balance < '-.01'"); $dbh->execute(); ($tmp) = $dbh->fetchrow_array(); $balance_due = substr $tmp, 1;
    ...there are lots of other things you can do ... but I would recommend the first one above.
      Thanks again! -p
Re: Chomp Maybe?
by parv (Parson) on Jul 01, 2003 at 05:01 UTC

    There are quite a ways to drop the -ve sign...

    my $due = -9.98; printf "substr_idx: %s\nneg_one_mul: %s\nregex: %s\n" , substr_idx($due) , neg_one_mul($due) , regex($due); sub substr_idx { my $number = shift; return -1 < index($number , '-' , 0) ? substr($number , 1) : $number; } sub neg_one_mul { my $number = shift; return $number =~ m/^-/ ? $number * -1 : $number; } sub regex { my $number = shift; return $number =~ m/^- (.+)/x ? $1 : $number; }

    ...Whatever you do just do not try to compare a floating point number (-9.98) against an integer (0) (or another float) -- due to inherent error in number representation -- w/o using some minimum difference that you would treat to be same as zero.

Re: Chomp Maybe?
by flounder99 (Friar) on Jul 01, 2003 at 14:30 UTC
    There is also abs which return the absolute value.
    my $val = -9.99; print abs $val __OUTPUT__ 9.99

    --

    flounder