可变精度浮点值/双精度值



我有一个正在序列化的对象,它包含大量的替身和替身结构,我正在通过protobuf-net发送这些替身和结构。问题是,隔着电线,我不需要那么精确。

例如,我有这样的东西,一个外部库正在返回一个double。

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

但我真的只需要两个小数点的精度。通过导线将其编码为双精度需要64位。将其编码为具有2位小数精度的字符串("4.35")实际上可能占用较少的空间。但我在双方都有转换问题需要处理。

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

我曾想过将其乘以一个整数,然后在远端将其转换回,但据我所知,这需要我对基类对象进行重大更改(我在反序列化过程中使用了merge选项)。

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

顺便说一句,protobuf网络具有强大的可配置性。谢谢你制作了这么棒的节目。

进行"也许将它们作为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个字节作为"变量"。

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

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

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

最新更新