2014-03-12 2 views
0

에서 모듈 얻기 위해 어떻게해야 :는 플로트

$value = 0.57; 
$step = 0.01; 

내가 가치 $/$ 단계 정수가 있는지 확인하고 싶습니다. 또한 때로는 $ 값이 음수입니다. 내가 무엇을 얻을

은 다음과 같습니다

$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) 

어떤 생각?

+0

소수점 연산 부동 사실상 당신에게 정확한 결과를 제공하지 않습니다. equals 연산자는 대개 수레와의 문맥에서 완전히 잘못 배치됩니다. 어떤 것이라도 결과는 항상 일정한 오류 범위 내에있는 것으로 평가됩니다. – deceze

+0

@deceze 그럼 $ value가 $ step => $ value = $ n * $ step의 $ n 단계인지 확인하는 방법을 알고 계십니까? $ n은 정수이고 $ value이면 $ step은 실수 일 수 있습니다 (음 또는 양수)? – RobM

답변

1

다른 가능성 : 문자열 모듈로 플로트 :-)

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

충분히 도움이 나도 몰라하지만 난 당신이 둥근 값에서 분할 결과를 빼고 같이, 엡실론 값과 비교할 수 있습니다 생각 :

$value = 0.57; 
$step = 0.01; 
$epsilon = 0.00000001; // less decimals means lower precision 
var_dump(abs(round($value/$step) - $value/$step) < $epsilon); 

함수에 싸서 그것을 test_integer라고 부르거나 그것이 당신을 위해 일하는 지 알고 싶습니다.

LE : 음수에 대해 작동하도록 abs()가 추가되었습니다.

+0

예, 나는 그것에 대해 생각했습니다 : 1. 나는 큰 엡실론이 얼마나 큰지 모르겠다. 2. 나는 0.000X와 같은 코드에서보다 정확한 수레를 가지고 있으며, 엡실론 방법은 덜 믿을만한 것으로 응시하고있다. 나는 $ value와 $ step에서 소수점 이하 자리에 sth base로 작업 중이며 최대 값 또는 최소값을 얻는다. – RobM

0

OP 솔루션

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