Re: Exploiting Perls idea of what is a number
by moritz (Cardinal) on Jul 08, 2008 at 12:47 UTC
|
use Scalar::Util qw(looks_like_number);
sub compare {
my ($x, $y) = @_:
if (looks_like_number($x) && looks_like_number($y)){
return $x == $y;
} else {
return $x eq $y;
}
}
| [reply] [d/l] |
|
My first thoughts were in the direction of Scalar::Util::looks_like_number, too ... but that always leads to the consideration of what should be done with strings like '3567rubb13h'. Perl will numify that to 3567, yet Scalar::Util::looks_like_number will tell you that it *doesn't* look like a number. (It amuses me that perl is capable of bestowing a non-zero numerical value on something that doesn't even "look like a number".)
Does rovf want such a string to be kept as a string ? or should it instead be numified to 3567 ?
Cheers, Rob
| [reply] |
|
what should be done with strings like '3567rubb13h'
At the moment, this type of strings won't be a problem,
but if they appear (for example, with (the same) measurement unit appended, such as "450KB"), it would be fine to have them interpreted as number.
--
Ronald Fischer <ynnor@mm.st>
| [reply] |
Re: Exploiting Perls idea of what is a number
by Corion (Patriarch) on Jul 08, 2008 at 12:49 UTC
|
If you approach the equivalence from the other direction, it becomes easier:
Two strings are equal iff
- ... they are equal as characters
- or ... they are equal as numbers
When described that way, the expression becomes:
$a eq $b || $a == $b
This has the small drawback of equating undef and the empty string with 0 as well though.
Update It also has the other small drawback of considering all strings to be equal, which is a bit suboptimal... | [reply] [d/l] [select] |
|
| [reply] |
|
Maybe !($a cmp $b || $a <=> $b) would work... nope.
| [reply] [d/l] |
|
| [reply] |
|
|
|
|
$a eq $b || $a == $b
I think I was too early with my response. Your suggestion, as elegant as it looks, would fail if $a and $b are unequal strings. In this case $a eq $b would result false, and $a == $b would be evaluated, yielding an error message because the arguments are not numeric...
--
Ronald Fischer <ynnor@mm.st>
| [reply] [d/l] [select] |
|
Thank's a lot for the suggestions!! I think for my original problem I find your solution most convenient, but actually there is another part of the program where I now can replace my cumbersome regexp to test for numerics, by moritz's idea of using Scalar::Util.
--
Ronald Fischer <ynnor@mm.st>
| [reply] [d/l] |
Re: Exploiting Perls idea of what is a number
by linuxer (Curate) on Jul 08, 2008 at 14:47 UTC
|
What about the good old perlfaq4?
perldoc -q determine presents (regex) ways to determine if a scalar contains a number...
I checked Scalar::Util::looks_like_number and it refers to perlfaq4... ;o)
| [reply] |
Re: Exploiting Perls idea of what is a number
by zentara (Archbishop) on Jul 08, 2008 at 17:10 UTC
|
You might be interested in convert hex string to hex number. My conclusion? Perl makes text processing easy, but converting them to numbers can be tricky. Luckily, you usually don't need to do it too often.
| [reply] |
Re: Exploiting Perls idea of what is a number
by graff (Chancellor) on Jul 09, 2008 at 03:10 UTC
|
The following snippet is almost certainly not what you want, but I find it instructive...
#!/usr/bin/perl
use strict;
my $numrgx = qr/^-?[\d.]+(?:e[+-]\d{2})?$/;
my @try_these = (
"0.2000000000000001",
"0.3000000000000001"
);
for ( @try_these ) {
my $x = my $y = $_;
$y .= "1";
my $same = ( $x eq $y );
if ( ! $same and
( $x =~ /^-?\.?\d/ and $x =~ /$numrgx/ ) and
( $y =~ /^-?\.?\d/ and $y =~ /$numrgx/ )) {
$same = ( $x == $y );
}
my $cmp = ( $same ) ? "is the same as" : "differs from";
print "$x $cmp $y\n";
}
For me (macosx 10.4 on intel core 2 duo, perl 5.8.6), the output is:
0.2000000000000001 differs from 0.20000000000000011
0.3000000000000001 is the same as 0.30000000000000011
Have fun...
BTW, the reason for the funny looking condition -- checking matches for both /^-?\.?\d/ and for the more elaborate regex -- was that it seemed like an easy way to keep $numrgx relatively clear and simple, while still making sure that the string contains at least one digit (which $numrgx by itself does not guarantee).
(updated the initial match condition that checks for at least one digit, so that it would only accept "\d", "-\d", ".\d" or "-.\d" at the beginning of the string; of course, $numrgx is still faulty, since it allows multiple periods)
Another update -- I knew the regex approach above was silly, and I was curious to have a version that would make it easier to test for more boundary cases (where floating point limitations blur the "same/different" distinction), so here's a version with a better regex -- still not perfect, I suspect, but more fun because of the @ARGV options:
#!/usr/bin/perl
use strict;
my $numrgx = qr/^-?(?:\d+\.?\d*|\d*\.\d+)(?:e[+-]?\d{1,2})?$/;
my @try_these = ( @ARGV == 2 ) ? ( $ARGV[0] ) :
(
"0.2000000000000001",
"0.3000000000000001"
);
for ( @try_these ) {
my $x = $_;
my $y = ( @ARGV == 2 ) ? $ARGV[1] : $_ . "1";
my $same = ( $x eq $y );
if ( ! $same and
( $x =~ /$numrgx/ ) and
( $y =~ /$numrgx/ )) {
$same = ( $x == $y );
}
my $cmp = ( $same ) ? "is the same as" : "differs from";
print "$x $cmp $y\n";
}
With that, you can put a pair like "0.123e4 1.230e3" on the command line, and find out that these are the same; and if you do a pair like "0.123e45 1.230e44", these are different. (final update/fix was to add "?" after the first period in $numrgx) | [reply] [d/l] [select] |
Re: Exploiting Perls idea of what is a number
by syphilis (Archbishop) on Jul 08, 2008 at 13:32 UTC
|
| [reply] [d/l] |
|
Under the influence of use warnings FATAL => qw(numeric);
| [reply] [d/l] |
|
use strict;
use warnings;
my $value="abc";
my $t=eval { 0+$value };
print "$@\n";
prints
Argument "abc" isn't numeric in addition (+) at U:\develsv\ARTS\playground\eval_test1.pl line 4.
--
Ronald Fischer <ynnor@mm.st>
| [reply] [d/l] [select] |
|
|