Question

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?

Was it helpful?

Solution

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);
}

OTHER TIPS

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));
    }

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top