2012-04-05 4 views
3

может помочь мне со следующим условием, пожалуйста? Я пытаюсь сравнить $ price и $ lsec.Преобразование струн в поплавки

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

Иногда Дампер печатает то же число (как строки) и прыгает в Мысль, что умножение с 1 делает поплавки из них ...

Здесь выход самосвала:.

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

Что я делаю не так?

Спасибо,

Приветствия и счастливой Пасхи.

+1

'$ price * 100 + 0.5', вероятно, не будет делать то, что вы ожидаете, если вы ожидаете округления. С '$ price = 8.5' эта часть уравнения даст' 850.5'. – TLP

+1

Запустите 'perl -e 'printf"% .2f ", 8.505'', чтобы увидеть, что вы делаете неправильно. – mob

+0

Вы сбрасываете '$ price' и' $ lsec', но это не цифры, которые вы сравниваете. –

ответ

3

Вы правильно сказать, что умножение строки на 1 заставит его для оценки как числа, но цифровой компаратор != будет делать то же самое. Это, по-видимому, метод, который вы приобрели на других языках, поскольку Perl, как правило, делает правильную вещь, и нет необходимости заставлять листинг какого-либо операнда.

Давайте посмотрим на значения вы сравниваете:

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); 
} 

выход

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

Так Perl правильно говорят, что 8,51 неодинаково до 8,5.

Я подозреваю, что ваш

($price * 100 + 0.5)/100 

предназначен для округления $price до двух знаков после запятой, но все это делает на самом деле является увеличение $price на 0,005. Я думаю, что вы имели в виду, чтобы написать

int($price * 100 + 0.5)/100 

но вы также поместить значение через sprintf что еще один способ сделать то же самое.

Либо

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

или

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

но и является излишеством!

+0

Когда у вас есть код осложнения внутри условного кода, трудно понять, что происходит. Лучшая часть ответа Бородина - это чистый код, который разъясняет проблему. –

-3

Вы ничего не делаете неправильно. Perl преобразует его в строку перед тем, как сбрасывать его. Для сравнения используйте == и != для числовых сравнений и eq и ne для сравнения строк. Perl преобразует в строки и числа по мере необходимости.

Пример:

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

$VAR1 = '3.1415';

+0

Вы не объяснили проблему - что 8.5, по-видимому, не соответствует 8.5 – Borodin

+0

Ну, неправильная часть не понимает, что математика с плавающей запятой, использующая ограниченную точность, часто немного нечеткая. –

1

Эта часть:

($price*100+0.5)/100) 

Если вы поставите в 8.5, вы получите обратно 8.505. Это, естественно, не равно 8.5. Поскольку вы не меняете $price, вы не заметите никакой разницы.

Perl обрабатывает автоматическое преобразование, поэтому вам не нужно беспокоиться об этом.

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

Характер сравнения, == или в случае != преобразует аргументы в числовой, являются ли они числовыми или нет.

3

Существует разница между тем, что хранится в переменной Perl и как она используется . Вы правы, что умножение на 1 заставляет переменную быть как номер. Это также приводит к тому, что номер сохраняется в структуре данных SV, которая представляет переменную интерпретатору. Вы можете использовать Devel::Peek модуль, чтобы увидеть, что Perl хранит в каждой переменной:

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

выходы:

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

продолжается ...

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

выходы:

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 

Атрибуты мы имеем дело с являются PV (указатель строки), NV (число с плавающей точкой) и IV (целое число). Первоначально $num имеет только строковое значение, но использование его как числа (например, в умножении) заставляет его хранить числовые значения. Однако $num все еще «помнит», что это строка, поэтому Data::Dumper относится к ней как к одному.

Для большинства целей не требуется явно принудительно использовать строку как число, так как операторы и функции могут использовать их в наиболее подходящей форме. Операторы == и !=, например, принуждают их операнды к числовой форме для численного сравнения. Вместо этого используется сравнение eq или ne. Это еще одна причина, чтобы всегда use warnings в ваших Perl скриптов, так что сравнивать нечисловое строку с == будет набрать это предупреждение:

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

Добавьте это к ответу Бородина, и у вас в значительной степени есть вся история. :) –

+0

Итак, у меня есть пример, где Data :: Dumper хранит мое значение как строку, но позволяет мне делать арифметику на нем. Если бы JSON :: PP не был настолько придирчивым к цитированию всего, я был бы в порядке. Итак, как же заставить хранилище скаляра в число? * 1 и +1 еще не работали для меня. – ericslaw

Смежные вопросы