以3.5个字节存储纬度

时间:2014-03-20 15:36:51

标签: java c floating-point

我知道标题听起来有点奇怪,但将消息压缩成16个字节非常重要。但是,整个数据是17.我能想到的唯一可能的解决方案是尝试将一个字节的坐标保存为7个字节而不是8个。

坐标的要求是存储5位小数的值作为最小值,例如0.00001。

假设我们有3.5个字节(28位)。一位将用于符号,另一位用于标度,2用于指数,21位用于小数点,即2097152的唯一值,足以存储6个小数位。

我的问题是如何在C / Java中将4字节浮点数转换为3.5字节浮点数?您能否参考我现有的“微调”浮点数解决方案,我可以定义浮点数的所有组成部分?感谢。

3 个答案:

答案 0 :(得分:6)

在这种情况下,我的第一个选择不是奇怪的3.5字节“float”,而是将其打包成一个整数。假设您的纬度范围是-90到90,经度从-180到180,它看起来像这样(Cish代码,未经测试):

 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 

这为您提供6.4字节的坐标。剩下的就是将这6.4个字节打包到你的16-18字节结构中,我假设你已经知道该怎么做(这取决于你将它包装在哪里以及在哪里)。

请注意,您需要了解此方法的一些问题。下限(-90和-180)是硬限制,如果超出限制,则解压缩的坐标将不正确。你的上限有一点给定:纬度可以达到245,经度可以达到491,但你可能应该确保它们被标准化为-90-90 / -180-180。如果它很重要,你也应该知道你如何舍入或截断0.00001以下的额外数字(我相信这种方法会截断它们)。

答案 1 :(得分:5)

Float在这里毫无意义。你几乎肯定希望在北极,赤道和南极具有相同的精度(就弧度而言)。因此,所有零都应表示北极0度,而28位1表示南极。

因此零度表示数字为零,180度表示(2 ** 28) - 1或268435455.乘以纬度(在"双倍"度数从北极)乘以268435455 / 180或1491308.0833333333,转换为整数,并取低28位。 (高6位应为零。)

要转换回来,将int中的28位隔离,强制转换为double,并除以上述因子。

经度可以类似地处理,只有范围是360度而不是180度。

答案 2 :(得分:3)

我不理解对比例的需要,因为指数和比例几乎相同。

您可能会查找C实现所使用的IEEE Floats规范。因此,您可以将值存储在浮点数中,并将其转换为uint32并从中提取符号,指数和尾数信息,并以较小的格式打包。

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; 

现在你有了单个组件。使用所需的精确度将这些存储在您的数据中,反之亦然。

一个警告:exp存储的偏移量为128,因此您必须将其转移回签名并将其与另一个符合您要求的偏移量一起存储

http://de.wikipedia.org/wiki/IEEE_754#Zahlenformate_und_andere_Festlegungen_des_IEEE-754-Standards(查看彩色图片)

编辑: 为了满足您的需要,您可以从尾数中剥离最低位而不用担心(但如果设置了第1位,您可能想要向上舍入)并且您必须从指数中剥离2位。

uint32_t smallMant = mant>>2;
int32_t  realExp   = ((int32_t)exp) - 128;
uint32_t smallExp  = realExp + 32;

uint32 reducedData28 = (signBit << 27) | (smallExp << 21) | smallMant;

如果所需范围的指数不对称,则可以选择另一个偏差而不是可能范围的一半。