有一些特殊格式(base-128)用于传输protobufs和elsewhere中使用的整数。当大多数整数很小时,它们是有利的(对于最小的数字,它们需要一个字节,而对于其他数字则可能浪费一个字节)。
我想知道在大多数实际上是小整数的情况下浮点数是否类似?
要解决爱丽丝的回答:我在考虑像
这样的事情void putCompressedDouble(double x) {
int n = (int) x;
boolean fits = (n == x);
putBoolean(fits);
if (fits) {
putCompressedInt(n);
} else {
putUncompressedLong(Double.doubleToLongBits(x));
}
}
这是有效的(除了负零,我真的不在乎),但在fits == true
的情况下它是浪费的。
答案 0 :(得分:1)
这取决于您的号码分布。幅度并不重要,因为它通过浮点数的指数字段表示。它通常是尾数,在储存方面贡献最大的“重量”。
如果你的浮点数主要是整数,你可以通过转换为int(通过Float.floatToIntBits())获得一些东西,并检查有多少尾随零(对于小的int值,应该有最多23个尾随零)。当使用简单的方案来编码小型int时,您可以简单地将编码浮点数实现为:
int raw = Float.floatToIntBits(f);
raw = Integer.reverse(raw);
encodeAsInt(raw);
(解码只是扭转过程)。 这样做只是将尾数中的尾随零移动到int表示的最高有效位,这对于为小整数设计的编码方案是友好的。
同样可以应用于double< - > long。
答案 1 :(得分:0)
可能不是,这几乎肯定不是你想要的东西。
如前所述at this stack overflow post,浮点数不以独立于平台的方式存储在协议缓冲区中;它们本质上是一点点表示,然后使用union进行转换。这意味着float将占用4个字节并加倍8个字节。 这几乎可以肯定是你想要的。
为什么呢?浮动点不是整数。整数是一个组织良好的群体;每个数字都有效,每个位模式代表一个数字,它们完全代表它们的整数。浮点不能完全代表许多重要数字:例如,大多数浮点数不能精确地表示0.1。无穷大,NAN等等的问题都使得压缩格式成为一项非常重要的任务。
如果浮点数中有小整数,则将它们转换为小整数或某些定点精度格式。例如,如果你知道你只有.... 4 sigfigs,你可以从浮点转换为固定点短,节省2个字节。只要确保每个人都知道如何处理这种类型,你就会变得金色。
但谷歌在这种情况下尝试和节省空间的任何操作都将重新发明轮子并且可能带来危险。这可能就是为什么他们试着不要弄乱浮子。
答案 2 :(得分:0)
我真的很喜欢Durandal的解决方案。尽管它很简单,但它表现得相当不错,至少对于float
来说。对于指数长于一个字节的double
s,一些额外的位重排可能会有所帮助。下表给出了最多D
个数字的数字的编码长度,也考虑了负数。在每列中,第一个数字给出所需的最大字节数,而带括号的数字是平均值。
D AS_INT REV_FLOAT REV_DOUBLE BEST
1: 1 (1.0) 2 (1.8) 3 (2.2) 1 (1.0)
2: 2 (1.4) 3 (2.4) 3 (2.8) 2 (1.7)
3: 2 (1.9) 3 (2.9) 4 (3.2) 2 (2.0)
4: 3 (2.2) 4 (3.3) 4 (3.8) 3 (2.6)
5: 3 (2.9) 4 (3.9) 5 (4.1) 3 (3.0)
6: 3 (3.0) 5 (4.2) 5 (4.8) 4 (3.5)
7: 4 (3.9) 5 (4.8) 6 (5.1) 4 (3.9)
8: 4 (4.0) 5 (4.9) 6 (5.8) 5 (4.3)
9: 5 (4.9) 5 (4.9) 6 (6.0) 5 (4.9)
测试了四种不同的方法:
int
即可。这是不可用的但是给了我们一个下限。float
s。double
s。