简体   繁体   English

序列化双精度的最佳方法

[英]Best way to serialize a double

I am serializing values to an XML document.我正在将值序列化为 XML 文档。 When I serialize a double , I want to make sure I am not losing any precision, and that culture will not interfere.当我序列化一个double ,我想确保我不会失去任何精度,并且这种文化不会干扰。 Or any other "gotchas" that I haven't thought of.或者我没有想到的任何其他“陷阱”。

Similarly for DateTime , I use ToBinary() to get a value that's very safe to serialize.同样对于DateTime ,我使用ToBinary()来获取一个非常安全的序列化值。

So, what is the best method to serialize / deserialize a double value in C#?那么,在 C# 中序列化/反序列化double值的最佳方法是什么?

In order to parse back the exact value, you should use the G17 format specifier, as documented here :为了解析回确切的值,您应该使用G17格式说明符,如此处所述

d.ToString("G17")

or或者

$"{d:G17}"

Note that this can fail to roundtrip on versions below .NET Core 3.0 .请注意,这可能无法在低于 .NET Core 3.0 的版本上往返。


Original answer below ;下面的原始答案; the "r" format specifier mentioned actually has a bug so the documentation was incorrect .提到的"r"格式说明符实际上有一个错误,因此文档不正确


The round-trip format specifier "r" guarantees that if you use double.Parse on the string, you will get back the exact same value: 往返格式说明符 "r"保证如果您在字符串上使用double.Parse ,您将获得完全相同的值:

d.ToString("r")

Checkout XmlConvert.ToString(double value)结帐XmlConvert.ToString(双值)

This handles infinity too:这也处理无穷大:

If value is Double.PositiveInfinity or Double.NegativeInfinity, this method returns the string INF or -INF respectively.如果值为 Double.PositiveInfinity 或 Double.NegativeInfinity,则此方法分别返回字符串 INF 或 -INF。

BitConverter.GetBytes(myValue)将给出一个 Byte 数组,然后可以在不损失精度的情况下对其进行序列化。

It looks like this should work.看起来这应该有效。 According to my tests, it also round-trips special values like infinity and NaN just fine.根据我的测试,它还可以很好地往返于无穷大和 NaN 等特殊值。

static string SerializeDouble(double d)
{
    return d.ToString("G17", CultureInfo.InvariantCulture);
}

static double DeserializeDouble(string s)
{
    return double.Parse(s, CultureInfo.InvariantCulture);
}

Why "G17" ?为什么是"G17"

Source: https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-numeric-format-strings?redirectedfrom=MSDN#GFormatString来源: https : //docs.microsoft.com/en-us/dotnet/standard/base-types/standard-numeric-format-strings?redirectedfrom=MSDN#GFormatString

Relevant quote (at the time of this post):相关引述(在发帖时):

Note that, when used with a Double value, the "G17" format specifier ensures that the original Double value successfully round-trips.请注意,当与 Double 值一起使用时,“G17”格式说明符可确保原始 Double 值成功往返。 This is because Double is an IEEE 754-2008-compliant double-precision (binary64) floating point number that gives up to 17 significant digits of precision.这是因为 Double 是符合 IEEE 754-2008 的双精度 (binary64) 浮点数,可提供多达 17 位有效数字的精度。 We recommend its use instead of the "R" format specifier, since in some cases "R" fails to successfully round-trip double-precision floating point values.我们建议使用它而不是“R”格式说明符,因为在某些情况下,“R”无法成功地往返双精度浮点值。


Why CultureInfo.InvariantCulture ?为什么是CultureInfo.InvariantCulture

This takes care of any culture-specific formatting that would otherwise break your round-trip.这会处理任何特定于文化的格式,否则会破坏您的往返行程。 For example, this code snippet gives some very undesirable results!例如,这个代码片段给出了一些非常不受欢迎的结果!

double d0 = Math.PI;
Console.WriteLine("d0: " + d0); // prints 3.14159265358979
// Serialize in America
string s = d0.ToString("G17", new CultureInfo("en-us"));
Console.WriteLine("s: " + s); // prints 3.1415926535897931
// Deserialize in Germany
double d1 = double.Parse(s, new CultureInfo("de-de"));
Console.WriteLine("d1: " + d1); // prints 3.14159265358979E+16

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM