开发者

check if a number is int or float

In perl, I want to check if the given variable holds a floating point number of not. To check this I am using,

my $Var = 0.02 # Floating point number

if (int($Var) != $Var) {

   # floating point numb开发者_StackOverflower
}

But the above code will not work for 0.0,

How can I achieve this?


This is a FAQ. See How do I determine whether a scalar is a number/whole/integer/float?

You can also use Scalar::Util::Numeric.

Interestingly, while

#!/usr/bin/perl

use strict; use warnings;
use Scalar::Util::Numeric qw(isint);

my $x = 0.0;
print "int\n" if isint $x;

prints int (not surprising if you look at the source code), based on @tchrist's comment, it should be possible to look at the information supplied in the variables structure to distinguish 0 from 0.0:

#!/usr/bin/perl

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

my $x  = 0.0; print Dump $x;
my $y  = 0;   print Dump $y;
   $y *= 1.1; print Dump $y;

Output:

SV = NV(0x18683cc) at 0x182c0fc
  REFCNT = 1
  FLAGS = (PADMY,NOK,pNOK)
  NV = 0
SV = IV(0x182c198) at 0x182c19c
  REFCNT = 1
  FLAGS = (PADMY,IOK,pIOK)
  IV = 0
SV = PVNV(0x397ac) at 0x182c19c
  REFCNT = 1
  FLAGS = (PADMY,NOK,pNOK)
  IV = 0
  NV = 0
  PV = 0

It seems to me that the check would have to just look at if the NOK flag is set. It takes me ages to write even the simplest XS so I won't provide an implementation.


($Var - int($Var))?'float':'int'


You can use autobox::universal module wich is part of autobox.

#! /usr/bin/perl

use autobox::universal qw(type);

my $x = 42;
print type($x), "\n";;

$x = 42.0;
print type($x), "\n";

Output:

INTEGER
FLOAT


Why not use regex?

print "Is INT\n" if ($test =~/-*\d+/);
print "Is FLOAT\n" if ($test =~/-*\d+\.\d+/);

#$test = "1234" = INT
#$test = "12.3" = FLOAT

Re-edited 2019-12-24 to work correctly in Perl (MHN)


Perl5 return true or false if a variable string is a float:

You have to either roll your own by being clever with regexes and handle edge cases, or else defer to a 3rd party library and catch and suppress exceptions thrown by them.

sub does_this_variable_look_like_a_perl_float { 
    $number_of_arguments = 0 + @_; 
    #If you passed too many arguments, exit program, it's certainly not a float 
    if ($number_of_arguments != 1){ 
        print "ArgumentException, you passed an incorrect number of parameters.\n"; 
        return 0;  
    }   
    $variable = $_[0]; 
    $first_argument = shift; 
    if ( ref(\$first_argument) eq 'ARRAY') { 
        #arrays are not floats 
        print("arrays are not floats"); 
        return 0;  
    }   
    if ($variable =~ m/^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/){ 
        return 1;  
    }   
    return 0;  
} 


sub is_convertable_to_float__casting_and_killing_canaries { 
    $number_of_arguments = 0 + @_; 
    if ($number_of_arguments != 1){ 
        print "ArgumentException, you passed an incorrect number of parameters.\n"; 
        return 0;  
    }   
    my $result = 0;  
    $variable = $_[0]; 
    use Error qw(:try); 
    try { 
        use Scalar::Util qw(blessed dualvar isdual readonly refaddr reftype 
                    tainted weaken isweak isvstring looks_like_number 
                    set_prototype); 
        $numeric_code = looks_like_number( $variable );  
        if ($numeric_code != 0){ 
            $result = 1;  
        } 
        else{ 
            $result = 0;  
        } 
    }   
    catch Error with { $result = 0; };  
    return $result; 
} 


sub is_float { 
    #Darkwing Duck says "I like Perl5's duck typing, so it's a float when I  
    #look at it with my regex goggles, and it overlays yes" 
    return does_this_variable_look_like_a_perl_float(@_); 

    #Beta-7 insists on a practical solution, the variable is a float when I ask 
    #a 3rd party library if it is a float, and the 3rd party classifies it 
    #as a float, without any major malfunctions or trapped bubble up implimentationitis. 
    #return is_convertable_to_float__casting_and_killing_canaries(@_); 

} 

#NO: 
print(is_float(""));            #blankstring 
print(is_float("yeah"));        #strings with ascii letters 
print(is_float(" "));           #space whitespace 
print(is_float("\t\n"));        #tabs and newlines 
print(is_float(" 58 "));        #whitespace on either side 
print(is_float('e'));           #e by itself 
print(is_float('0xf'));         #0x hexidecimal  
print(is_float('\xf'));         #\x hexidecimal  
print(is_float("1,234.56"));    #commas as thousands separator 
print(is_float("35,5"));        #European, East oriental comma
print(is_float(undef));         #undef and variants 
print(is_float("NaN"));         #nan and variants 
print(is_float("inf"));         #nan and variants 
print(is_float("infinity"));    #inf and variants 
print(is_float("null"));        #null and variants 
print(is_float("12.34.56"));    #double dots 
print(is_float("四"));          #unicode, oriental japanese 4 
print(is_float("#56"));         #Pound sign 
print(is_float("56%"));         #percent sign 
print(is_float("56^3"));        #arithmatic expressions not interpreted 
print(is_float("+1e1.5"));      #decimals in exponent 
print(is_float("+-1"));         #make up your mind 
print("\n"); 

#YES: 
print(is_float(35));            #bare integer 
print(is_float(35.5));          #decimal numeric, typical float 
print(is_float(35.00000));      #superfluous zeros to the right 
print(is_float("35"));          #bare integer packaged as string 
print(is_float(0));             #integer zero 
print(is_float(07));            #leading zero makes for octal 
print(is_float(000));           #stealth octal zero 
print(is_float(-13));           #negative numbers 
print(is_float(12e2));            #integers with e scientific notation 
print(is_float(12.2e2));          #float with scientific notation 
print(is_float(12.E4));           #float with e after period and scientific notation 
print(is_float(.4));              #mantissa only 
print(is_float(6e7777777777777)); #huge number 
print(is_float(1.797693e+308));   #max value 
print(is_float("0E0"));           #zero in exponential 
print(is_float(0**0));            #exponentiation 
print(is_float("-5e-5"));         #raise a negative to a negative 
print(is_float("+5e+5"));         #raise a positive with plus to a positive 
print(is_float(0xfade));          #valid hexidecimal converted before pass by value 
print(is_float(0b1100_0000));     #valid binary converted before pass by value 

print("\n"); 

#ERROR: 

print(is_float(5,6,7)) 
my @s = (10,20,30); 
print(is_float(@s)); 

$arr = (5, 'foo', 7); 
print(is_float($arr));      #an array containing integers and strings 
print(is_float((1, 2, 3))); #error, array is not float 
print(is_float(35,5));      #error, comma is not a decimal here, that's 2 parameters 

Results of 'does_this_variable_look_like_a_perl_float():

0000000000000000000000
11111111111111111111

Results of 'is_convertable_to_float__casting_and_killing_canaries():

0000100000011100000000
11111111111111111111


I'm unsure if you are wishing to fish a number out of the variable or whether you wish to check if the variable IS (well, can be) a float or int.

However, to build on the regex example above, its mostly correct, minus a couple tweaks.

#original code snippet
print "Is INT\n" if ($test =~/-*\d+/);
print "Is FLOAT\n" if ($test =~/-*\d+\.\d+/);

#$test = "1234" = INT
#$test = "12.3" = FLOAT

if test is this however...

$test = "123.asd23aa"; # IS AN INT!!!!

try this instead:

$test = "123.asd23aa";
print "Is INT\n" if ($test =~/-*\d+/); #NO ANCHORS, -* allows for multiple --
print "Is INT\n" if ($test =~/^-?\d+$/); # WITH ANCHORS, fixed -?
print "Is FLOAT\n" if ($test =~/^-?\d*\.\d+$/); #AS ABOVE, with \d* instead of \d+ (floats need not have a leading 0 . can start with .5 or -.5 etc)

and here are some easy subs you can drop into whatever tool box you might have

sub isInt{
    return  ($_[0] =~/^-?\d+$/)?1:0;
}


sub isFloat{
    return ($_[0] =~/^-?\d*\.\d+$/)?1:0;
}


sub isNum{
    return (isInt($_[0]) || isFloat($_[0]) )?1:0;
}


This should do what you need:

my $var = 0.02 # Floating point number
if ($var > int($var)) {
    
# is floating point number because int() always rounds down
    
}

If you need to test for 0.00 in your application, you could use:

my $var = 0.00 # Floating point number
if ($var > int($var) || length($var) > length(int($var)) {
        
# is floating point number because int() always rounds down
# or string length is longer than integer string
        
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜