Question

Considérez le code suivant et sa sortie:

Code

#!/usr/bin/perl -w
use strict;
use Data::Dumper;
my $HOURS_PER_DAY = 24.0 * 1.0;
my $BSA = 1.7 * 1.0;
my $MCG_PER_MG = 1000.0 * 1.0;
my $HOURS_DURATION    = 20.0 * $HOURS_PER_DAY;
my $dummy = $HOURS_PER_DAY * $BSA * $MCG_PER_MG * $HOURS_DURATION;
print Dumper($HOURS_PER_DAY);
print Dumper( $BSA);
print Dumper( $MCG_PER_MG);
print Dumper( $HOURS_DURATION );

Sortie

$VAR1 = 24;
$VAR1 = '1.7';
$VAR1 = 1000;
$VAR1 = 480;

Comme vous pouvez le constater, la deuxième variable est traitée comme une chaîne, tandis que la première et la quatrième sont traitées comme un nombre. Quelqu'un a une idée de la logique sous-jacente?

Modifier les calculs arithmétiques ajoutés ne résolvent pas complètement le problème (voir la variable $ BSA).

$ perl -v

This is perl, v5.10.0 built for cygwin-thread-multi-64int
(with 6 registered patches, see perl -V for more detail)

Copyright 1987-2007, Larry Wall
Était-ce utile?

La solution

Le travail de Data :: Dumper consiste à sérialiser des données et vous ne pouvez pas en dire beaucoup sur ce que perl fait en interne avec les données en fonction de leur sortie. Le module Devel :: Peek peut vider les indicateurs et les valeurs sous-jacents stockés dans les variables. Le POD Devel :: Peek explique l’importance des drapeaux.

#!/usr/bin/perl

use warnings;
use strict;
use Devel::Peek;

my $HOURS_PER_DAY = 24.0 * 1.0;
my $BSA = 1.7 * 1.0;
my $MCG_PER_MG = 1000.0 * 1.0;
my $HOURS_DURATION    = 20.0 * $HOURS_PER_DAY;
my $dummy = $HOURS_PER_DAY * $BSA * $MCG_PER_MG * $HOURS_DURATION;

Dump($HOURS_PER_DAY);
Dump($BSA);
Dump($MCG_PER_MG);
Dump($HOURS_DURATION);

__END__
SV = PVNV(0xd71ff0) at 0xd87f90
  REFCNT = 1
  FLAGS = (PADBUSY,PADMY,IOK,NOK,pIOK,pNOK)
  IV = 24
  NV = 24
  PV = 0
SV = PVNV(0xd71fc8) at 0xd87f60
  REFCNT = 1
  FLAGS = (PADBUSY,PADMY,NOK,pIOK,pNOK)
  IV = 1
  NV = 1.7
  PV = 0
SV = PVNV(0xd72040) at 0xd87f40
  REFCNT = 1
  FLAGS = (PADBUSY,PADMY,IOK,NOK,pIOK,pNOK)
  IV = 1000
  NV = 1000
  PV = 0
SV = IV(0xd8b408) at 0xd87f30
  REFCNT = 1
  FLAGS = (PADBUSY,PADMY,IOK,pIOK)
  IV = 480
# compare the above output to output without the assignment to $dummy:
SV = IV(0x7b0eb8) at 0x7adf90
  REFCNT = 1
  FLAGS = (PADBUSY,PADMY,IOK,pIOK)
  IV = 24
SV = NV(0x7c7c90) at 0x7adf60
  REFCNT = 1
  FLAGS = (PADBUSY,PADMY,NOK,pNOK)
  NV = 1.7
SV = IV(0x7b13d8) at 0x7adf40
  REFCNT = 1
  FLAGS = (PADBUSY,PADMY,IOK,pIOK)
  IV = 1000
SV = IV(0x7b1408) at 0x7adf30
  REFCNT = 1
  FLAGS = (PADBUSY,PADMY,IOK,pIOK)
  IV = 480

Autres conseils

Tout votre concept selon lequel Perl considère les variables comme des chaînes ou des nombres est erroné. Perl traitera vos variables de la bonne façon lorsque vous en aurez besoin, par exemple, les opérateurs arithmétiques always traiteront leurs arguments comme des nombres (en supposant que vous n'abusiez pas de la surcharge d'opérateurs ou autres).

Ne vous inquiétez pas pour ça: Perl sait ce qu'il fait.

Data :: Dumper utilise un modèle simple sur la représentation sous forme de chaîne de la variable pour déterminer s’il s’agit d’un nombre. À partir du code source:

...
elsif ($val =~ /^(?:0|-?[1-9]\d{0,8})\z/) { # safe decimal number
  $out .= $val;
}
else {               # string
...

Cela ne correspond pas aux nombres avec une virgule décimale qui explique le comportement observé.

Façon rapide et sale de forcer un contexte numérique:

print Dumper( $HOURS_DURATION + 0.0 );

Si votre préoccupation est de savoir comment les données seront affichées, la méthode la plus simple consiste à: -

printf "%5.2d",$HOURS_DURATION;
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top