C#加倍到十进制精度损失
我有一个双"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");
另外:如何在Double上获取ToString()
以打印出与调试器显示的相同的结果? 例如138630.78380386264
?
138630.78380386264
不能精确表示双精度。 最接近的双精度数(如此处所示 )是138630.783803862635977566242218017578125
,这与您的发现一致。
你问为什么转换为十进制不包含更多精度。 Convert.ToDecimal()
的文档有答案:
此方法返回的Decimal值最多包含15位有效数字。 如果value参数包含超过15个有效数字,则使用舍入到最近的值进行舍入。 下面的示例说明了Convert.ToDecimal(Double)方法如何使用舍入到最近以返回带有15位有效数字的Decimal值。
双倍值,四舍五入到最接近的15位有效数字是138630.783803863
,正如您在上面所示。
我想这是一个不幸的事。 接近139,000, Decimal
精度远远高于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
事实上, 在 doub1
和doub2
之间有六个不同的可表示的Double
值,所以它们不一样。
这是一个有点愚蠢的工作 - 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
具有高精度的域中)。
请注意,在某些范围内, 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
当目标是decimal
时,使用不同的“规则”似乎不一致。
注意,因此, (decimal)(long)doub3
产生比(decimal)doub3
更准确的结果。