3

soemone が次の状態で私を助けてくれませんか? $price と $lsec を比較しようとしています。

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

時々、ダンパーは同じ数字を (文字列として) 出力してジャンプします。

ここでダンパー出力:

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

私は何を間違っていますか?

ありがとうございました、

ご挨拶とハッピー イースター。

4

4 に答える 4

4

Perl 変数に格納される内容とその使用方法には違いがあります。1 を掛けると、変数が強制的に数値として使用されることは間違いありません。またSV、インタープリターに対して変数を表すデータ構造に数値が格納されます。このモジュールを使用して、Devel::PeekPerl が各変数に格納したものを確認できます。

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ように扱います。

ほとんどの場合、文字列を数値として使用することを明示的に強制する必要はありません。これは、演算子と関数が文字列を最も適切な形式で使用できるためです。たとえば、==and!=演算子は、オペランドを数値形式に変換して数値比較を行います。eqorを代わりに使用neすると、文字列比較が強制されます。use warnings数値以外の文字列を比較しようとすると、次の==警告が表示されるため、これは Perl スクリプトで常に使用するもう 1 つの理由です。

Argument "asdf" isn't numeric in numeric eq (==) at -e line 1.
于 2012-04-05T16:41:22.187 に答える
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';

したがって、8.51 は 8.5 と等しくないと Perl は正しく言っています。

私はあなたのことを疑う

($price * 100 + 0.5) / 100

$priceは小数点以下 2 桁に丸められるように意図されていますが、実際には$price0.005 増加するだけです。私はあなたが書くつもりだったと思います

int($price * 100 + 0.5) / 100

sprintfしかし、同じことを行う別の方法である値も入れます。

また

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

また

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

しかし、どちらもやり過ぎです!

于 2012-04-05T18:16:21.280 に答える
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

比較の性質、==またはあなたの場合!=、引数が数値であるかどうかにかかわらず、引数を数値に変換します。

于 2012-04-05T15:58:16.390 に答える
-3

あなたは何も悪いことをしていません。Perl はそれをダンプする前に文字列に変換します。比較には==!=数値比較にはeqandneを、文字列比較には and を使用します。Perl は、必要に応じて文字列と数値に変換します。

例:

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

$VAR1 = '3.1415';

于 2012-04-05T15:49:45.667 に答える