PHP check if variable is a whole number

后端 未结 20 966
感动是毒
感动是毒 2020-12-29 20:05

I have this PHP code:

$entityElementCount = (-($highScore-$totalKeywordCount))/0.29;

What i want to know is, how to check whether $

相关标签:
20条回答
  • 2020-12-29 20:29

    I tested all the proposed solutions with many problematic values mentioned, they all fail for at least one of the test cases. Start checking if $value is a number using is_numeric($value) reduces the number of failures for many solutions, but does not turn any solution into an ultimate one:

    $test_cases = array(0.29, 2, 6, 2.33, 6.2, '10.00', 1.4, 10, "10", 10.5, "0x539", true,
        false, 0x53, 9.4, "ten", "100", 1, 0.999999997, 0, 0.0001, 1.0, 0.9999999,
        (-(4.42-5))/0.29);
    
    function is_whole_number($value) {
        // Doing this prevents failing for values like true or "ten"
        if (!is_numeric($value)) {
            return false;
        }
    
        // @ghostdog74's solution fails for "10.00"
        // return (ctype_digit((string) $value));
    
        // Both @Maurice's solutions fails for "10.00"
        // return ((string) $value === (string) (int) $value);
        // return is_int($value);
    
        // @j.hull's solution always returns true for numeric values
        // return (abs($value) % 1 == 0 ? true : false);
    
        // @ MartyIX's solution fails for "10.00"
        // return ($value === intval($value));
    
        // This one fails for (-(4.42-5))/0.29
        // return (floor($value) == $value);
    
        // This one fails for 2
        // return ctype_digit($value);
    
        // I didn't understand Josh Crozier's answer
    
        // @joseph4tw's solution fails for (-(4.42-5))/0.29
        // return !(fmod($value, 1) != 0);
    
        // If you are unsure about the double negation, doing this way produces the same
        // results:
        // return (fmod($value, 1) == 0);
    
        // Doing this way, it always returns false 
        // return (fmod($value, 1) === 0);
    
        // @Anthony's solution fails for "10.00"
        // return (is_numeric($value) && is_int($value));
    
        // @Aistina's solution fails for 0.999999997
        // return (abs($value - round($value)) < 0.0001);
    
        // @Notinlist's solution fails for 0.999999997
        // return (round($value, 3) == round($value));
    }
    
    foreach ($test_cases as $test_case) {
        var_dump($test_case);
        echo ' is a whole number? ';
        echo is_whole_number($test_case) ? 'yes' : 'no';
        echo "\n";
    }
    

    I think that solutions like the ones proposed by @Aistina and @Notinlist are the best ones, because they use an error threshold to decide whether a value is a whole number. It is important to note that they worked as expected for the expression (-(4.42-5))/0.29, while all the others failed in that test case.

    I decided to use @Notinlist's solution because of its readability:

    function is_whole_number($value) {
        return (is_numeric($value) && (round($value, 3) == round($value)));
    }
    

    I need to test if values are whole numbers, currency or percentage, I think 2 digits of precision is enough, so @Notinlist's solution fits my needs.

    Running this test:

    $test_cases = array(0.29, 2, 6, 2.33, 6.2, '10.00', 1.4, 10, "10", 10.5, "0x539", true,
        false, 0x53, 9.4, "ten", "100", 1, 0.999999997, 0, 0.0001, 1.0, 0.9999999,
        (-(4.42-5))/0.29);
    
    function is_whole_number($value) {
        return (is_numeric($value) && (round($value, 3) == round($value)));
    }
    
    foreach ($test_cases as $test_case) {
        var_dump($test_case);
        echo ' is a whole number? ';
        echo is_whole_number($test_case) ? 'yes' : 'no';
        echo "\n";
    }
    

    Produces the following output:

    float(0.29)
     is a whole number? no
    int(2)
     is a whole number? yes
    int(6)
     is a whole number? yes
    float(2.33)
     is a whole number? no
    float(6.2)
     is a whole number? no
    string(5) "10.00"
     is a whole number? yes
    float(1.4)
     is a whole number? no
    int(10)
     is a whole number? yes
    string(2) "10"
     is a whole number? yes
    float(10.5)
     is a whole number? no
    string(5) "0x539"
     is a whole number? yes
    bool(true)
     is a whole number? no
    bool(false)
     is a whole number? no
    int(83)
     is a whole number? yes
    float(9.4)
     is a whole number? no
    string(3) "ten"
     is a whole number? no
    string(3) "100"
     is a whole number? yes
    int(1)
     is a whole number? yes
    float(0.999999997)
     is a whole number? yes
    int(0)
     is a whole number? yes
    float(0.0001)
     is a whole number? yes
    float(1)
     is a whole number? yes
    float(0.9999999)
     is a whole number? yes
    float(2)
     is a whole number? yes
    
    0 讨论(0)
  • 2020-12-29 20:29

    Just to share my solution with localized string/number, this combo worked like a charm for me.

    public static function isWholeNumber ($input, $decimalDelimiter = ',')
    {
        if (is_string($input)){
            $input = str_replace($decimalDelimiter, '.', $input);
            $input = floatval($input);
        }
    
        if (fmod($input,1) !== 0.0) {
            return false;
        }
    
        return true;
    }
    
    0 讨论(0)
  • 2020-12-29 20:32
    if(floor($number) == $number)
    

    Is not a stable algorithm. When a value is matematically 1.0 the numerical value can be 0.9999999. If you apply floor() on it it will be 0 which is not equals to 0.9999999.

    You have to guess a precision radius for example 3 digits

    if(round($number,3) == round($number))
    
    0 讨论(0)
  • 2020-12-29 20:34
    function isInteger($value)
    {
        // '1' + 0 == int, '1.2' + 0 == float, '1e2' == float
        return is_numeric($value) && is_int($value + 0);
    }
    
    function isWholeNumber($value)
    {
        return is_numeric($value)
            && (is_int($value + 0)
                || (intval($value + 0) === intval(ceil($value + 0))));
    }
    

    If you want to check for both whole and decimal numbers, you can do the following:

    if (isInteger($foo))
    {
        // integer as int or string
    }
    if (isWholeNumber($foo))
    {
        // integer as int or string, or float/double with zero decimal part
    }
    else if (is_numeric($foo))
    {
        // decimal number - still numeric, but not int
    }
    

    This will correctly check your number without rounding it, casting it to int (which in the case of a decimal number will lose the decimal part), or doing any math. If, however, you want to treat 1.00 as a whole number, then that's a whole another story.

    0 讨论(0)
  • 2020-12-29 20:37

    If you know that it will be numeric (meaning it won't ever be a an integer cast as a string, like "ten" or "100", you can just use is_int():

    $entityElementCount = (-($highScore-$totalKeywordCount))/0.29;
    $entityWholeNumber = is_int($entityElementCount);
    
    echo ($entityWholeNumber) ? "Whole Number!" : "Not a whole number!";
    
    0 讨论(0)
  • 2020-12-29 20:37

    A simple solution for positive whole numbers only. This may not work for everything.

    $string = '0x539';
    $ceil = ceil($string);
    
    if($ceil < 1){
      $ceil = FALSE; // or whatever you want i.e 0 or 1
    }
    
    echo $ceil; // 1337
    

    You can use floor() instead of ceil() if so desired.

    0 讨论(0)
提交回复
热议问题