我要压缩位置数据(纬度,经度,日期,时间)。所有数字都是固定格式。其中2个(纬度,经度)采用十进制格式。其他2是整数。
现在这些数字是固定格式的字符串。
以固定格式压缩数字的算法是什么? 数字压缩(如果有的话)比字符串压缩更好吗? 我应该直接压缩字符串而不将其转换为数字然后压缩吗?
提前致谢。
答案 0 :(得分:7)
这是一个小理论有用的地方之一。你需要考虑几件事:
假设,例如,分辨率为0.01°。你知道你的值在-180°到+ 180°之间,或35900个不同的值。 Lg(35900)≈16所以你需要16位; 14位 - -90° - + 90°。显然,如果您将这种值存储为浮点数,则可以立即将数据压缩一半。
与日期时间相似,范围是多少;你必须拥有多少位?
现在,如果数据按某种顺序排列(例如,在一艘船上顺序拍摄的样本),那么您只需要一个起始值和一个增量;这可以使大区别开来。如果船舶以30节的速度行驶,则位置不能再变化,即每小时约0.03度或每秒约0.0000083度。这些增量将是非常小的值,因此您可以将它们存储在很少的位中。
关键是你可以做很多事情,但你需要了解更多有关数据的信息,而不是我们提出建议。
更新:哦,等一下,定点字符串?!
好的,这(相对)容易。首先,是的,您希望将字符串转换为某种二进制表示形式。只是编写一个数据项,你可能有
040.00105.0020090518212100Z
你可以转换为
| 4000 | short int, 16 bits | | 10500 | short int, 16 bits | | 20090518212100Z | 64 bits |
这是96位,12个字节对26个字节。
答案 1 :(得分:5)
压缩通常适用于字节流。当流具有非均匀的字节值分布(例如文本或存储为文本的数字)时,您可以实现的压缩率会更高,因为使用更少的位来存储更频繁出现的字节(在Huffman中)压缩)。
通常情况下,您所谈论的数据只会存储为二进制数字(而不是文本),而且通常是空间和检索效率。
答案 2 :(得分:2)
您要压缩哪种数据?它是如何分发的?是以任何方式订购的吗?所有这些都会影响它的压缩效果,并且可能允许您将数据转换为更容易压缩的内容,或者只是更小的内容。
数据压缩在“随机”数据上运行不佳。如果您的数据在较小的范围内,您可能能够利用它。
事实上,您应该尝试运行任何常用算法,看看数据是否“足够压缩”。如果没有,并且您对数据的了解比压缩算法“直觉”要多,那么您应该利用这些信息。
一个例子是你的数据不仅仅是Lat和Long,而是假设它们彼此“接近”。然后你可以存储一个“原点”Lat和Long,其余的可以是差分。也许这些差异足够小,可以适应单个有符号字节。
这只是一个简单的例子,你可以利用数据知识与一些通用算法无法弄清楚的事情来做。
答案 3 :(得分:1)
这取决于您要对数据做什么,以及您需要多少精度。
Lat / long传统上以度,分和秒给出,60分钟到分钟,60分钟到度,1度纬度名义上等于60海里(nmi)。 1分钟然后是1 nmi,1秒则超过100英尺。
纬度从-90到+90度。将纬度表示为整数秒可以得到-324000 .. + 324000或大约20位的范围。经度变为-180到+180,因此以相同的方式表示经度需要1位。
所以你可以用41位代表一个完整的纬度/长度位置,+ / - 50英尺。
显然,如果你不需要那么精确,你可以减少你的位数。
观察传统的单精度32位浮点数使用大约24位的尾数,所以如果你只是将你的lat / long转换为浮点数,那么你可以降低到大约+/- 6英尺。对于这种事情来说,很难击败两个单精度浮子。
答案 4 :(得分:0)
根据可用字符,您可以很轻松地完成一些事情。
例如,如果输入仅是数字(0..9),则此解决方案将使用Kotlin(与Java类似)对它们进行编码和解码:
fun encodeDigitsOnlyString(stringWithDigitsOnly: String): ByteArray {
//we couple each 2 digits together into a single byte.
//For the last digit, if it has no digit to pair with, it's paired with something that's not a digit
val result = ArrayList<Byte>()
val length = stringWithDigitsOnly.length
var lastDigit: Byte? = null
for (i in 0 until length) {
val char = stringWithDigitsOnly[i]
val digitAsByte = char.toString().toInt().toByte()
if (lastDigit == null) {
if (i == length - 1) {
//last digit
val newByte = (digitAsByte + 0xf0).toByte()
result.add(newByte)
} else {
//more to go
lastDigit = digitAsByte
}
} else {
val newByte = (digitAsByte + lastDigit.toInt().shl(4)).toByte()
result.add(newByte)
lastDigit = null
}
}
return result.toByteArray()
}
fun decodeByteArrayToDigitsOnlyString(encodedDigitsOnlyByteArray: ByteArray): String {
val sb = StringBuilder(encodedDigitsOnlyByteArray.size * 2)
for (byte in encodedDigitsOnlyByteArray) {
val hex = Integer.toHexString(byte.toInt()).takeLast(2).padStart(2, '0')
if (hex[0].isLetter())
sb.append(hex.last())
else
sb.append(hex)
}
return sb.toString()
}
用法示例:
val inputString="12345"
val byteArray=encodeDigitsOnlyString(inputString) //produces a byte array of size 3
val outputString=decodeByteArrayToDigitsOnlyString(byteArray) //should be the same as the input