Keep latitude at 3.5 bytes

I know that the name sounds a little strange, but it is extremely important to reduce our message to 16 bytes. However, the whole data is 17. The only possible solution I can think of is to try to save one byte by entering the coordinates at 7 bytes instead of 8.

The requirement for coordinates is to keep the value with 5 decimal places at least, for example 0.00001.

Say we have 3.5 bytes (28 bits). One bit will be used for the sign, another 4 for the scale, 2 for the exponent and 21 bits for decimal points, which are equal to 2097152 unique values, which are enough to store 6 decimal places.

My question is, how can I convert 4 bytes of float to 3.5 bytes of float in C / Java? Can you refer me to existing solutions for "fine tuning" such floats where I can define all the components of a floating point number? Thanks.

+6
source share
3 answers

My first choice in this case would not be a strange 3.5-byte "float", but to package it integer. Assuming your latitude range is from -90 to 90 and longitude is from -180 to 180, it will look something like this (Cish code, untested):

float latitude = 45.12345 float longitude = 110.12345 unsigned int packedLatitude = (latitude + 90) * 100000 //25 bits unsigned int packedLongitude = (longitude + 180) * 100000 //26 bits float unpackedLatitude = packedLatitude / 100000.0f - 90.0f float unpackedLongitude = packedLongitude / 100000.0f - 180.0f 

This gives you a coordinate of 6.4 bytes. It remains only to pack these 6.4 bytes into the structure of your 16-18 bytes, which, I believe, you already know how to do (it depends on what you are packing into it and where).

Note that there are several fixes to this method that you need to be aware of. Lower limits (-90 and -180) are hard limits, and if they are exceeded, your unpacked coordinates will be incorrect. Your upper limits give a little: latitude can go up to 245, longitudes up to 491, but you probably need to make sure that they are normalized to -90-90 / -180-180. If that matters, you should also know how you round or truncate extra digits below 0.00001 (I believe this method truncates them).

+6
source

Float doesn't make sense here. You almost certainly need the same accuracy (in degrees of arc) at the North Pole, Equator and South Pole. Thus, all zeros should represent 0 degrees at the North Pole, and 28 bits 1 s should represent the South Pole.

Thus, zero degrees are zero in your number, and 180 degrees represent (2 ** 28) - 1 or 268435455. Multiply your latitude (in "double" degrees from the North Pole) times 268435455/180 or 1491308.0833333333, cast by an integer and take the lower 28 bits. (The high 6 bits should be zero.)

To convert back, select 28 bits in int, add to double and divide by the specified factor.

Longitude can be handled similarly, only the range is 360 degrees, not 180.

+5
source

I do not understand the need for scaling, since the exponents and scales are almost the same.

you can find the IEEE Floats specification used by C. implementations, so you can save your value in the float by typing it in uint32 and extract information about the sign, exponent and mantissa from it and pack it in a smaller format.

 float val = 234.323f; uint32_t valB = ((uint32_t*)(&val)); uint32_t signBit = valB >> 31; uint32_t exp = (valB >> 23) & 0xff; uint32_t mant = valB & 0x7FF; 

You now have separate components. save them in your data with the necessary degree of accuracy and vice versa.

One caveat: exp is stored at offset 128, so you have to transfer it back to the signed one and save it with another offset that suits your requirements.

http://de.wikipedia.org/wiki/IEEE_754#Zahlenformate_und_andere_Festlegungen_des_IEEE-754-Standards (look at the color image)

edit: according to your needs you can reset bits from the mantissa to a minimum without any problems (but you may want to round if bit 1 is set) and you need to separate 2 bits from the exponent.

 uint32_t smallMant = mant>>2; int32_t realExp = ((int32_t)exp) - 128; uint32_t smallExp = realExp + 32; uint32 reducedData28 = (signBit << 27) | (smallExp << 21) | smallMant; 

If the indicator of the desired range is not symmetrical, you can choose a different offset than half the possible range.

+3
source

All Articles