Léo
Léo

Reputation: 132

Transform a double into a 32-bit representation (and reverse procedure)

[Context]
I am currently working on a probe balloon. My communication is restricted to messages of the 12 bytes in which I have to transmit several pieces of information. (Altitude, max temperature, longitude, latitude, average acceleration).
The probe is based on a raspberry pi 2 b.

[Question]
I am currently building my datagram and want to store my latitude and longitude as a 32-bit double (lossy). Storage can be done with floating point or fixed point Are there tools to do this kind of conversion? How else can I do that? (in particular on the rounded party)
I initially planned to work in Java but I can migrate to python.

Thank you in advance

Upvotes: 3

Views: 360

Answers (2)

Peter Lawrey
Peter Lawrey

Reputation: 533530

Instead of using a float which is not really designed for a lat/long I suggest using a fraction. If you multiply by Integer.MAX_VALUE/90 for latitude and Integer.MAX_VALUE/180.0 for longitude you will get a value which uses a 32-bit value more efficiently.

float lat = 90f;
System.out.println("precision using float: " + (lat - Math.nextDown(lat)) + " degrees");
double ratio = Integer.MAX_VALUE / 90.0;
int val2 = (int) Math.round(90 * ratio);
System.out.println("precision using int: " + 1 / ratio + " degrees");

prints

precision using float: 7.6293945E-6 degrees
precision using int: 4.190951587721217E-8 degrees

in short, an int can have more than 100x the precision as it has 32-bits of precision whereas a float has a 23-bit mantissa.

For longitude, this error represents 1.7m for float and 0.94 cm using an int this way.

NOTE: If a 2m error is ok (more accurate than a mobile phone GPS) you might decide that float is simpler to work with.

Upvotes: 2

AJNeufeld
AJNeufeld

Reputation: 8695

If you want to translate a double to 64-bits, you can use long Double.doubleToLongBits(double value), and double Double.longBitsToDouble(long bits) to convert it back.

If you want to convert 32-bit values to Float values and back, the corresponding functions are floatToIntBits(...) and intBitsToFloat(...).

For double to 32 bits, I'd use a 2-step conversion, converting to float first:

double val = ...;
int bits = Float.floatToIntBits( (float) val );

And back:

int bits = ...;
double val = (double) Float.intBitsToFloat(bits);

Packing and unpacking directly to a buffer:

ByteArrayOutputStream baos = new ByteArrayOutputStream(20);
DataOutputStream dos = new DataOutputStream( ... );
dos.writeFloat( altitude );
dos.writeFloat( max_temperature );
dos.writeFloat( longitude );
dos.writeFloat( latitude );
dos.writeFloat( average_acceleration);
byte[] data = baos.toByteArray();

Of course, this creates a 20 byte buffer (5 x 32 bit floats), not a 12 byte buffer, so you'll need to figure out which values you want as 32 bits, and which you can cram into smaller space.

Unpacking, use a DataInputStream and readFloat().

ByteArrayInputStream bais = ...
DataInputStream dis = new DataInputStream(bais);
altitude = dis.readFloat();
max_temperature = dis.readFloat();
...etc...

Upvotes: 1

Related Questions