Question

I have been reading timestamp values from sensor readings, but since they are provided in nanoseconds, I thought I would cast them to double and make the conversion. The resulting number is a 17 digit value, plus the separator.

Trying to print it directly results in scientific notation, which I don't want, so I use a DecimalFormat class to output it to an expected value of 4 decimal places. The problem is, even though the debugger shows a number of 17 decimal digits, even after the 'doubleValue()' call, the output string shows me a number of 15 digits.

Code:

...
Double timestamp = (new Date().getTime()) +       // Example: 1.3552299670232847E12
            ((event.timestamp - System.nanoTime()) / 1000000D);
DecimalFormat dfmt = new DecimalFormat("#.####");

switch(event.sensor.getType()){
    case Sensor.TYPE_LINEAR_ACCELERATION:
    case Sensor.TYPE_ACCELEROMETER:
        accel = event.values.clone();
        String line = "A" + LOGSEPARATOR +              
            dfmt.format(timestamp.doubleValue()) + // Prints: 1355229967023.28
...

I thought this might be an android precision problem, but the debugger has the formatter showing the wrong precision as well. I have tested this in a local java program and both calls have the same amount of digits.

Is this a DecimalFormat bug/limitation? Or am I doing something wrong?

Was it helpful?

Solution 2

There is indeed a difference between Java's and Android's DecimalFormat class, and they output different results, despite taking the exact same arguments.

This was enough for me to try Henry's approach, and now that I have I see that I have gained an extra 2 places of precision. I am also confident that the values are calculated accurately, as only sums and multiplications are involved.

This is the modified code I ended up using:

...
long javaTime = new Date().getTime();
long nanoTime = System.nanoTime();
long newtimestamp = javaTime * 1000000 +            // Compute the timestamp
            (event.timestamp - nanoTime);           // in nanos first
String longStr = Long.valueOf(newtimestamp).toString();
String tsString = longStr.substring(0, longStr.length()-6) +// Format the output string
            "." + longStr.substring(longStr.length()-6);    // to have the comma in the
                                                            // correct space.
...

OTHER TIPS

A double in Java has a mantissa of only 52 bit (counting the hidden 1 its 53 bit). This is equivalent to 15-16 decimal places (53*log10(2)). Every digit after this is kind of random and therefore it makes sense for the conversion function to cut the output after 15 decimal places.

Since you do not need the large number range that double provides, why not keep the value as long? This would give you 63 significant bits (64 -1 for the sign).

Was doing some research with String.format aswell with same results.

Double timestamp = 1.3552299670232847E12;
System.out.println("it was " + timestamp);
System.out.println("and now " + String.format("%.4f", timestamp));

And this is the output:

12-12 15:48:58.255: I/System.out(2989): it was 1.3552299670232847E12
12-12 15:48:58.255: I/System.out(2989): and now 1355229967023,2800

Maybe you're right and it's an Android precision problem as if you try it in Java, the output is correct: http://ideone.com/PBOiet

I'll keep googling...

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top