【问题标题】:PHP returning NaNPHP 返回 NaN
【发布时间】:2012-01-02 01:27:19
【问题描述】:

我有一个函数可以计算两个 GPS 坐标之间的距离。然后我从数据库中获取所有坐标并循环遍历它们以获得当前坐标与前一个坐标之间的距离,然后将其添加到特定 GPS 设备的数组中。出于某种原因,它返回 NaN。我尝试将其转换为 double、int 和四舍五入。

这是我的 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);

【问题讨论】:

  • 你能更详细地说明什么时候出了问题吗?
  • 你确定你从数据库中得到的值是数字而不是字符串?
  • 我建议在你的 distance() 公式的每个阶段都加入调试输出,找出产生 nan 的确切位置。
  • 这一行确实看起来很有趣:$dist[$row['imeiN']][]["lat"] = $row['lat'];——解释器应该如何知道如何处理那组空的[] 数组索引?我很惊讶它并没有直接退出。
  • @sarnold 这是要附加的普通 PHP 功能。然后他让 count() 知道指数,这是丑陋的。一个非常简单的方法是使用计数器,他必须分层......

标签: php nan


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    如果点彼此太接近,算法将产生 NaN。在这种情况下,$dist 的值为 1。 acos(1) 是 NaN。所有 sunsequent 计算也产生 NaN。 第一步是四舍五入坐标,因此四舍五入后值更可能相等,并产生 NaN

    【讨论】:

    【解决方案3】:

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

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

    【讨论】:

      【解决方案4】:

      您使用的是球面余弦定律吗?我会切换到Haversine 公式:

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

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

      【讨论】:

        【解决方案5】:

        感谢这里的所有回复 - 结果我做了一个函数,它结合计算和测试每个中的 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;
        }
        

        未来也有人。

        【讨论】:

          猜你喜欢
          • 2012-03-25
          • 2018-02-05
          • 2017-08-12
          • 1970-01-01
          • 2011-04-22
          • 2016-05-20
          • 2014-02-20
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多