Reputation: 432
I have:
$value = 0.57;
$step = 0.01;
I want to check if $value/$step is integer. Additionally sometimes $value is negative.
What I get is:
$value/$step -> 57
is_int($value/$step) -> false
and the best one:
floor($value/$step) -> 56 (I assume that 57 is really 56.9999999(9) )
$a - $b * floor($a / $b) -> 0.0099999(9)
($value/$step)%1 -> 0 (ok, but % doesn't work if it is really a float)
fmod($value/$step) -> 0.999999999(9)
any idea?
Upvotes: 1
Views: 482
Reputation: 5443
other possibility: float as string modulo :-)
function float_modulo($value, $step) {
$str_value = strval($value);
$float_part_value = substr($str_value, strpos($str_value, ".") + 1);
$str_step = strval($step);
$float_part_step = substr($str_step, strpos($str_step, ".") + 1);
return intval($float_part_value) % intval($float_part_step);
}
Upvotes: 1
Reputation: 432
OP solution
public static function isZero($number, $precision = 0.0000000001)
{
$precision = abs($precision);
return -$precision < (float)$number && (float)$number < $precision;
}
public static function isEqual($number1, $number2)
{
return self::isZero($number1 - $number2);
}
public static function fmod($number1, $number2)
{
//$rest = self::sfmod($number1, $number2);
if ($number2<0)
{
$rest = $number1 - $number2 * ceil($number1/$number2);
}
else if ($number2>0)
{
$rest = $number1-$number2*floor($number1/$number2);
}
if (self::isEqual($rest, $number2)) {
return 0.0;
}
if (mb_strpos($number1, ".") === false) {
$decimals1 = 0;
} else {
$decimals1 = mb_strlen($number1) - mb_strpos($number1, ".") - 1;
}
if (mb_strpos($number2, ".") === false) {
$decimals2 = 0;
} else {
$decimals2 = mb_strlen($number2) - mb_strpos($number2, ".") - 1;
}
return (float)round($rest, max($decimals1, $decimals2));
}
Upvotes: 1
Reputation: 340
I don't know if it's helpful enough but i think you can subtract the division result from its rounded value and compare it to an epsilon value, like this:
$value = 0.57;
$step = 0.01;
$epsilon = 0.00000001; // less decimals means lower precision
var_dump(abs(round($value/$step) - $value/$step) < $epsilon);
Wrap it in a function and call it test_integer or however you want and see if it's working for you.
LE: Added abs() to make it work for negative numbers.
Upvotes: 0