【问题标题】:compress floating point numbers with specified range and precision压缩具有指定范围和精度的浮点数
【发布时间】:2012-01-13 00:50:16
【问题描述】:

在我的应用程序中,我将使用浮点值来存储地理坐标(纬度和经度)。

我知道这些值的整数部分将分别在[-90, 90][-180, 180] 范围内。我还需要对这些值强制执行一些固定的精度(现在它是0.00001,但以后可以更改)。

在研究了单精度浮点类型 (float) 之后,我可以看到包含我的值有点小。这是因为180 * 10^5 大于2^24(float 有效数字的大小)但小于2^25

所以我必须使用双精度。但问题是我要存储大量的这些值,所以我不想浪费字节,存储不必要的精度。

那么,当我将双精度值(具有固定整数部分范围和指定精度 X)转换为 java 中的字节数组时,如何执行某种压缩?因此,例如,如果我使用示例中的精度 (0.00001),我最终会得到每个值 5 个字节。 我正在寻找一种轻量级的算法或解决方案,这样它就不会涉及大量的计算。

【问题讨论】:

  • 压缩数据后,您仍然可以使用压缩,例如GZIPOutputStream 可能会再次变小。
  • @PeterLawrey 对于大小合适的数组应该非常有用。我认为您的建议与 Aaron 的建议有一些共同点——它们都利用了存储值将彼此接近的事实。

标签: java compression floating-point


【解决方案1】:

要将数字x 存储为(例如)0.00001 的固定精度,只需存储最接近100000 * x 的整数即可。 (顺便说一句,这需要 26 位,而不是 25 位,因为您也需要存储负数。)

【讨论】:

  • 谢谢!但是在使用这种方法时存在一些问题。所以你建议存储int store = round(value / precision)。举个例子:value1 = 1.34, value2 = 1.36,精度是0.1。然后我们有|value1-value2| = 0.02 < precision,所以这些值被认为是相等的。但是我们将这些值存储为round(1.34/0.1)=round(13.4)=13round(1.36/0.1)=14。所以当我们恢复它们时,它们变成了 1.3 和 1.4,被认为是不相等的。这个例子并不准确,因为许多值不能在计算机中表示(著名的 0.1),它只是显示了可能的问题。我该如何解决?
  • @pavel,无论您使用哪种方法,都会有任意接近的数字被存储为不同的压缩数字。否则所有数字都必须存储相同!想一想……
  • 明白了,有一段时间失去了“精确”的含义。实际上,接近的值可以存储为不同的值,但它们的差异永远不会大于原始值的差异超过“精度”阈值。谢谢。
【解决方案2】:

正如TonyKhis answer 中所说,使用int 来存储数字。

要进一步压缩数字,请使用位置:地理坐标通常是“聚集”的(比如城市街区的轮廓)。使用固定参考点(全 2x26 位分辨率),然后将最后一个坐标的偏移存储为 bytes(给你 +/-0.00127)。或者,使用short,它可以为您提供超过一半的值范围。

请务必将压缩/解压缩隐藏在仅提供double 作为外部 API 的类中,以便您可以随时调整精度和压缩算法。

【讨论】:

  • 一个非常有价值的通知,亚伦!谢谢!我必须花一些时间来考虑在不违反 OOP 原则的情况下实施这个想法。
  • 创建最简单的实现以满足您的需求并在以后进行优化(当您知道什么是慢时)。只需确保 API 简单且不暴露任何内部结构即可。我建议一个简单的类似列表的方法:size() 返回坐标数,然后get(int index) 得到一个点。将一些值保留在内部缓存中,因为大多数访问都是顺序的。
【解决方案3】:

考虑到您的用例,我仍然会使用 double 并直接压缩它们。

原因是强大的压缩器,例如 7zip,非常擅长处理“结构化”数据,即双精度数组(一个数据 = 8 字节,这是非常规律且可预测的)。

您可能“手动”提出的任何其他优化都可能效果不佳或提供微不足道的优势,同时会花费您的时间和风险。

请注意,您仍然可以在压缩之前应用将 double 转换为 int 的“技巧”,但我真的不确定它是否会给您带来切实的好处,而另一方面它会严重降低您应对的能力未来的数字范围不可预见。

[编辑] 根据源数据,如果“低于精度级别”的位是“嘈杂的”,则压缩比可以通过舍入值或甚至直接在最低位上应用掩码(我想这最后一种方法不会取悦纯粹主义者,但至少您可以通过这种方式直接选择您的精度级别,同时保持所有可能值的可用范围)。

所以,总而言之,我建议在你的 double 数组上使用 direct LZMA compression

【讨论】:

  • 你完全倒退了。如果数字在低位有任何噪音,那么这些位(无论如何都不需要)将是不可压缩的。
  • 这一切都取决于来源。正如 pavel 所说:“对这些值强制执行一些固定的精度(现在它是 0.00001,但以后可以更改)”。所以要么源数据带有这个精度,要么可以强制选择精度,使用一个简单的 double->double 函数。更重要的是,以后可以更改精度,而无需修改方法。
  • 直接压缩双精度和压缩整数表示(定点算法)之间的性能差异可能很小,无论是速度方面还是压缩方面。真正的问题在于复杂性。通过创建中间格式,还有一个值得担心的理由,不仅是今天,还有明天的代码维护。所以它必须提供一些真正有价值的好处。
  • @TonyK 您认为他的建议中的哪些具体细节是个坏主意?虽然我发现您关于低位的通知非常有用,但他提供了解决方案。
  • 也许测试会告诉更多,更有意义。这不是第一次有人尝试手动调整输入数据以进一步压缩它,只是对低于预期的结果感到失望(例如,查看 Con Kolivas 的此条目:ck-hack.blogspot.com/2010/10/on-lrzip-and-packing-bytes.html)。恰好比 7z 非常擅长结构化数据。不能从其他算法(例如 zip 或 ppm)中得出同样的结论。一个主要的例外是当源数据使用增量模型发生巨大变化时,但这是一个完全不同的故事。
猜你喜欢
  • 2012-03-14
  • 2011-08-06
  • 2023-04-01
  • 2015-05-17
  • 2016-05-13
  • 1970-01-01
  • 2015-06-09
  • 2012-04-01
相关资源
最近更新 更多