首页 > 解决方案 > .Net 中的往返格式说明符“R”失败

问题描述

文档建议我使用而G17不是R,因为R有时无法往返。

但是,(1.0/10).ToString("G17")"0.10000000000000001",这是非常可怕的。而往返格式似乎工作得很好(并且给出了"0.1")。我很乐意花几个 cpu 周期来获得更美观的结果。但潜在的往返失败更令人担忧。

对于哪种(双)值确实R无法往返?有多糟糕?.Net 版本(我们在 Net Framework 4.72 和 NetCore 3.1 上运行)会影响事情吗?在一个平台上写作和在另一个平台上阅读是否会使往返失败更加频繁?

我们正在考虑R先写双打,解析检查往返,G17只有在失败时才回退。有没有更好的方法来获得格式良好、可靠的结果?

标签: c#.net.net-corefloating-pointformat-specifiers

解决方案


此处的往返行程是将数值转换为字符串,然后解析回相同的数值

OP 对(1.0/10).ToString("G17") 的失望给出了“0.10000000000000001”,这非常可怕。是对往返成功的错误评估。中间字符串只是往返的一半

Double精确编码大约 2 64 个不同的值。所有可编码值都是一些有限的整数* 2 some_power。0.1不是其中之一。1.0/10 使数学商为 0.1,但值略有不同Double。最接近的Double值和它的两个最近的Double邻居:

 Before     0.099999999999999991673... 
            0.100000000000000005551...
 After      0.100000000000000019428...
 OP report  0.10000000000000001
 Digit count  12345678901234567

OP的例子应该是 <(0.100000000000000005551).ToString("G17") 给出 "0.10000000000000001"> 这很好

打印一个DoublewithG17提供 17 位有效数字,足以成功往返。


对于哪种(双)值,R 无法往返?有多糟糕?

为此,我继续记忆。 R有时使用少于 17 个有效数字(如 15)来形成中间字符串。用于确定数字计数的算法有时会有点短,因此“某些情况下无法成功往返原始值”。

使用G17总是有效的。对于某些值,小于 17 也可以。不利的一面G17正是在这种情况下。少于 17 位数字就可以工作,并提供了一个更令人愉悦、更短的中间字符串。

令人愉悦的人类可读字符串不是往返的目标。目标是在Double从值到字符串到值之后形成相同的形式,即使中间字符串在某些情况下有额外的数字。


有没有更好的方法来获得格式良好、可靠的结果?

“格式很好”是往返的额外负担。MS 尝试这样做R但在某些情况下失败了,宁愿保留相同的损坏功能而不是修复它。

OP 会明智地避免该路径并放弃格式良好的中间字符串的目标,并专注于获取最终相同值的往返目标。

使用G17.


我们正在考虑先将双精度写到 R,解析以检查往返,只有在失败时才回退到 G17。

如果做得正确,那将起作用。要评估正确性,请使用许多值测试您的代码,并将其和测试工具发布以进行代码审查。


推荐阅读