1

I know the formular for conversion from Degree to Milliseconds and vice-versa. It can be implemented like that:

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

Scenario: I convert from Degree to Miliseconds and continue converting from Miliseconds to Degree. The converted value has some difference with original value. I want the value is exact as the orginal value as well. For example:

$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)

Is there another way to reduce difference is caused by conversion between degree and milliseconds?

Cœur
  • 37,241
  • 25
  • 195
  • 267
secretlm
  • 2,361
  • 2
  • 27
  • 38
  • Based on the code, it means degree-minute-second. – Jaime Gris Jun 26 '13 at 04:32
  • @DevZer0: Sorry I updated. – secretlm Jun 26 '13 at 04:41
  • Huh ? The "difference" ? You're using `round()` which means it will round your output thus "the difference". – HamZa Jun 26 '13 at 06:05
  • @HamZa: I use round() so the difference will be less than or equal 0.5 miliseconds. But I want to reduce it smaller than round() do it. – secretlm Jun 26 '13 at 06:11
  • @secretlm not sure what you want, but [round()](http://php.net/manual/en/function.round.php) has a second parameter `precision`, take a look at it. – HamZa Jun 26 '13 at 06:14
  • @HamZa: I convert from DMS to miliseconds and continue converting from miliseconds to Degree. The converted value has some difference with original value. I want the value is exact as the orginal value as well. – secretlm Jun 26 '13 at 07:40
  • @secretlm Ok, can you give an input, the actual output, and your desired output ? – HamZa Jun 26 '13 at 07:43
  • @HamZa: I updated. Please take a loot at it. – secretlm Jun 26 '13 at 07:54

1 Answers1

3

There are 360 degrees (longitude), 60 minutes per degree, 60 secondes per minute, 1000 milliseconds per second. So at most

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

That fits well on 31 bits, so the idea would be to first convert to an integer, and perform as much operations as possible in integer.

Note that if you use single precision floating point, you'll get a 24 bits significand and will loose accuracy under 1 tenth of second (log2(360*60*60*10) is about 23.6).

I would recommend to store results in double precision (53 bits significand).

EDIT

What I was suggesting is to perform the conversion all at once, if there is a way to use double precision for representing $decimaldegrees (I don't know php enough to tell so), something like:

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

Then if ever you want to decompose into DMS (but these variables are not used in your code):

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

Ater a deeper look at you code, it seems you are separating the decimal part first $tempma = "0.".$vars[1];
That could work if you work on the decimal representation string, because in this case that fits well even on a single precision float (log2(60*60*1000) is about 21.8). So the beginning could be replaced with:

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

From the example of output you gave, it sounds like the problem comes from the other conversion milisecond_to_decimal, presumably because some arithmetic operation is performed with integer arithmetic and thus discards the milliseconds.

Once again, I don't know php enough, but wouldn't $s = $s % 3600; in fact operate on (int)(%s) and thus discard the milliseconds?
You would need to find something equivalent to C function fmod or modf.

Once again, you could do all operation at once if there is a way to do it in double precision:

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

If you don't have access to double precision, you can't recompose safely, single precision does not have enough bits...

You would need to operate on separate string parts, caring of leading zeros in fraction part

Anyway, I strongly suggest to perform unit tests, that is to test your two functions separately, this way you'll get a better understanding of what works and what not.

aka.nice
  • 9,100
  • 1
  • 28
  • 40
  • Thanks for your answer. However, I don't understand your idea clearly. Could you explain more detail about it? Thanks. – secretlm Jun 27 '13 at 02:19