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

时间:2011-09-17 09:50:36

标签: c# double decimal precision

我有一个双"138630.78380386264",我想将其转换为十进制,但是当我这样做时,我通过强制转换或使用Convert.ToDecimal()来实现它,我会失去精确度。

发生了什么事? decimal和double都可以保存这个数字:

enter image description here

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");

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

3 个答案:

答案 0 :(得分:23)

138630.78380386264不能完全表示双精度。最接近的双精度数(找到here)是138630.783803862635977566242218017578125,这与您的发现一致。

你问为什么转换为十进制不包含更多精度。 documentation for Convert.ToDecimal()有答案:

  

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

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

答案 1 :(得分:5)

我认为这是一个不幸的事。接近139,000,Decimal的精确度远远高于Double。但是,由于这个问题,我们将不同的 Double投射到相同的 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

实际上 Doubledoub1之间存在六个不同的可表示doub2,所以它们不一样

这是一个有点愚蠢的工作 - 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);
}

"R"格式字符串确保包含足够的额外数字以使映射成为内射(在Decimal具有更高精度的域中)。


请注意,在某些范围内,longInt64)的精度优于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

当目标为decimal时,使用不同的“规则”似乎不一致。

请注意,正因为如此,(decimal)(long)doub3产生的结果比(decimal)doub3更准确。

答案 2 :(得分:1)

这里的答案为您提供了问题的为什么的见解,但是(即使您问了很多年也是如此),这是一种将double转换为decimal,不舍入到15位数字。不过,它需要一点儿摆弄。

除了强制类型转换(如果值不合适或为OverflowExceptionNaNINF会抛出-INF之外,此方法会产生{{1}如果无法进行转换,请在false参数中输入}。由于success不支持负零,但decimal支持负零,因此我忽略了它,只是返回零。

以下代码并非完全属于我,但是对不起,我找不到原始帖子。可能是从Jon Skeet's code of ToExactString提取的,并用于二进制精确转换。

double