C#加倍到十进制精度损失

Gre*_*oud 29 c# precision double decimal

我有一个双"138630.78380386264",我想将它转换为十进制,但是当我这样做时,我通过铸造或使用Convert.ToDecimal(),我失去精度.

这是怎么回事?decimal和double都可以保存这个数字:

在此输入图像描述

double doub = double.Parse("138630.78380386264");
decimal dec = decimal.Parse("138630.78380386264");
string decs = dec.ToString("F17");
string doubse =DoubleConverter.ToExactString(doub);
string doubs = doub.ToString("F17");

decimal decC = (decimal) doub;
string doudeccs = decC.ToString("F17");
decimal decConv = Convert.ToDecimal(doub);
string doudecs = decConv.ToString("F17");
Run Code Online (Sandbox Code Playgroud)

另外:如何使用ToString()on double打印出与调试器显示的相同的结果?例如138630.78380386264

Dav*_*nan 23

138630.78380386264双精度并不完全可以表示.最接近的双精度数(如此处所示)138630.783803862635977566242218017578125,与您的发现一致.

你问为什么转换为十进制不包含更多精度.在对文档Convert.ToDecimal()拥有了答案:

此方法返回的Decimal值最多包含15位有效数字.如果value参数包含超过15个有效数字,则使用舍入舍入为最接近的数字.下面的示例说明了Convert.ToDecimal(Double)方法如何使用舍入到最近以返回具有15位有效数字的Decimal值.

双值,四舍五入到最接近的15位有效数字138630.783803863,正如您在上面所示.


Jep*_*sen 5

我想这是一个不幸的事.接近139,000,Decimal精度远远高于a Double.但是,由于这个问题,我们将不同的 Double s投射到同一个问题上 Decimal.例如

double doub1 = 138630.7838038626;
double doub2 = 138630.7838038628;
Console.WriteLine(doub1 < doub2);                    // true, values differ as doubles
Console.WriteLine((decimal)doub1 < (decimal)doub2);  // false, values projected onto same decimal
Run Code Online (Sandbox Code Playgroud)

事实上,有6个不同的可表示Double之间 doub1doub2之上,因此他们是不一样的.

这是一个有点愚蠢的工作 - aronud:

static decimal PreciseConvert(double doub)
{
  // Handle infinities and NaN-s first (throw exception)
  // Otherwise:
  return Decimal.Parse(doub.ToString("R"), NumberStyles.AllowExponent | NumberStyles.AllowDecimalPoint);
}
Run Code Online (Sandbox Code Playgroud)

"R"格式串可以确保包含足够的额外的数字,使映射射(在该域Decimal具有优异的精度).


请注意,在某些范围内,a long(Int64)的精度优于Double.().所以我检查了这里的转换是否以相同的方式进行(首先舍入到15个有效小数位).他们不是!所以:

double doub3 = 1.386307838038626e18;
double doub4 = 1.386307838038628e18;

Console.WriteLine(doub3 < doub4);              // true, values differ as doubles
Console.WriteLine((long)doub3 < (long)doub4);  // true, full precision of double used when converting to long
Run Code Online (Sandbox Code Playgroud)

当目标是使用不同的"规则"时似乎不一致decimal.

请注意,因此,(decimal)(long)doub3产生比仅更准确的结果(decimal)doub3.