【问题标题】:Variable precision float/double values可变精度浮点/双精度值
【发布时间】:2012-02-02 04:01:12
【问题描述】:

我有一个我正在序列化的对象,其中包含我使用 protobuf-net 通过网络发送的许多双精度和双精度结构。问题是,我不需要所有的精确度。

例如,我有这样的事情,其中​​外部库返回双精度。

double Volts = Sampler.GetValue(); //Volts is a value like 4.35(...)

但我真的只需要两个小数点的精度。将其通过网络编码为双精度需要 64 位。将其编码为具有 2 位小数精度的字符串(“4.35”)实际上可能会占用更少的空间。但是我有转换问题要处理。

我一直在探索 v2 选项,但我还没有看到这样的功能。如果您可以将浮点值编码为可变长度的精度,我可以看到它如何节省大量空间。

我曾考虑将其乘以一个整数发送,然后在远端将其转换回,但据我所知,这需要我对我的基类对象进行重大更改(而且我在反序列化期间使用合并选项)。

有什么想法或聪明的解决方法吗?

顺便说一句,protobuf-net 非常棒,具有大量的可配置性。感谢您制作了如此出色的程序。

【问题讨论】:

  • “通过网络将其编码为双精度需要 64 个字节。” - 不,它需要 64 个 = 8 个字节
  • 如果你真的很在意空间,可以使用“半浮动”(err..bandwidth 在这种情况下)。
  • 谢谢,修正了位/字节错字。

标签: c# serialization protobuf-net


【解决方案1】:

进行“也许将他们发送为float”的讨论,实际上你可以很容易地做到这一点;例如,如果您目前有:

[ProtoMember(4)]
public double Value {get;set;}

您可以将其更改为:

public double Value {get;set;} // this won't be serialized directly

[Protomember(4)] // but we'll use this private property for the serialization
private float ValueSingle {
    get { return (float)Value; }
    set { Value = value; }
}

它会在后台为你做垫片。这个特别的改变也应该与现有数据兼容(虽然从技术上讲它确实改变了 .proto 架构,但 protobuf-net 是相当宽容的)。这将占用 4 个字节。另请注意,IEEE754 一如既往地适用,因此与 protobuf-net 完全无关无法保证任何特定值(例如 4.35)可以准确地存储

如果您想要固定精度,另一种选择是使用倍数。例如:

public double Value {get;set;}

[ProtoMember(4)]
public int ValueInt32 {
    get { return (int)Math.Round(100 * Value); }
    set { Value = value/100.0; }
}

您必须进行测试以查看它是否与旧数据兼容……这是一个更大的变化。在这里,4.35 将作为 435 发送,它需要 2 个字节作为“varint”。

【讨论】:

  • 我实际上只是在挖掘 protobuf-net 代码,以了解如何使用属性装饰双精度,这实际上是第二个想法,我可以使用 FixedPrecision=2 装饰双精度并处理它序列化/反序列化。如果失败了,我可能会像这样编辑带宽占用。我不想这样做,但如果我达到了我非常接近的带宽限制,我将不得不想出一些办法。我不关心旧数据;我可以根据需要打破东西。我认为这可能是 protobuf-net 中的一个不错的功能。
  • @Mike 重新属性;问题在于,您在 v2 中所做的任何更改都需要实现两次 - 一次在常规代码中,一次在 ILGenerator...
  • 是的,这可能是一个学习过程 :) 和/或史诗般的失败 :)
  • @MarcGravell - 我发现自己处于类似情况。我们可以谦虚地在ProtoMemberAttribute 中建议一个额外的Type 参数吗?例如。 [ProtoMember(1, SerializedType = typeof(float)]?
【解决方案2】:

将数据序列化为字符串听起来是个坏主意。

双值已经只有 64 位(请参阅Protocol Buffers encoding,电线类型 1),文本以 UTF-8 传输,因此即使在 4.35 的简化示例中,您也需要 32 位来传输,更不用说反序列化时将其转换回双倍,而当有人查看该代码时,一般维护噩梦。

如果您不需要精度,我建议您使用仅使用 32 位的浮点数,但在使用这些值及其序列化时保持一致。

【讨论】:

  • 是的,我在想 ASCII 文本。 Unicode 显然会更糟。我可以使用浮点数并将数据大小减半。我可以随处施放,因为一切都返回双打(包括第 3 方对象)。更改它并在任何地方强制转换可能会涉及超过一千行代码。
  • 是的,我确实搞砸了位/字节。盯着屏幕太久。我的一般问题仍然存在。浮动可能不值得我必须更改多少行。
猜你喜欢
  • 1970-01-01
  • 2018-07-06
  • 2018-02-23
  • 1970-01-01
  • 2010-09-27
  • 1970-01-01
  • 1970-01-01
  • 2023-03-18
  • 1970-01-01
相关资源
最近更新 更多