Re: Integer detection concept
by merlyn (Sage) on May 15, 2001 at 00:21 UTC
|
I'd frown on it because this is so much more straightforward:
sub is_int {
$_[0] == int $_[0];
}
-- Randal L. Schwartz, Perl hacker | [reply] [d/l] |
|
For regular numbers, this is works, but it also claims
'integerness' for things like '2na' and '4ever'. Would
a regexp be a reliable way of catching this, or is there
something better?
sub is_int
{
($_[0] =~ /^\-?\d+(?:\.\d+)?(?:e\+\d+)?$/
&& $_[0] == int $_[0]);
}
| [reply] [d/l] |
|
Maybe something like this:
sub is_int {
my $warned = 0;
local $SIG{__WARN__} = sub { $warned++ };
local $^W = 1;
$_[0] == int $_[0] and not $warned;
}
-- Randal L. Schwartz, Perl hacker | [reply] [d/l] |
|
I realized this after I pushed 'submit'...
I'm a dolt.
| [reply] |
(tye)Re: Integer detection concept
by tye (Sage) on May 15, 2001 at 00:40 UTC
|
Well, I can think of quite a few meanings of "is an integer".
- Fits in a Perl UV:
sub isUV {
my( $i )= @_;
return isIntVal($i) && $i == (0|$i);
}
- Fits in a Perl IV (no test provided)
- Fits in a Perl NV but has no fractional part:
sub isNVint {
my( $i )= @_;
return isIntVal($i) && $i == int($i);
}
- Is the (string) representation of an integer that may not fit into (1), (2), or (3):
sub isInt {
my( $i )= @_;
return $i =~ /^-?\d+\z/;
}
- A scalar that will result in (1), (2), or (3) w/o warning when used in a "numeric context":
sub isIntVal {
my( $i )= @_;
return $i =~ /^\s*[-+]?\d+\s*$/;
}
But (update) that doesn't cover "1.2e4", for example,
so you can also use (updated):
sub isIntVal2 {
my( $i )= @_;
my $warn= 0;
{
local( $^W )= 1;
# my $warn= 0;
local( $SIG{__WARN__} )= sub { $warn++ };
$i= 0+$i;
}
return ! $warn && int($i) == $i;
}
- A string that will result in literal (1), (2), or (3) w/o warning when used in Perl code (for example, with eval). This one has to allow for _ in the middle, "0x" or "0b" at the start, etc.
And, in particular, (4) has plenty of room for changes based on what you think should be allowed. And my test for (3) doesn't account for numbers that don't accurately fit in an NV.
I really think that the best solution involves making the looks_like_number() C subroutine that Perl itself uses available to scripts.
-
tye
(but my friends call me "Tye")
| [reply] [d/l] [select] |
|
No. 5 looks like a pretty cool solution to the problem. There's one thing with this code though that I can't figure out. It looks to me that you're using a closure, but it doesn't work. When I try to run this code Perl complains: Global symbol "$warn" requires explicit package name
I could only make this work by removing the outer { }. Does anyone know why this closure doesn't work?
| [reply] |
|
| [reply] |
|
| [reply] [d/l] |
|
|
|
Re: Integer detection concept
by traveler (Parson) on May 15, 2001 at 01:45 UTC
|
I am confused by the question. Consider
$x = 17;
for $i (1..10){
$x = sqrt($x);
}
for $i (1..10){
$x *= $x;
}
print $x;
prints 17.00000000000002 on my perl 5.005_003 on an x86. Is that an integer? merlin's comment shows how to see if a number is a "good" integer, but if you are using this in some mathematics, you might check for some fudge as it is fairly easy to get a non-integer that "should be" an integer.
You probably knew that, but it might not be obvious to everyone...
--traveler | [reply] [d/l] |
Re (tilly) 1: Integer detection concept
by tilly (Archbishop) on May 15, 2001 at 03:40 UTC
|
| [reply] |
|
I'm not computer whizzy enough to explain in detail but I think that if you ask a computer to store a floating point number which is obtained as a fraction (eg. $a = 1/3;) then you get 0.333333333333333 (not 0.3 recurring) to however many decimal places. If yuo then operate on this number, because it does not remain a fraction, the results are "rounded". So to compare the result of iakobski's sqrt and subsequent squaring to 1/3 would not match using ==.
In this case it is only integers (whole numbers - no decimal places) which are being discussed so they must be stored more sensible and a numerical comparison (==) will be more efficient than comparing the two strings (especially on large numbers, possibly several hundreds of thousands of times through a loop).
I think essentially the eq and ne have to go through both "strings" a character at a time and compare them but == or != can just say these numbers are('nt) the same.
larryk
----------------------------------------------------
$less->{'chars'} = `"time in the pub" | more`; # :-D
| [reply] [d/l] [select] |
Re: Integer detection concept
by mothra (Hermit) on May 15, 2001 at 17:33 UTC
|
As one might expect, this is already answered in the FAQ:
How do I determine whether a scalar is a number/whole/integer/float?
Assuming that you don't care about IEEE notations like "NaN" or "Infinity", you probably just want to use a regular expression.
...
if (/^-?\d+$/) { print "is an integer\n" }
if (/^[+-]?\d+$/) { print "is a +/- integer\n" }
...
| [reply] [d/l] |
Re: Integer detection concept
by tachyon (Chancellor) on May 16, 2001 at 03:46 UTC
|
Your code and Randal's code only works if you believe a foobar is an integer ;-)
C:\>type test.pl
foreach (1.2, foobar){
print &is_int ($_)?"$_ is an integer\n":"$_ is not an integer\n";
}
sub is_int{
my $testvar =shift;
use integer;
my $intval=$testvar_*1;
no integer;
return $testvar == $intval;
}
C:\>perl test.pl
1.2 is not an integer
foobar is an integer
C:\>
C:\>type test.pl
$_ = 'foobar';
print "'$_' is an integer" if is_int($_);
sub is_int {
$_[0] == int $_[0];
}
C:\>perl test.pl
'foobar' is an integer
C:\>
Sadly this is not the only problem. You might also try testing foo2you and foo2.1
tachyon
| [reply] [d/l] |