C# 可变精度浮点/双精度值
我有一个我正在序列化的对象,它包含了很多double和double的结构,我用protobuf-net通过网络发送。问题是,在整个过程中,我不需要所有的精度 例如,我有这样一个例子,外部库返回一个doubleC# 可变精度浮点/双精度值,c#,serialization,protobuf-net,C#,Serialization,Protobuf Net,我有一个我正在序列化的对象,它包含了很多double和double的结构,我用protobuf-net通过网络发送。问题是,在整个过程中,我不需要所有的精度 例如,我有这样一个例子,外部库返回一个double double Volts=Sampler.GetValue()//伏特值类似于4.35(…) 但我真的只需要两个小数点的精度。将其作为双精度编码需要64位。将其编码为具有2位十进制精度(“4.35”)的字符串实际上可能占用更少的空间。但我还有转换问题要处理 我一直在探索v2选项,但我还没有
double Volts=Sampler.GetValue()//伏特值类似于4.35(…)
但我真的只需要两个小数点的精度。将其作为双精度编码需要64位。将其编码为具有2位十进制精度(“4.35”)的字符串实际上可能占用更少的空间。但我还有转换问题要处理
我一直在探索v2选项,但我还没有看到这样的功能。我可以看出,如果可以将浮点值编码为可变长度的精度,它将节省大量空间
我曾考虑过将其乘以一个整数,然后将其发送到远端,然后将其转换回远端,但据我所知,这需要我对基类对象进行重大更改(我在反序列化过程中使用了merge选项)
有什么想法或聪明的解决办法吗
顺便说一句,protobuf网络的可配置性非常好。感谢您制作了这么好的程序。将数据序列化为字符串听起来不是个好主意 双精度值已经只有64位了(参见,wire type 1),文本以UTF-8的形式传输,因此即使在简化的4.35示例中,也需要32位进行传输,更不用说在反序列化时将其转换回双精度值,以及在有人查看该代码时的一般维护噩梦
如果您不需要精度,我建议使用浮点,它只使用32位,但在使用这些值及其序列化时保持一致。将数据序列化为字符串听起来是个坏主意 双精度值已经只有64位了(参见,wire type 1),文本以UTF-8的形式传输,因此即使在简化的4.35示例中,也需要32位进行传输,更不用说在反序列化时将其转换回双精度值,以及在有人查看该代码时的一般维护噩梦 如果您不需要精度,我建议使用浮点,它只使用32位,但在使用这些值及其序列化时保持一致。继续“可能将它们作为
浮点发送”
讨论,实际上,您可以很容易地做到这一点;例如,如果您当前有:
[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个字节作为一个“变量”。进行“可能将它们作为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个字节。”-不,它需要64位=8字节。如果你真的关心空间的话,这里有一个“半浮点数”(在这种情况下是指带宽)。谢谢,修复了位/字节的错误。“将其作为双精度编码需要64个字节。”-不,需要64位=8字节。如果你真的关心空间,那么就有“半浮点数”(在这种情况下是带宽)。谢谢,修复了位/字节输入错误。是的,我在考虑ASCII文本。Unicode显然会更糟。我可以使用浮点数并将数据大小减半。我可以到处强制转换,因为所有内容都返回双倍(包括第三方对象)。更改它并在任何地方强制转换可能会涉及到上千行代码。是的,我真的搞砸了位/字节。盯着屏幕看太久了。但我的一般问题仍然存在。浮动可能不值得我更改多少行代码。是的,我想ASCII文本。Unicode显然会更糟。我可以使用浮动并将数据大小减半。我可以在任何地方进行强制转换,因为所有内容都返回双倍(包括第三方对象)。更改它并在任何地方强制转换可能会涉及到上千行代码。是的,我确实搞砸了位/字节。盯着屏幕看的时间太长了。但我的一般问题仍然存在。浮动可能不值得我花费精力更改多少行代码。我实际上只是在挖掘protobuf网络代码以查看about用属性修饰一个double基本上是第二个想法,我可以用
FixedPrecision=2
来修饰一个double,并在序列化/反序列化中处理它。如果失败,我可能会编辑这个命令