PHP проверяет, является ли переменная целым числом - PullRequest
28 голосов
/ 03 февраля 2010

У меня есть этот код PHP:

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

Я хочу знать, как проверить, является ли $ entityElementCount целым числом (2, 6, ...) или частичным (2.33, 6.2, ...).

Спасибо!

Ответы [ 18 ]

41 голосов
/ 03 февраля 2010
if (floor($number) == $number)
36 голосов
/ 21 августа 2013

Я знаю, что это старый, но я думал, что поделюсь тем, что я только что нашел:

Используйте fmod и проверьте 0

$entityElementCount = (-($highScore-$totalKeywordCount))/0.29;
if (fmod($entityElementCount,1) !== 0.0) {
    echo 'Not a whole number!';
} else {
    echo 'A whole number!';
}

fmod isотличается от%, потому что если у вас есть дробь,%, кажется, не работает для меня (он возвращает 0 ... например, echo 9.4 % 1; будет выводить 0).С fmod вы получите дробную часть.Например:

echo fmod(9.4, 1);

Будет выводить 0.4

19 голосов
/ 03 февраля 2010
$entityElementCount = (-($highScore-$totalKeywordCount))/0.29;
if (ctype_digit($entityElementCount) ){
    // (ctype_digit((string)$entityElementCount))  // as advised.
    print "whole number\n";
}else{
    print "not whole number\n";
}
10 голосов
/ 13 декабря 2013

Я бы использовал функцию intval следующим образом:

if($number === intval($number)) {

}

Тесты:

var_dump(10 === intval(10));     // prints "bool(true)"
var_dump("10" === intval("10")); // prints "bool(false)"
var_dump(10.5 === intval(10.5)); // prints "bool(false)"
var_dump("0x539" === intval("0x539")); // prints "bool(false)"

Другие решения

1)

if(floor($number) == $number) {   // Currently most upvoted solution: 

Тесты:

$number = true;
var_dump(floor($number) == $number); // prints "bool(true)" which is incorrect.

2)

if (is_numeric($number) && floor($number) == $number) {

Угловой корпус:

$number = "0x539";
var_dump(is_numeric($number) && floor($number) == $number); // prints "bool(true)" which depend on context may or may not be what you want

3)

if (ctype_digit($number)) {

Тесты:

var_dump(ctype_digit("0x539")); // prints "bool(false)"
var_dump(ctype_digit(10)); // prints "bool(false)"
var_dump(ctype_digit(0x53)); // prints "bool(false)"
9 голосов
/ 03 февраля 2010

Основной путь, как сказал Чача, -

if (floor($number) == $number)

Однако типы с плавающей запятой не могут точно хранить числа, что означает, что 1 может быть сохранено как 0.999999997. Это, конечно, будет означать, что вышеупомянутая проверка не будет выполнена, поскольку она будет округлена до 0, даже если для ваших целей она достаточно близка к 1, чтобы считаться целым числом. Поэтому попробуйте что-то вроде этого:

if (abs($number - round($number)) < 0.0001)
6 голосов
/ 03 февраля 2010

Если вы знаете, что он будет числовым (то есть он никогда не будет целым числом, приведенным к строке, как "ten" или "100", вы можете просто использовать is_int():

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

echo ($entityWholeNumber) ? "Whole Number!" : "Not a whole number!";
4 голосов

Я проверил все предложенные решения со многими упомянутыми проблемными значениями, все они терпят неудачу по крайней мере для одного из тестовых случаев. Начните проверять, является ли $value число, используя is_numeric($value), уменьшает количество сбоев для многих решений, но не превращает любое решение в окончательное:

$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";
}

Я думаю, что решения, подобные тем, что предложены @Aistina и @Notinlist, являются лучшими, потому что они используют порог ошибки, чтобы определить, является ли значение целым числом. Важно отметить, что они работали, как и ожидалось, для выражения (-(4.42-5))/0.29, тогда как в этом тесте все остальные потерпели неудачу.

Я решил использовать решение @ Notinlist из-за его читабельности:

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

Мне нужно проверить, являются ли значения целыми числами, валютой или процентом, я думаю, что достаточно двух цифр точности, поэтому решение @ Notinlist соответствует моим потребностям.

Запуск этого теста:

$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";
}

Создает следующий вывод:

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
3 голосов
/ 03 февраля 2010
if(floor($number) == $number)

Не является стабильным алгоритмом. Если значение математически равно 1,0, числовое значение может быть 0,9999999. Если вы примените floor () к нему, это будет 0, что не равно 0.9999999.

Вы должны угадать радиус точности, например, 3 цифры

if(round($number,3) == round($number))
3 голосов
/ 04 декабря 2012
(string)floor($pecahformat[3])!=(string)$pecahformat[3]
1 голос
/ 29 октября 2018

Это не попытка ответить на этот вопрос так много. Их много уже ответа. Если вы ведете статистику, как подразумевает вопрос, я подозреваю, что ответ @ antonio-vinicius-menezes-medei подойдет вам лучше. Однако мне нужен этот ответ для проверки ввода. Я нашел эту проверку более надежной для проверки входной строки целого числа:

is_numeric($number) && preg_match('/^[0-9]+$/', $number)

is_numeric просто исправляет "true", преобразовывая в "1" в preg_match.

Итак, разыгрывание ответа @ antonio-vinicius-menezes-medei. Я написал скрипт для проверки этого ниже. Обратите внимание на ini_set('precision', 20). preg_match преобразует аргумент в строку. Если ваша точность установлена ​​ниже длины значений с плавающей точкой, они будут просто округляться с заданной точностью. Подобно ответу @ antonio-vinicius-menezes-medei, этот параметр точности приведет к аналогичной длине оценки.

  ini_set('precision', 20);
  $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);

  foreach ($test_cases as $number)
  {
    echo '<strong>';
    var_dump($number);
    echo '</strong>';
    echo boolFormater(is_numeric($number) && preg_match('/^[0-9]+$/', $number));
    echo '<br>';
  }

  function boolFormater($value)
  {
    if ($value)
    {
      return 'Yes';
    }
    return 'No';
  }

, который производит этот вывод:

float (0.28999999999999998002) Нет
int (2) Да
int (6) Да
float (2.3300000000000000711) Нет
float (6.2000000000000001776) Нет
строка (5) "10,00" Нет
float (1.3999999999999999112) Нет
int (10) Да
строка (2) "10" Да
float (10,5) Нет
строка (5) "0x539" Нет
bool (true) Нет
bool (false) Нет
int (83) Да
float (9.4000000000000003553) Нет
строка (3) "десять" Нет
строка (3) "100" Да
int (1) Да
float (0.99999999699999997382) Нет
int (0) Да
float (0.00010000000000000000479) Нет
float (1) Да
с плавающей запятой (0,9999990000000005264) Нет
float (2.0000000000000004441) Нет

...