PHP 返回 NaN

问题描述 投票:0回答:6

我有一个函数可以计算两个 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);
php nan
6个回答
5
投票

sin()
cos()
的范围在-1和1之间。因此,在第一次计算
$dist
时,结果范围是-2到2。然后将其传递给
acos()
,其参数必须介于-1 和 1。因此
acos(2)
例如给出 NaN。那里的其他所有内容也给出 NaN。

我不确定公式应该是什么,但这就是你的 NaN 的来源。仔细检查你的三角函数。


4
投票

如果点彼此太接近,算法将产生 NaN。在这种情况下,$dist 的值为 1。acos(1) 为 NaN。所有后续计算也会产生 NaN。 您首先对坐标进行舍入,因此舍入后值更有可能变得相等,并产生 NaN。


2
投票

您从数据库中提取的值可能是字符串,这会导致此问题。

您可能还想检查 Kolink 在他的帖子中提出的问题。


0
投票

这是您使用的余弦球面定律吗? 我会改用半正矢公式:

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

您应该能够将地球半径更改为任何形式的测量形式,从光年半径到纳米半径,并根据所使用的单位得到正确的数字。


0
投票

感谢这里的所有回复 - 结果我做了一个函数,它结合了每个 NaN 的计算和测试,如果两者都不是 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
投票

如果两点相同,则 acos 函数的自变量为

sin^(bg+cos^2(bg)*cos(lg-lg =
sin^(bg+cos^2(bg)*cos(0) =
sin^(bg+cos^2(bg)*1 =
sin^(bg+cos^2(bg) =
1

显示中间结果以及所有小数位,并检查结果是否恰好为 1,而不是类似的内容 1,00000000000000003。 发生这种情况是因为最后一位数字总是四舍五入。如果最后两位数字偶然四舍五入,则总和可能稍大。但是,它不能超过 1,因为这样 acos 就会失败并返回 NaN(不是数字)。

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.