2009-06-23 5 views
0

여기에서 내가 한 일을 확신하는 데 끔찍한 시간을 보내고 있습니다. 나는 불쾌감을 특정 섹션은 다음과 같습니다 다시 BC 또는 GMP 라이브러리 (어느 것도 사용할 수 항상)에 가을 중 하나에 부동 소수점 정밀도를 유지하기 위해PHP에서 미세 시간 및 부동 소수점을 추가하는 숫자가 정확하지 않습니다.

return ((float)($now+$sec).'.'.$mic); 

, 내가 강제하고있다. 이 경우 문자열 연결과 함께 숫자를 jamming하는 데 의존했습니다.

<?php 

// return the current time, with microseconds 
function tick() { 
    list($sec, $mic, $now) = sscanf(microtime(), "%d.%d %d"); 
    return ((float)($now+$sec).'.'.$mic); 
} 

// compare the two given times and return the difference 
function elapsed($start, $end) { 
    $diff = $end-$start; 

    // the difference was negligible 
    if($diff < 0.0001) 
     return 0.0; 

    return $diff; 
} 

// get our start time 
$start = tick(); 

// sleep for 2 seconds (should be ever slightly more than '2' when measured) 
sleep(2); 

// get our end time 
$end = tick(); 

$elapsed = elapsed($start, $end); 

// should produce output similar to: float(2.00113797188) 
var_dump($elapsed); 

?> 

나는 변함없이 123456789.099와 끝까지 더하기 연산자 (+)를 사용하여, 123456789 (타임 스탬프를 나타내는)0.0987654321 (대표 마이크로)처럼 두 개의 번호를 추가하려고하면

. float에 정수를 캐스팅 할 때도 결과는 동일합니다.

1) 해킹이 아니며 2) 문자열 연결이 필요하지 않은이 문제에 대한 해결책이 있습니까? 마이크로 초 해상도의 정확한 타임 스탬프를 얻기 위해 이런 종류의 코드가 엉망이되어서는 안됩니다.

편집 : S. Gehrig가 설명했듯이 PHP의 부동 소수점 숫자는 때때로 약간 까다로울 수 있습니다. PHP 구성에 표시된 "정밀도"는 표시에 관한 것입니다. 내가 생각한 것처럼 실제 값은 반올림되지 않습니다. 당신이 $가 또는 $ 다른에서 하나를 뺀 전에을 종료 시작 검토한다면,

// return the current time, with microseconds 
function tick() { 
    return microtime(true); 
} 

// compare the two given times and return the difference 
function elapsed($start, $end) { 
    return $end-$start; 
} 

// get our start time 
$start = tick(); 

// sleep for 2 seconds (should be ever slightly more than '2' when measured) 
sleep(2); 

// get our end time 
$end = tick(); 

$elapsed = elapsed($start, $end); 

// should produce output similar to: float(2.00113797188) 
var_dump($elapsed); 

그들이 1/100로 반올림 된 나타날 수 있습니다 위의 코드에 대한 훨씬 간단 솔루션과 같이 보일 것이다 위치. 그렇지 않다. 디스플레이가 제한되어있는 동안 산술에 대해 임의의 정밀도가 유지되는 것으로 보입니다.

답변

2

float으로 간단히 마이크로 초 타임 스탬프를 반환하는 microtime(true)을 사용하지 않는 이유는 무엇입니까? 매개 변수 [bool] $get_as_float은 PHP 5.0.0에서 추가되었습니다. 정밀의 "손실"에 대한 의견에 대해서는

:

$start = microtime(true); 
$end = microtime(true); 
echo $end - $start; 
// prints 7.1526861190796 

microtime(true) 2 소수점에 한정되는 것은 아니다. 포스터가 만나는 부분은 float 변수를 출력 할 때 인쇄 할 소수점 자리 수를 제어하는 ​​구성 설정 precision의 효과입니다. 이것은 내부 정밀도 microtime(true)와는 아무 관련이 없습니다. 항상 number_format() 또는 (s)printf()을 사용하여 원하는 정밀도로 출력의 서식을 지정할 수 있습니다.

+0

정확하지만 정밀도는 2 곳으로 반올림되며이를 변경하는 방법이없는 것 같습니다. 기본적으로 PHP의 정밀도는 12 개입니다. 그러나이 함수는이를 존중하지 않습니다. 다음과 같이 확인하십시오 : php -r 'echo microtime (true); 나는 그것이 무엇처럼 둥글게 만드는 지 전혀 모른다. – spligak

+0

float의 소수 자릿수 12 자의 정밀도는 쉼표 앞에 소수점 이하자를 포함하므로 12 자릿수 정밀도는 사용자가 보는 것과 정확히 일치합니다. –

+0

이것은 디스플레이 문제 일 뿐이며 'precision' 구성 설정에 의해 제어됩니다. http://us2.php.net/manual/en/ini.core.php#ini.precision. 내부적으로 float는 대략 십진수 14 자리의 정밀도를가집니다. –

0

부동 소수점 유형은 본질적으로 부정확합니다. 함께 살거나 사용하지 마십시오.

+0

최후 통첩이 언급했다. 나는 "그걸로 살아갈 것"이라고 생각한다. – spligak

+0

BC, GMP 또는 문자열은 "사용하지 마십시오"를 나타냅니다. –

+0

부동 소수점을 사용할 수는 있지만 너무 많은 부정확 함으로 살아 가지 않기로 결정했습니다. http://en.wikipedia.org/wiki/Kahan_summation_algorithm –

1

먼저 spligak, 코드에 오류가 있음을 확인했습니다.

list($sec, $mic, $now) = sscanf(microtime(), "%d.%d %d"); 
return ((float)($now+$sec).'.'.$mic); 

$ mic가 6 자리 미만인 경우 가비지 결과가 발생합니다.(! 경고 : 테스트되지 않은 코드) 을 :

the case where microtime() returns "0.000009 1234567890" 

두 번째에 책상 검사를 수행합니다, 당신은 크게 다음과 같이 부동 소수점 오류를 줄일 수 있습니다

가 // 두 개의 주어진 시간을 비교하고 차이를 반환

// get our start time 
$start = microtime(); 

// sleep for 2 seconds (should be ever slightly more than '2' when measured) 
sleep(2); 

// get our end time 
$end = microtime(); 

// work around limited precision math 
// subtract whole numbers from whole numbers and fractions from fractions 

list($start_usec, $start_sec) = explode(" ", $start); 
list($end_usec, $end_sec) = explode(" ", $end); 
$elapsed = ((float)$end_usec)-((float)$start_usec); 
$elapsed += ((float)$end_sec)-((float)$start_sec); 

// please check the output 
var_dump($elapsed); 
관련 문제