C# 在C中,将浮点数转换为十进制将失去精度#

C# 在C中,将浮点数转换为十进制将失去精度#,c#,.net,casting,floating-point,decimal,C#,.net,Casting,Floating Point,Decimal,在C#4.0中,以下类型转换的行为非常意外: (decimal)1056964.63f 1056965 铸造双倍效果很好: (double)1056964.63f 1056964.625 (decimal)(double)1056964.63f 1056964.625 这是设计的吗?问题在于初始值-浮点值仅精确到7位有效十进制数字: float f = 1056964.63f; Console.WriteLine(f); // Prints 1056965 因此,第二个例子在某些方面是出

在C#4.0中,以下类型转换的行为非常意外:

(decimal)1056964.63f
1056965
铸造双倍效果很好:

(double)1056964.63f
1056964.625

(decimal)(double)1056964.63f
1056964.625

这是设计的吗?

问题在于初始值-
浮点值
仅精确到7位有效十进制数字:

float f = 1056964.63f;
Console.WriteLine(f); // Prints 1056965
因此,第二个例子在某些方面是出乎意料的

现在
f
中的精确值是1056965.625,但这是从1056964.563到1056964.687的所有值的给定值-因此即使是“.6”部分也不总是正确的。这就是为什么
系统的文档。单个
状态:

默认情况下,单个值仅包含7位精度的十进制数字,但内部最多保留9位


当您转换为
double
时,额外的信息仍然会被保留,因为这样可以在根本不“解释”它的情况下保留它-将它转换为十进制形式(打印或用于
十进制类型)需要经过知道它不能“信任”最后两位数字的代码。

这是出于设计。Float可以将数字[edit]保持得相当准确[/edit],但为了转换为最接近的整数,它会将数字舍入为最接近的整数,因为数字和整数(1056964.75和1056964.88)之间只有很少几个可表示的Float值。请参阅SSCLI中的COMNumber::FormatSingle和COMDecimal::InitSingle。

不正确。在本例中,float实际上可以保存值
1056964.63
,是格式将其舍入到1056965。引用SSCLI中COMNumber::FormatSingle的一句话:“为了给出既便于显示又可对trippable进行四舍五入的数字,我们使用7位数字解析数字,然后确定它是否循环到相同的值。如果是,我们将该数字转换为字符串,否则我们使用9位数字重新解析并显示。”@麦格纳特鲁:它实际上不能容纳xxx.63。它可以容纳xxx.625,但该值也是最接近xxx.68的值,因此它甚至对“.6”部分也不准确。阅读我编辑的答案,看看你是否更同意。我认为.NET的
float
是IEEE-754的精确实现,在IEEE-754中,浮点数的精确值由其指数和分数决定,精确值用于每次计算(
float
操作根据协处理器指令进行JIT)。当CLI使用自定义方法并删除最后一个重要和精确的数字时,它仅转换为
字符串
COMNumber
。@MagnatLU:是-请参阅我的最后一段。当需要将位解释为有效位时,这包括到
十进制的转换。根据严格的浮点规则,您可以信任这些数字,但在某些操作中,实现选择不信任这些数字。这对于非sci计算是有意义的。无论如何,我猜你的答案比我的更精确。不,它不能精确地保存值-否则到
double
的转换将打印出1056964.63而不是1056964.625。你是对的。但我的观点是,Yurik的结果是由于转换期间的非IEEE处理,而不是由于表示中的实际精度损失。另外,值得注意的是SQL Server浮点与.NET浮点不同。它们不一样。