在度和毫秒之间转换

时间:2013-06-26 03:59:48

标签: php floating-point geolocation rounding precision

我知道从度数转换为毫秒的公式,反之亦然。它可以这样实现:

 protected function decimal_to_milisecond($dec) {
        if (!empty($dec)) {         
            $vars = explode(".",$dec);
            if (count($vars) == 2) {
                $deg = $vars[0];
                $tempma = "0.".$vars[1];
                $tempma = $tempma * 3600;
                $min = floor($tempma / 60);
                $sec = $tempma - ($min*60);
                return round((((($deg * 60) + $min) * 60 + $sec) * 1000));
            } 
            else return false;
        } else return false;
    }

 function milisecond_to_decimal($sec) {
        if (!empty($sec)) {
            $s = $sec / 1000;
            $d = (int)($s / 3600);
            $s = $s % 3600;
            $m = (int)($s / 60);
            $s %= 60;       
            $ret = substr($d+((($m*60)+($s))/3600),0);
        } else return null;
        return $ret;
    }

场景:我从Degree转换为Miliseconds并继续从Miliseconds转换为Degree。转换后的值与原始值有一些差异。我希望值也是精确的原始值。例如:

$lat = "1284146";
$long = "503136198";
$lat1 = milisecond_to_decimal($lat);
$long1 = milisecond_to_decimal($long);

$result1 = decimal_to_milisecond($lat1);
$result2 = decimal_to_milisecond($long1);
var_dump($result1, $result2);

The output is float(1284000) and float(503136000)

还有另一种减少差异的方法是由度数和毫秒之间的转换引起的吗?

1 个答案:

答案 0 :(得分:3)

有360度(经度),每度60分钟,每分钟60次,每秒1000毫秒。所以最多

360*60*60*1000 milliseconds = 1 296 000 000 milliseconds

这非常适合31位,因此我们的想法是首先转换为整数,并在整数中执行尽可能多的操作。

请注意,如果使用单精度浮点数,则会得到24位有效数,并且在十分之一秒内会失去准确度(log2(360*60*60*10)约为23.6)。

我建议以双精度(53位有效数字)存储结果。

修改

我建议的是一次执行转换,如果有一种方法可以使用双精度来表示$decimaldegrees(我不知道php足以说明这一点),例如:

$millis = (int)( round( $decimaldegrees * (60*60*1000) ) );

然后,如果你想要分解成DMS(但是你的代码中没有使用这些变量):

$ms  =  $millis % 1000;
$sec = ($millis / 1000) % 60;
$min = ($millis / (60*1000)) % 60;
$deg = ($millis / (60*60*1000)) % 360;

更深入地看一下你的代码,似乎你先将小数部分分开$tempma = "0.".$vars[1];
如果你处理十进制表示字符串,那可能会有效,因为在这种情况下,即使在单个精度浮点数上也很合适(log2(60*60*1000)约为21.8)。所以开头可以替换为:

$deg  = (int) $vars[0];
$frac = "0.".$vars[1];
$millis = (int)( round( $frac * (60*60*1000) ) );
$millis = deg + millis;

从您给出的输出示例中,听起来问题来自其他转换milisecond_to_decimal,可能是因为某些算术运算是使用整数运算执行的,因此会丢弃毫秒。

再一次,我不知道php,但$s = $s % 3600;实际上不会在(int)(%s)上运行,从而丢弃毫秒数?
您需要找到与C函数fmodmodf等效的内容。

如果有双重精确的方法,你可以再一次完成所有操作:

$decimaldegrees = ((double)($millis)) / (60*60*1000);

如果您无法获得双精度,则无法安全地重构,单精度没有足够的位......

您需要在单独的字符串部分上操作,在分数部分

中处理前导零

无论如何,我强烈建议你进行单元测试,即分别测试你的两个功能,这样你就可以更好地理解什么有效,什么无效。