user897237
user897237

Reputation: 623

Converting strings to floats

could soemone help me with the following condition, please? I'm trying to compare $price and $lsec.

if( (sprintf("%.2f", ($price*100+0.5)/100)*1 != $lsec*1) )
{
                print Dumper($price,$lsec)
}

Sometimes the dumper prints same numbers(as strings) and jumps in. Thought, that multiplying with 1 makes floats from them...

Here dumper output:

$VAR1 = '8.5';
$VAR2 = '8.5';

What am I doing wrong?

Thank you,

Greetings and happy easter.

Upvotes: 4

Views: 13349

Answers (4)

Borodin
Borodin

Reputation: 126722

You are correct to say that multiplying a string by 1 will force it to be evaluated as a number, but the numeric != comparator will do the same thing. This is presumably a technique you have acquired from other languages as Perl will generally do the right thing and there is no need to force a cast of either operand.

Lets take a look at the values you're comparing:

use strict;
use warnings;

use Data::Dumper;

my $price = '8.5';
my $lsec = '8.5';

my $rounded_price = sprintf("%.2f", ($price * 100 + 0.5) / 100);
print "$rounded_price <=> $lsec\n";

if ( $rounded_price != $lsec ) {
  print Dumper($price,$lsec);
}

output

8.51 <=> 8.5
$VAR1 = '8.5';
$VAR2 = '8.5';

So Perl is correctly saying that 8.51 is unequal to 8.5.

I suspect that your

($price * 100 + 0.5) / 100

is intended to round $price to two decimal places, but all it does in fact is to increase $price by 0.005. I think you meant to write

int($price * 100 + 0.5) / 100

but you also put the value through sprintf which is another way to do the same thing.

Either

$price = int($price * 100 + 0.5) / 100

or

$price = sprintf ".2f", $price

but both is overkill!

Upvotes: 4

bonsaiviking
bonsaiviking

Reputation: 5995

There is a difference between what is stored in a Perl variable and how it is used. You are correct that multiplying by 1 forces a variable to be used as a number. It also causes the number to be stored in the SV data structure that represents the variable to the interpreter. You can use the Devel::Peek module to see what Perl has stored in each variable:

use Devel::Peek;
my $num = "8.5";
Dump $num;

outputs:

SV = PV(0xa0a46d8) at 0xa0c3f08
  REFCNT = 1
  FLAGS = (POK,pPOK)
  PV = 0xa0be8c8 "8.5"\0
  CUR = 3
  LEN = 4

continuing...

my $newnum = $num * 1;
Dump $num;
Dump $newnum;

outputs:

SV = PVNV(0xa0a46d8) at 0xa0c3f08
  REFCNT = 1
  FLAGS = (PADMY,NOK,POK,pIOK,pNOK,pPOK)
  IV = 8
  NV = 8.5
  PV = 0xa0be8c8 "8.5"\0
  CUR = 3
  LEN = 4
SV = NV(0x9523660) at 0x950df20
  REFCNT = 1
  FLAGS = (PADMY,NOK,pNOK)
  NV = 8.5

The attributes we are concerned with are PV (string pointer), NV (floating-point number), and IV (integer). Initially, $num only has the string value, but using it as a number (e.g. in multiplication) causes it to store the numeric values. However, $num still "remembers" that it is a string, which is why Data::Dumper treats it like one.

For most purposes, there is no need to explicitly force the use of a string as a number, since operators and functions can use them in the most appropriate form. The == and != operators, for example, coerce their operands into numeric form to do numeric comparison. Using eq or ne instead forces a string comparison. This is one more reason to always use warnings in your Perl scripts, since trying to compare a non-numeric string with == will garner this warning:

Argument "asdf" isn't numeric in numeric eq (==) at -e line 1.

Upvotes: 5

TLP
TLP

Reputation: 67900

This part:

($price*100+0.5)/100)

If you put in 8.5, you get back 8.505. Which naturally is not equal to 8.5. Since you do not change $price, you do not notice any difference.

Perl handles conversion automatically, so you do not need to worry about that.

my $x = "8.5";
my $y = 8.5;
print "Equal" if $x == $y; # Succeeds

The nature of the comparison, == or in your case != converts the arguments to numeric, whether they are numeric or not.

Upvotes: 1

Marius Kjeldahl
Marius Kjeldahl

Reputation: 6824

You're doing nothing wrong. Perl converts it to a string before dumping it. For comparisons, use == and != for numeric comparisons and eq and ne for a string comparisons. Perl converts to strings and numbers as needed.

Example:

$ perl -MData::Dumper -e "my $a=3.1415; print Dumper($a);"

$VAR1 = '3.1415';

Upvotes: -3

Related Questions