PHP возвращает NaN - PullRequest
       2

PHP возвращает NaN

0 голосов
/ 02 января 2012

У меня есть функция, которая рассчитывает расстояние между двумя GPS-координатами.Затем я получаю все координаты из базы данных и перебираю их все, чтобы определить расстояние между текущим и предыдущим, а затем добавляю это в массив для конкретного устройства GPS.Почему-то это возврат NaN.Я попытался привести его к двойному, целому и округлению числа.

Вот мой PHP-код:

function distance($lat1, $lon1, $lat2, $lon2) {
      $lat1 = round($lat1, 3);
      $lon1 = round($lon1, 3);
      $lat2 = round($lat2, 3);
      $lon2 = round($lon2, 3);
      $theta = $lon1 - $lon2; 
      $dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) +  cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta)); 
      $dist = acos($dist); 
      $dist = rad2deg($dist); 
      $miles = $dist * 60 * 1.1515;
      if($miles < 0) $miles = $miles * -1;
      return ($miles * 1.609344);  
}
$this->db->query("SELECT * FROM `gps_loc` WHERE `imeiN`='" . $sql . "' AND `updatetime`>=$timeLimit ORDER BY `_id` DESC");
    $dist = array();
    $dist2 = array();
    while($row = $this->db->getResults()) {
        $dist2[$row['imeiN']] = 0;
        $dist[$row['imeiN']][]["lat"] = $row['lat'];
        $dist[$row['imeiN']][count($dist[$row['imeiN']]) - 1]["lng"] = $row['lon'];
    }

    foreach($dist as $key=>$d) {
        $a = 0;
        $b = 0;
        foreach($dist[$key] as $n) {
            if($a > 0) {
                $dist2[$key] += $this->distance($n['lat'], $n['lng'], $dist[$key][$a - 1]['lat'], $dist[$key][$a - 1]['lng']);
            }
            $a++;
        }

    }
    echo json_encode($dist2);

Ответы [ 5 ]

4 голосов
/ 29 октября 2012

Алгоритм выдаст NaN, если точки расположены слишком близко друг к другу. В этом случае $ dist получает значение 1. acos (1) равно NaN. Все последующие вычисления также дают NaN. Вы округляете координаты в качестве первого шага, поэтому становится более вероятным, что значения станут равными после округления, и получится NaN

4 голосов
/ 02 января 2012

Диапазон sin() и cos() находится в диапазоне от -1 до 1. Поэтому при первом вычислении $dist диапазон результата составляет от -2 до 2. Затем вы передаете его в acos(), аргумент которого долженбыть между -1 и 1. Таким образом, acos(2), например, дает NaN.Все остальное оттуда также дает NaN.

Я не уверен, какой именно должна быть формула, но именно отсюда исходит ваш NaN.Дважды проверьте свою тригонометрию.

2 голосов
/ 02 января 2012

Значения, которые вы извлекаете из базы данных, могут быть строками, которые могут вызвать эту проблему.

Возможно, вы также захотите проверить проблемы, поднятые Колинком в его сообщении.

0 голосов
/ 11 мая 2014

Спасибо за все ответы здесь - в результате я сделал функцию, которая объединяет вычисления и тесты для NaN в каждом, если оба не являются NaN - он усредняет вычисления, если один является NaN, а другой - нет использует тот, который действителен, и выдает отчет об ошибке для координат, которые не прошли один из расчетов:

function distance_slc($lat1, $lon1, $lat2, $lon2) {
        $earth_radius = 3960.00; # in miles
        $distance  = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($lon2-$lon1)) ;
        $distance  = acos($distance);
        $distance  = rad2deg($distance);
        $distance  = $distance * 60 * 1.1515;
        $distance1  = round($distance, 4);

        // use a second method as well and average          
        $radius = 3959;  //approximate mean radius of the earth in miles, can change to any unit of measurement, will get results back in that unit
    $delta_Rad_Lat = deg2rad($lat2 - $lat1);  //Latitude delta in radians
    $delta_Rad_Lon = deg2rad($lon2 - $lon1);  //Longitude delta in radians
    $rad_Lat1 = deg2rad($lat1);  //Latitude 1 in radians
    $rad_Lat2 = deg2rad($lat2);  //Latitude 2 in radians

    $sq_Half_Chord = sin($delta_Rad_Lat / 2) * sin($delta_Rad_Lat / 2) + cos($rad_Lat1) * cos($rad_Lat2) * sin($delta_Rad_Lon / 2) * sin($delta_Rad_Lon / 2);  //Square of half the chord length
    $ang_Dist_Rad = 2 * asin(sqrt($sq_Half_Chord));  //Angular distance in radians
    $distance2 = $radius * $ang_Dist_Rad;  
        //echo "distance=$distance and distance2=$distance2\n";
    $avg_distance=-1;
    $distance1=acos(2);
        if((!is_nan($distance1)) && (!is_nan($distance2))){
            $avg_distance=($distance1+$distance2)/2;
        } else {
            if(!is_nan($distance1)){
                $avg_distance=$distance1;
                try{
                    throw new Exception("distance1=NAN with lat1=$lat1 lat2=$lat2 lon1=$lon1 lon2=$lon2");
                } catch(Exception $e){
                    trigger_error($e->getMessage());
                    trigger_error($e->getTraceAsString());
                }
            }
            if(!is_nan($distance2)){
                $avg_distance=$distance2;
                try{
                    throw new Exception("distance1=NAN with lat1=$lat1 lat2=$lat2 lon1=$lon1 lon2=$lon2");
                } catch(Exception $e){
                    trigger_error($e->getMessage());
                    trigger_error($e->getTraceAsString());
                }
            }
        }
        return $avg_distance;
}

HTH кто-то и в будущем.

0 голосов
/ 02 января 2012

Это сферический закон косинусов, который вы используете?Я бы переключился на формулу Хаверсайна:

function distance($lat1, $lon1, $lat2, $lon2) 
{  
    $radius = 3959;  //approximate mean radius of the earth in miles, can change to any unit of measurement, will get results back in that unit

    $delta_Rad_Lat = deg2rad($lat2 - $lat1);  //Latitude delta in radians
    $delta_Rad_Lon = deg2rad($lon2 - $lon1);  //Longitude delta in radians
    $rad_Lat1 = deg2rad($lat1);  //Latitude 1 in radians
    $rad_Lat2 = deg2rad($lat2);  //Latitude 2 in radians

    $sq_Half_Chord = sin($delta_Rad_Lat / 2) * sin($delta_Rad_Lat / 2) + cos($rad_Lat1) * cos($rad_Lat2) * sin($delta_Rad_Lon / 2) * sin($delta_Rad_Lon / 2);  //Square of half the chord length
    $ang_Dist_Rad = 2 * asin(sqrt($sq_Half_Chord));  //Angular distance in radians
    $distance = $radius * $ang_Dist_Rad;  

    return $distance;  
}  

Вы должны быть в состоянии изменить радиус Земли на любую форму измерения от радиуса в световых годах до радиуса в нанометрах и получить правильное число обратно дляединица измерения используется.

...