Я проверил все предложенные решения со многими упомянутыми проблемными значениями, все они терпят неудачу по крайней мере для одного из тестовых случаев. Начните проверять, является ли $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