仅限数字的压缩算法

时间:2009-05-18 18:16:19

标签: compression data-compression

我要压缩位置数据(纬度,经度,日期,时间)。所有数字都是固定格式。其中2个(纬度,经度)采用十进制格式。其他2是整数。

现在这些数字是固定格式的字符串。

以固定格式压缩数字的算法是什么? 数字压缩(如果有的话)比字符串压缩更好吗? 我应该直接压缩字符串而不将其转换为数字然后压缩吗?

提前致谢。

5 个答案:

答案 0 :(得分:7)

这是一个小理论有用的地方之一。你需要考虑几件事:

  • 您的测量分辨率是多少:0.1°或0.001°? 1秒或1微秒?
  • 是与测量相关联的测量结果,还是随机扔在一起?

假设,例如,分辨率为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中)压缩)。

通常情况下,您所谈论的数据只会存储为二进制数字(而不是文本),而且通常是空间和检索效率。

我建议您查看The Data Compression Book

答案 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