C# 为什么要将.ToDecimal(双精度)四舍五入转换为15位有效数字?

C# 为什么要将.ToDecimal(双精度)四舍五入转换为15位有效数字?,c#,double,decimal,C#,Double,Decimal,我有一个双精度,小数点后有17位数字,即: double myDouble = 0.12345678901234567; 如果我将其转换为如下的十进制: decimal myDecimal = Convert.ToDecimal(myDouble); 然后根据Convert.ToDecimal文档,将myDecimal的值四舍五入为15位(即0.0123456789012345)。我的问题是,为什么要进行舍入 我知道,如果我的原始数字能够准确地以10为基数表示,并且我试图将其存储为双精度,那

我有一个
双精度
,小数点后有17位数字,即:

double myDouble = 0.12345678901234567;
如果我将其转换为如下的
十进制

decimal myDecimal = Convert.ToDecimal(myDouble);
然后根据
Convert.ToDecimal
文档,将
myDecimal
的值四舍五入为15位(即
0.0123456789012345
)。我的问题是,为什么要进行舍入

我知道,如果我的原始数字能够准确地以10为基数表示,并且我试图将其存储为
双精度
,那么我们只能对前15位有信心。最后两位数字可能存在舍入误差。但是,这是一个基于10的偏颇观点。我的数字可能更准确地表示为
双精度
,我希望将其转换为
十进制
,同时尽可能保持准确性


不应
转换。ToDecimal
旨在最大限度地减少
myDouble
(double)转换之间的差异。ToDecimal(myDouble)

以下内容摘自相关方法的文档

此方法返回的十进制值最多包含15位有效数字。如果value参数包含的有效数字超过15位,则使用四舍五入到最近值进行四舍五入。

来自:

双精度值最多有15位小数位数,但 内部最多保留17位数字


因此,由于双精度值本身最多有15位小数,将其转换为十进制将产生一个具有15位有效数字的十进制值。

每个终止二进制分数都可以精确表示为十进制分数,因此有限数的最小可能差始终为0。的IEEE 754 64位表示法您的号码正好等于0.1234567890121345663492098442853592149913311004638671875

从二进制浮点到十进制或十进制字符串的每一次转换都必须包含一些关于舍入的决定。理论上,它们可以保留所有数字,但这将导致一些非常长的输出,而大多数数字几乎没有意义

Java的Double.toString中使用的一个选项是在转换回原始Double的最短十进制表示处停止


大多数设置了一些相当任意的限制。15个有效数字保留了最有意义的数字。

舍入的行为保证了将最多有15个有效数字的任何
十进制
转换为
双位
,再转换回
十进制
,将产生原始值不变。如果值为rou如果是16位数字而不是15位数字,这样的保证不仅不能适用于16位数字,甚至不能适用于更短的值。例如,最接近9000.04的
Double
值约为9000.04000000000873115;四舍五入到16位数字将产生9000.04000000001


应该使用的四舍五入选择取决于是否将
双精度
值9000.04的最佳
十进制
值视为9000.04m、9000.04000000001m、9000.040000000008731m或其他值。微软可能认为9000.04m以外的任何表示形式都会令人困惑。

这是一个重复t取整是因为它被指定为取整。并没有真正回答为什么。我认为OP对这背后的原因感兴趣。团队,除非你和语言的设计者谈过,否则这是不可回答的。这是唯一可以接受的答案。它之所以如此,是因为它确实如此。@MichaelPerrenoud:团队可能决定使用im如果他们的行为是因为占星家告诉他们的,我怀疑他们的决定可能更多地是因为像9999.04这样的a
double
的值更接近9000.04000000001m,而不是9000.04m。如果一个人想要
double
的值,它应该代表十个分数的幂,以f的形式出现它们应该代表的分数,四舍五入到15位将实现这一点;四舍五入到16位则不会。MichaelPerrenoud:可以添加这样的逻辑,即对于每一个具有15位或更少有效数字的小数点,最接近的
双精度
值应四舍五入到15位,而其他双精度值则应四舍五入不同的是,这将在转换中引入非线性,这可能比舍入更有害。也许为了与
double.ToString
+
decimal.Parse一致,请查看是否有兴趣创建“舍入三表”“十进制值。您正在进行的测量与万亿分之一的精度有关吗?”?你在这里运行大型强子对撞机吗?这是一个如此之小的数量,以至于不需要强调。在这个双精度中表示的任何度量值上的误差条都可能比舍入误差大数百万倍。@EricLippert我从C接口后面的SDK中得到了一个最大值和最小值(因此
double
)。我的系统在内部将其存储为
decimal
s。当我尝试在SDK中设置这些值时,它们需要在max-min范围内。我没有强调准确性,但这并不能阻止SDK返回超出范围。
double
的不同值在以十进制形式呈现时具有不同的有效位数,这取决于它们是刚刚超过或刚刚低于10的幂,还是刚刚超过或刚刚低于2的幂。例如,1000-1023.9范围内的值用1.137E-12分隔,而8192-9999.9范围内的值用1.819E-11分隔;因此,在这些范围内的值的相对精度存在着超过一个十进制数字的差异,即使它们(以十进制表示)具有相同的数量级